From c8711f4ea5d941d12ae7e6cf99302bfc3211dd3c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 5 Sep 2023 22:22:56 +0300 Subject: Initial prototype of embedded LUA --- indra/newview/CMakeLists.txt | 6 + indra/newview/llfilepicker.cpp | 5 + indra/newview/llfilepicker.h | 3 +- indra/newview/llfloaterluadebug.cpp | 92 +++++++++++++ indra/newview/llfloaterluadebug.h | 62 +++++++++ indra/newview/llluamanager.cpp | 152 +++++++++++++++++++++ indra/newview/llluamanager.h | 38 ++++++ indra/newview/llviewerfloaterreg.cpp | 3 + .../skins/default/xui/en/floater_lua_debug.xml | 98 +++++++++++++ indra/newview/skins/default/xui/en/menu_viewer.xml | 11 ++ indra/newview/viewer_manifest.py | 3 + 11 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 indra/newview/llfloaterluadebug.cpp create mode 100644 indra/newview/llfloaterluadebug.h create mode 100644 indra/newview/llluamanager.cpp create mode 100644 indra/newview/llluamanager.h create mode 100644 indra/newview/skins/default/xui/en/floater_lua_debug.xml (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dbd1f1b4ac..ca0b7692c4 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -46,6 +46,7 @@ include(VisualLeakDetector) include(ZLIBNG) include(URIPARSER) include(LLPrimitive) +include(lualibs) if (NOT HAVOK_TPV) # When using HAVOK_TPV, the library is precompiled, so no need for this @@ -235,6 +236,7 @@ set(viewer_SOURCE_FILES llfloaterlandholdings.cpp llfloaterlinkreplace.cpp llfloaterloadprefpreset.cpp + llfloaterluadebug.cpp llfloatermarketplacelistings.cpp llfloatermap.cpp llfloatermediasettings.cpp @@ -361,6 +363,7 @@ set(viewer_SOURCE_FILES lllogchat.cpp llloginhandler.cpp lllogininstance.cpp + llluamanager.cpp llmachineid.cpp llmanip.cpp llmaniprotate.cpp @@ -879,6 +882,7 @@ set(viewer_HEADER_FILES llfloaterlandholdings.h llfloaterlinkreplace.h llfloaterloadprefpreset.h + llfloaterluadebug.h llfloatermap.h llfloatermarketplacelistings.h llfloatermediasettings.h @@ -1003,6 +1007,7 @@ set(viewer_HEADER_FILES lllogchat.h llloginhandler.h lllogininstance.h + llluamanager.h llmachineid.h llmanip.h llmaniprotate.h @@ -1698,6 +1703,7 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/openjp2.dll ${SHARED_LIB_STAGING_DIR}/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/uriparser.dll + ${SHARED_LIB_STAGING_DIR}/lua54.dll #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index f1f156c2e0..b9435dc9df 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -61,6 +61,7 @@ LLFilePicker LLFilePicker::sInstance; #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0" #define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0" +#define LUA_FILTER L"Script files (*.lua)\0*.lua\0" #endif #ifdef LL_DARWIN @@ -218,6 +219,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = DICTIONARY_FILTER \ L"\0"; break; + case FFLOAD_LUA: + mOFN.lpstrFilter = LUA_FILTER \ + L"\0"; + break; default: res = FALSE; break; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 692b908fff..cb453ea87e 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -85,7 +85,8 @@ public: FFLOAD_SCRIPT = 11, FFLOAD_DICTIONARY = 12, FFLOAD_DIRECTORY = 13, // To call from lldirpicker. - FFLOAD_EXE = 14 // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin + FFLOAD_EXE = 14, // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin + FFLOAD_LUA = 15 }; enum ESaveFilter diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp new file mode 100644 index 0000000000..c8b330f732 --- /dev/null +++ b/indra/newview/llfloaterluadebug.cpp @@ -0,0 +1,92 @@ +/** + * @file llfloaterluadebug.cpp + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterluadebug.h" + +#include "lllineeditor.h" +#include "lltexteditor.h" +#include "llviewermenufile.h" // LLFilePickerReplyThread + +#include "llagent.h" +#include "llappearancemgr.h" +#include "llfloaterreg.h" +#include "llfloaterimnearbychat.h" + +#include "llluamanager.h" + +#if LL_WINDOWS +#pragma comment(lib, "liblua54.a") +#endif + + +LLFloaterLUADebug::LLFloaterLUADebug(const LLSD &key) + : LLFloater(key) +{ +} + + +BOOL LLFloaterLUADebug::postBuild() +{ + mResultOutput = getChild<LLTextEditor>("result_text"); + mLineInput = getChild<LLLineEditor>("lua_cmd"); + mScriptPath = getChild<LLLineEditor>("script_path"); + + getChild<LLButton>("execute_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); + getChild<LLButton>("browse_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnBrowse, this)); + +#if !LL_WINDOWS + getChild<LLButton>("execute_btn")->setEnabled(false); + getChild<LLButton>("browse_btn")->setEnabled(false); +#endif + + return TRUE; +} + +LLFloaterLUADebug::~LLFloaterLUADebug() +{} + +void LLFloaterLUADebug::onExecuteClicked() +{ + std::string cmd = mLineInput->getText(); + LLLUAmanager::runScriptLine(cmd); +} + +void LLFloaterLUADebug::onBtnBrowse() +{ + (new LLFilePickerReplyThread(boost::bind(&LLFloaterLUADebug::runSelectedScript, this, _1), LLFilePicker::FFLOAD_LUA, false))->getFile(); +} + +void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames) +{ + std::string filepath = filenames[0]; + if (!filepath.empty()) + { + mScriptPath->setText(filepath); + LLLUAmanager::runScriptFile(filepath); + } +} + diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h new file mode 100644 index 0000000000..a7a3b695d4 --- /dev/null +++ b/indra/newview/llfloaterluadebug.h @@ -0,0 +1,62 @@ +/** + * @file llfloaterluadebug.h + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERLUADEBUG_H +#define LL_LLFLOATERLUADEBUG_H + +#include "llfloater.h" + +extern "C" +{ +#include "lua/lua.h" +#include "lua/lauxlib.h" +#include "lua/lualib.h" +} + +class LLLineEditor; +class LLTextEditor; + +class LLFloaterLUADebug : + public LLFloater +{ + public: + LLFloaterLUADebug(const LLSD& key); + virtual ~LLFloaterLUADebug(); + + /*virtual*/ BOOL postBuild(); + + void onExecuteClicked(); + void onBtnBrowse(); + + void runSelectedScript(const std::vector<std::string> &filenames); + +private: + LLTextEditor* mResultOutput; + LLLineEditor* mLineInput; + LLLineEditor* mScriptPath; +}; + +#endif // LL_LLFLOATERLUADEBUG_H + diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp new file mode 100644 index 0000000000..516993c967 --- /dev/null +++ b/indra/newview/llluamanager.cpp @@ -0,0 +1,152 @@ +/** + * @file llluamanager.cpp + * @brief classes and functions for interfacing with LUA. + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llluamanager.h" + +#include "llagent.h" +#include "llappearancemgr.h" +#include "llfloaterreg.h" +#include "llfloaterimnearbychat.h" + +extern "C" +{ +#include "lua/lua.h" +#include "lua/lauxlib.h" +#include "lua/lualib.h" +} + +#if LL_WINDOWS +#pragma comment(lib, "liblua54.a") +#endif + +int lua_printWarning(lua_State *L) +{ + std::string msg(lua_tostring(L, 1)); + + LL_WARNS() << msg << LL_ENDL; + return 1; +} + +int lua_avatar_sit(lua_State *L) +{ + gAgent.sitDown(); + return 1; +} + +int lua_avatar_stand(lua_State *L) +{ + gAgent.standUp(); + return 1; +} + +int lua_nearby_chat_send(lua_State *L) +{ + std::string msg(lua_tostring(L, 1)); + LLFloaterIMNearbyChat *nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + nearby_chat->sendChatFromViewer(msg, CHAT_TYPE_NORMAL, gSavedSettings.getBOOL("PlayChatAnim")); + + return 1; +} + +int lua_wear_by_name(lua_State *L) +{ + std::string folder_name(lua_tostring(L, 1)); + LLAppearanceMgr::instance().wearOutfitByName(folder_name); + + return 1; +} + +bool checkLua(lua_State *L, int r) +{ + if (r != LUA_OK) + { + std::string lua_error = lua_tostring(L, -1); + + LL_WARNS() << lua_error << LL_ENDL; + return false; + } + return true; +} + +void initLUA(lua_State *L) +{ + lua_register(L, "lua_printWarning", lua_printWarning); + + lua_register(L, "lua_avatar_sit", lua_avatar_sit); + lua_register(L, "lua_avatar_stand", lua_avatar_stand); + + lua_register(L, "lua_nearby_chat_send", lua_nearby_chat_send); + lua_register(L, "lua_wear_by_name", lua_wear_by_name); +} + +void LLLUAmanager::runScriptFile(const std::string &filename) +{ + LLCoros::instance().launch("LUAScriptFileCoro", [filename]() + { + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + initLUA(L); + + auto LUA_sleep_func = [](lua_State *L) + { + F32 seconds = lua_tonumber(L, -1); + llcoro::suspendUntilTimeout(seconds); + return 0; + }; + + lua_register(L, "sleep", LUA_sleep_func); + + if (checkLua(L, luaL_dofile(L, filename.c_str()))) + { + lua_getglobal(L, "call_once_func"); + if (lua_isfunction(L, -1)) + { + if (checkLua(L, lua_pcall(L, 0, 0, 0))) {} + } + } + + lua_close(L); + }); +} + +void LLLUAmanager::runScriptLine(const std::string &cmd) +{ + LLCoros::instance().launch("LUAScriptFileCoro", [cmd]() + { + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + initLUA(L); + int r = luaL_dostring(L, cmd.c_str()); + if (r != LUA_OK) + { + std::string lua_error = lua_tostring(L, -1); + LL_WARNS() << lua_error << LL_ENDL; + } + lua_close(L); + }); +} diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h new file mode 100644 index 0000000000..d31f159480 --- /dev/null +++ b/indra/newview/llluamanager.h @@ -0,0 +1,38 @@ +/** + * @file llluamanager.h + * @brief classes and functions for interfacing with LUA. + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLLUAMANAGER_H +#define LL_LLLUAMANAGER_H + +class LLLUAmanager +{ +public: + static void runScriptFile(const std::string &filename); + static void runScriptLine(const std::string &cmd); +}; + + +#endif diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 0f2fe1e1cd..d00ccd05a0 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -90,6 +90,7 @@ #include "llfloaterlandholdings.h" #include "llfloaterlinkreplace.h" #include "llfloaterloadprefpreset.h" +#include "llfloaterluadebug.h" #include "llfloatermap.h" #include "llfloatermarketplacelistings.h" #include "llfloatermediasettings.h" @@ -385,6 +386,8 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLinkReplace>); LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>); + + LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUADebug>); LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml new file mode 100644 index 0000000000..7ed6c35151 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_minimize="false" + can_resize="false" + can_close="true" + bevel_style="in" + height="220" + layout="topleft" + name="LUA debug" + save_rect="true" + title="LUA DEBUG" + single_instance="true" + width="530"> + <text + type="string" + length="1" + follows="left|bottom" + font="SansSerif" + height="30" + layout="topleft" + left="10" + left_delta="10" + name="editor_path_label" + top="10" + width="100"> + LUA string: + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + left="10" + max_length_bytes="300" + name="lua_cmd" + select_on_focus="true" + top_delta="30" + width="415" /> + <button + follows="left|bottom" + height="25" + label="Execute" + layout="topleft" + left_pad="5" + name="execute_btn" + top_delta="-2" + width="75" /> + + <text_editor + enabled="false" + left="10" + height="95" + layout="topleft" + name="result_text" + follows="left|top" + width="495" + top_delta="40" + word_wrap="true" /> + <text + type="string" + length="1" + follows="left|bottom" + font="SansSerif" + height="30" + layout="topleft" + left="10" + name="path_label" + top_pad="15" + width="100"> + File Path: + </text> + <line_editor + border_style="line" + enabled="false" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + left_delta="65" + max_length_bytes="300" + name="script_path" + select_on_focus="true" + top_delta="-2" + width="315" /> + <button + follows="left|bottom" + height="25" + label="Browse..." + label_selected="Browse..." + layout="topleft" + left_pad="5" + name="browse_btn" + top_delta="-2" + width="75" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 810d3fddd5..89643189b5 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2484,6 +2484,17 @@ function="World.EnvPreset" function="Develop.SetTexFetchDebugger" /> </menu_item_call> + <menu_item_separator/> + <menu_item_check + label="LUA Debug Console" + name="LUA Debug Console"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="lua_debug" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="lua_debug" /> + </menu_item_check> <menu_item_separator/> <menu_item_call diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 3a7c7d7f46..83d88ad21d 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -523,6 +523,9 @@ class WindowsManifest(ViewerManifest): # Uriparser self.path("uriparser.dll") + # lua libs + self.path("lua54.dll") + # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx self.path("msvcp140.dll") -- cgit v1.2.3 From b51cef8c8eaafa873f2a62d967cc4fe62cc0d94e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 6 Sep 2023 14:09:00 +0300 Subject: addcallback to display error msg --- indra/newview/llfloaterluadebug.cpp | 16 ++++++++-- indra/newview/llluamanager.cpp | 60 ++++++++++++++++++++++++++----------- indra/newview/llluamanager.h | 6 ++-- 3 files changed, 60 insertions(+), 22 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index c8b330f732..e7d220c503 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -71,8 +71,13 @@ LLFloaterLUADebug::~LLFloaterLUADebug() void LLFloaterLUADebug::onExecuteClicked() { + mResultOutput->setValue(""); + std::string cmd = mLineInput->getText(); - LLLUAmanager::runScriptLine(cmd); + LLLUAmanager::runScriptLine(cmd, [this](std::string msg) + { + mResultOutput->setText(msg); + }); } void LLFloaterLUADebug::onBtnBrowse() @@ -81,12 +86,17 @@ void LLFloaterLUADebug::onBtnBrowse() } void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames) -{ +{ + mResultOutput->setValue(""); + std::string filepath = filenames[0]; if (!filepath.empty()) { mScriptPath->setText(filepath); - LLLUAmanager::runScriptFile(filepath); + LLLUAmanager::runScriptFile(filepath, [this](std::string msg) + { + mResultOutput->setText(msg); + }); } } diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 516993c967..bb86731140 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -81,13 +81,27 @@ int lua_wear_by_name(lua_State *L) return 1; } -bool checkLua(lua_State *L, int r) +int lua_open_floater(lua_State *L) +{ + std::string floater_name(lua_tostring(L, 1)); + + LLSD key; + if (floater_name == "profile") + { + key["id"] = gAgentID; + } + LLFloaterReg::showInstance(floater_name, key); + + return 1; +} + +bool checkLua(lua_State *L, int r, std::string &error_msg) { if (r != LUA_OK) { - std::string lua_error = lua_tostring(L, -1); + error_msg = lua_tostring(L, -1); - LL_WARNS() << lua_error << LL_ENDL; + LL_WARNS() << error_msg << LL_ENDL; return false; } return true; @@ -95,18 +109,19 @@ bool checkLua(lua_State *L, int r) void initLUA(lua_State *L) { - lua_register(L, "lua_printWarning", lua_printWarning); + lua_register(L, "print_warning", lua_printWarning); - lua_register(L, "lua_avatar_sit", lua_avatar_sit); - lua_register(L, "lua_avatar_stand", lua_avatar_stand); + lua_register(L, "avatar_sit", lua_avatar_sit); + lua_register(L, "avatar_stand", lua_avatar_stand); - lua_register(L, "lua_nearby_chat_send", lua_nearby_chat_send); - lua_register(L, "lua_wear_by_name", lua_wear_by_name); + lua_register(L, "nearby_chat_send", lua_nearby_chat_send); + lua_register(L, "wear_by_name", lua_wear_by_name); + lua_register(L, "open_floater", lua_open_floater); } -void LLLUAmanager::runScriptFile(const std::string &filename) +void LLLUAmanager::runScriptFile(const std::string &filename, script_finished_fn cb) { - LLCoros::instance().launch("LUAScriptFileCoro", [filename]() + LLCoros::instance().launch("LUAScriptFileCoro", [filename, cb]() { lua_State *L = luaL_newstate(); luaL_openlibs(L); @@ -121,32 +136,43 @@ void LLLUAmanager::runScriptFile(const std::string &filename) lua_register(L, "sleep", LUA_sleep_func); - if (checkLua(L, luaL_dofile(L, filename.c_str()))) + std::string lua_error; + if (checkLua(L, luaL_dofile(L, filename.c_str()), lua_error)) { lua_getglobal(L, "call_once_func"); if (lua_isfunction(L, -1)) { - if (checkLua(L, lua_pcall(L, 0, 0, 0))) {} + if (checkLua(L, lua_pcall(L, 0, 0, 0), lua_error)) {} } } - lua_close(L); + + if (cb) + { + cb(lua_error); + } }); } -void LLLUAmanager::runScriptLine(const std::string &cmd) +void LLLUAmanager::runScriptLine(const std::string &cmd, script_finished_fn cb) { - LLCoros::instance().launch("LUAScriptFileCoro", [cmd]() + LLCoros::instance().launch("LUAScriptFileCoro", [cmd, cb]() { lua_State *L = luaL_newstate(); luaL_openlibs(L); initLUA(L); int r = luaL_dostring(L, cmd.c_str()); + + std::string lua_error; if (r != LUA_OK) { - std::string lua_error = lua_tostring(L, -1); - LL_WARNS() << lua_error << LL_ENDL; + lua_error = lua_tostring(L, -1); } lua_close(L); + + if (cb) + { + cb(lua_error); + } }); } diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index d31f159480..5bdf58bd3d 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -30,8 +30,10 @@ class LLLUAmanager { public: - static void runScriptFile(const std::string &filename); - static void runScriptLine(const std::string &cmd); + typedef std::function<void(std::string msg)> script_finished_fn; + + static void runScriptFile(const std::string &filename, script_finished_fn cb = script_finished_fn()); + static void runScriptLine(const std::string &cmd, script_finished_fn cb = script_finished_fn()); }; -- cgit v1.2.3 From 5b09d6372ff0900f67714af61bea100ee9a6d87b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 8 Sep 2023 17:00:42 +0300 Subject: allow to take snapshot; bind more funcs to call from lua --- indra/newview/llluamanager.cpp | 77 +++++++++++++++++++++++ indra/newview/llviewermenu.cpp | 125 ++++++++++++++++++++----------------- indra/newview/llviewermenu.h | 1 + indra/newview/llviewermenufile.cpp | 24 ++++--- indra/newview/llviewermenufile.h | 2 + 5 files changed, 162 insertions(+), 67 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index bb86731140..edfd5c3cad 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -30,8 +30,16 @@ #include "llagent.h" #include "llappearancemgr.h" +#include "llcallbacklist.h" #include "llfloaterreg.h" #include "llfloaterimnearbychat.h" +#include "llfloatersidepanelcontainer.h" +#include "llvoavatarself.h" +#include "llviewermenu.h" +#include "llviewermenufile.h" +#include "llviewerwindow.h" + +#include <boost/algorithm/string/replace.hpp> extern "C" { @@ -95,6 +103,66 @@ int lua_open_floater(lua_State *L) return 1; } +int lua_close_all_floaters(lua_State *L) +{ + close_all_windows(); + return 1; +} + +int lua_snapshot_to_file(lua_State *L) +{ + std::string filename(lua_tostring(L, 1)); + + //don't take snapshot from coroutine + doOnIdleOneTime([filename]() + { + gViewerWindow->saveSnapshot(filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + gSavedSettings.getBOOL("RenderUIInSnapshot"), + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + FALSE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + }); + + return 1; +} + +int lua_open_wearing_tab(lua_State *L) +{ + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "now_wearing")); + return 1; +} + +int lua_set_debug_setting_bool(lua_State *L) +{ + std::string setting_name(lua_tostring(L, 1)); + bool value(lua_toboolean(L, 2)); + + gSavedSettings.setBOOL(setting_name, value); + return 1; +} + + int lua_get_avatar_name(lua_State *L) +{ + std::string name = gAgentAvatarp->getFullname(); + lua_pushstring(L, name.c_str()); + return 1; +} + +int lua_is_avatar_flying(lua_State *L) +{ + lua_pushboolean(L, gAgent.getFlying()); + return 1; +} + +int lua_env_setting_event(lua_State *L) +{ + handle_env_setting_event(lua_tostring(L, 1)); + return 1; +} + bool checkLua(lua_State *L, int r, std::string &error_msg) { if (r != LUA_OK) @@ -117,6 +185,15 @@ void initLUA(lua_State *L) lua_register(L, "nearby_chat_send", lua_nearby_chat_send); lua_register(L, "wear_by_name", lua_wear_by_name); lua_register(L, "open_floater", lua_open_floater); + lua_register(L, "close_all_floaters", lua_close_all_floaters); + lua_register(L, "open_wearing_tab", lua_open_wearing_tab); + lua_register(L, "snapshot_to_file", lua_snapshot_to_file); + + lua_register(L, "get_avatar_name", lua_get_avatar_name); + lua_register(L, "is_avatar_flying", lua_is_avatar_flying); + + lua_register(L, "env_setting_event", lua_env_setting_event); + lua_register(L, "set_debug_setting_bool", lua_set_debug_setting_bool); } void LLLUAmanager::runScriptFile(const std::string &filename, script_finished_fn cb) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index cc59e559e9..240fa15685 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -8895,71 +8895,80 @@ class LLToolsSelectTool : public view_listener_t }; /// WINDLIGHT callbacks -class LLWorldEnvSettings : public view_listener_t -{ - void defocusEnvFloaters() +void defocusEnvFloaters() +{ + // currently there is only one instance of each floater + std::vector<std::string> env_floaters_names = {"env_edit_extdaycycle", "env_fixed_environmentent_water", + "env_fixed_environmentent_sky"}; + for (std::vector<std::string>::const_iterator it = env_floaters_names.begin(); it != env_floaters_names.end(); ++it) { - //currently there is only one instance of each floater - std::vector<std::string> env_floaters_names = { "env_edit_extdaycycle", "env_fixed_environmentent_water", "env_fixed_environmentent_sky" }; - for (std::vector<std::string>::const_iterator it = env_floaters_names.begin(); it != env_floaters_names.end(); ++it) + LLFloater *env_floater = LLFloaterReg::findTypedInstance<LLFloater>(*it); + if (env_floater) { - LLFloater* env_floater = LLFloaterReg::findTypedInstance<LLFloater>(*it); - if (env_floater) - { - env_floater->setFocus(FALSE); - } + env_floater->setFocus(FALSE); } } +} + +bool handle_env_setting_event(std::string event_name) +{ + if (event_name == "sunrise") + { + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNRISE, + LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); + } + else if (event_name == "noon") + { + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDDAY, + LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); + } + else if (event_name == "sunset") + { + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNSET, + LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); + } + else if (event_name == "midnight") + { + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDNIGHT, + LLEnvironment::TRANSITION_INSTANT); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); + } + else if (event_name == "region") + { + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL); + LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); + defocusEnvFloaters(); + } + else if (event_name == "pause_clouds") + { + if (LLEnvironment::instance().isCloudScrollPaused()) + LLEnvironment::instance().resumeCloudScroll(); + else + LLEnvironment::instance().pauseCloudScroll(); + } + else if (event_name == "adjust_tool") + { + LLFloaterReg::showInstance("env_adjust_snapshot"); + } + else if (event_name == "my_environs") + { + LLFloaterReg::showInstance("my_environments"); + } + return true; +} +class LLWorldEnvSettings : public view_listener_t +{ bool handleEvent(const LLSD& userdata) { - std::string event_name = userdata.asString(); - - if (event_name == "sunrise") - { - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNRISE, LLEnvironment::TRANSITION_INSTANT); - LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); - defocusEnvFloaters(); - } - else if (event_name == "noon") - { - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDDAY, LLEnvironment::TRANSITION_INSTANT); - LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); - defocusEnvFloaters(); - } - else if (event_name == "sunset") - { - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNSET, LLEnvironment::TRANSITION_INSTANT); - LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); - defocusEnvFloaters(); - } - else if (event_name == "midnight") - { - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDNIGHT, LLEnvironment::TRANSITION_INSTANT); - LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); - defocusEnvFloaters(); - } - else if (event_name == "region") - { - LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL); - LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); - defocusEnvFloaters(); - } - else if (event_name == "pause_clouds") - { - if (LLEnvironment::instance().isCloudScrollPaused()) - LLEnvironment::instance().resumeCloudScroll(); - else - LLEnvironment::instance().pauseCloudScroll(); - } - else if (event_name == "adjust_tool") - { - LLFloaterReg::showInstance("env_adjust_snapshot"); - } - else if (event_name == "my_environs") - { - LLFloaterReg::showInstance("my_environments"); - } + handle_env_setting_event(userdata.asString()); return true; } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index a90b32c984..b17a5d8b96 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -140,6 +140,7 @@ void handle_give_money_dialog(); bool enable_pay_object(); bool enable_buy_object(); bool handle_go_to(); +bool handle_env_setting_event(std::string event_name); // Export to XML or Collada void handle_export_selected( void * ); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 2634c8d908..9d5f5377b0 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -743,19 +743,25 @@ class LLFileEnableCloseAllWindows : public view_listener_t } }; +void close_all_windows() +{ + bool app_quitting = false; + gFloaterView->closeAllChildren(app_quitting); + LLFloaterSnapshot *floater_snapshot = LLFloaterSnapshot::findInstance(); + if (floater_snapshot) + floater_snapshot->closeFloater(app_quitting); + LLFloaterSimpleOutfitSnapshot *floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance(); + if (floater_outfit_snapshot) + floater_outfit_snapshot->closeFloater(app_quitting); + if (gMenuHolder) + gMenuHolder->hideMenus(); +} + class LLFileCloseAllWindows : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool app_quitting = false; - gFloaterView->closeAllChildren(app_quitting); - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); - if (floater_snapshot) - floater_snapshot->closeFloater(app_quitting); - LLFloaterSimpleOutfitSnapshot* floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance(); - if (floater_outfit_snapshot) - floater_outfit_snapshot->closeFloater(app_quitting); - if (gMenuHolder) gMenuHolder->hideMenus(); + close_all_windows(); return true; } }; diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 61572b9996..fd13eef8b7 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -72,6 +72,8 @@ void assign_defaults_and_show_upload_message( const std::string& display_name, std::string& description); +void close_all_windows(); + //consider moving all file pickers below to more suitable place class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) -- cgit v1.2.3 From a93e6c12fbf8a0b05bd2db820a41aa2e1182c143 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 13 Sep 2023 20:19:04 +0300 Subject: autorun selected script after login --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llluamanager.cpp | 19 +++++++++++++++++++ indra/newview/llluamanager.h | 2 ++ indra/newview/llstartup.cpp | 3 +++ 4 files changed, 35 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 816b7b7c92..cc9740d934 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -17063,6 +17063,17 @@ <key>Value</key> <integer>3</integer> </map> + <key>AutorunLuaScriptName</key> + <map> + <key>Comment</key> + <string>Script name to autorun after login.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>default.lua</string> + </map> <key>ResetUIScaleOnFirstRun</key> <map> <key>Comment</key> diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index edfd5c3cad..df5011597b 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -253,3 +253,22 @@ void LLLUAmanager::runScriptLine(const std::string &cmd, script_finished_fn cb) } }); } + +void LLLUAmanager::runScriptOnLogin() +{ + std::string filename = gSavedSettings.getString("AutorunLuaScriptName"); + if (filename.empty()) + { + LL_INFOS() << "Script name wasn't set." << LL_ENDL; + return; + } + + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + if (!gDirUtilp->fileExists(filename)) + { + LL_INFOS() << filename << " was not found." << LL_ENDL; + return; + } + + runScriptFile(filename); +} diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 5bdf58bd3d..4581c33ff2 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -34,6 +34,8 @@ public: static void runScriptFile(const std::string &filename, script_finished_fn cb = script_finished_fn()); static void runScriptLine(const std::string &cmd, script_finished_fn cb = script_finished_fn()); + + static void runScriptOnLogin(); }; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 1b0a814c45..748c79f9d6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -207,6 +207,7 @@ #include "llstacktrace.h" #include "threadpool.h" +#include "llluamanager.h" #include "llperfstats.h" @@ -2361,6 +2362,8 @@ bool idle_startup() LLPerfStats::StatsRecorder::setAutotuneInit(); + LLLUAmanager::runScriptOnLogin(); + return TRUE; } -- cgit v1.2.3 From 1d5db5e5926954b9f22469cd736d6cfb396491f4 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Thu, 14 Sep 2023 20:43:45 +0100 Subject: DRTVWR-589 - LUA support for UI commands, only if no parameters --- indra/newview/llluamanager.cpp | 18 ++++++++++++++++++ indra/newview/lluilistener.h | 3 ++- indra/newview/llviewermenu.cpp | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index edfd5c3cad..b251ebb6d5 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -38,6 +38,7 @@ #include "llviewermenu.h" #include "llviewermenufile.h" #include "llviewerwindow.h" +#include "lluilistener.h" #include <boost/algorithm/string/replace.hpp> @@ -52,6 +53,9 @@ extern "C" #pragma comment(lib, "liblua54.a") #endif +// FIXME extremely hacky way to get to the UI Listener framework. There's almost certainly a cleaner way. +extern LLUIListener sUIListener; + int lua_printWarning(lua_State *L) { std::string msg(lua_tostring(L, 1)); @@ -163,6 +167,18 @@ int lua_env_setting_event(lua_State *L) return 1; } +int lua_run_ui_command(lua_State *L) +{ + std::string func_name = lua_tostring(L,1); + LL_WARNS("LUA") << "running ui func " << func_name << LL_ENDL; + LLSD event; + event["function"] = func_name; + event["parameter"] = LLSD(); + sUIListener.call(event); + + return 1; +} + bool checkLua(lua_State *L, int r, std::string &error_msg) { if (r != LUA_OK) @@ -194,6 +210,8 @@ void initLUA(lua_State *L) lua_register(L, "env_setting_event", lua_env_setting_event); lua_register(L, "set_debug_setting_bool", lua_set_debug_setting_bool); + + lua_register(L, "run_ui_command", lua_run_ui_command); } void LLLUAmanager::runScriptFile(const std::string &filename, script_finished_fn cb) diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index 08724024dc..e53984dae2 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -39,7 +39,8 @@ class LLUIListener: public LLEventAPI public: LLUIListener(); -private: +// FIXME These fields are intended to be private, changed here to support very hacky code in llluamanager.cpp +public: void call(const LLSD& event) const; void getValue(const LLSD&event) const; }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 240fa15685..50ce213f20 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -171,6 +171,8 @@ extern BOOL gShaderProfileFrame; // Globals // +LLUIListener sUIListener; + LLMenuBarGL *gMenuBarView = NULL; LLViewerMenuHolderGL *gMenuHolder = NULL; LLMenuGL *gPopupMenuView = NULL; @@ -348,8 +350,6 @@ public: static LLMenuParcelObserver* gMenuParcelObserver = NULL; -static LLUIListener sUIListener; - LLMenuParcelObserver::LLMenuParcelObserver() { LLViewerParcelMgr::getInstance()->addObserver(this); -- cgit v1.2.3 From a870b767337d0f9c54953189f99a77ca06d634a4 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Thu, 14 Sep 2023 21:21:03 +0100 Subject: DRTVWR-589 - lua support parameter to UI commands --- indra/newview/llluamanager.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 7045379964..1a1732aa5e 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -169,11 +169,24 @@ int lua_env_setting_event(lua_State *L) int lua_run_ui_command(lua_State *L) { - std::string func_name = lua_tostring(L,1); - LL_WARNS("LUA") << "running ui func " << func_name << LL_ENDL; + int top = lua_gettop(L); + std::string func_name; + if (top >= 1) + { + func_name = lua_tostring(L,1); + } + std::string parameter; + if (top >= 2) + { + parameter = lua_tostring(L,2); + } + LL_WARNS("LUA") << "running ui func " << func_name << " parameter " << parameter << LL_ENDL; LLSD event; event["function"] = func_name; - event["parameter"] = LLSD(); + if (!parameter.empty()) + { + event["parameter"] = parameter; + } sUIListener.call(event); return 1; -- cgit v1.2.3 From 66f39dece85d38afb1d8272ca89112ea70e05494 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Fri, 15 Sep 2023 21:30:26 +0100 Subject: DRTVWR-589 - lua file browser added run button to allow re-running same script --- indra/newview/llfloaterluadebug.cpp | 12 ++++++++++++ indra/newview/llfloaterluadebug.h | 1 + indra/newview/lluilistener.cpp | 2 +- indra/newview/skins/default/xui/en/floater_lua_debug.xml | 10 ++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index e7d220c503..9ca554d4ad 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -57,6 +57,7 @@ BOOL LLFloaterLUADebug::postBuild() getChild<LLButton>("execute_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); getChild<LLButton>("browse_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnBrowse, this)); + getChild<LLButton>("run_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnRun, this)); #if !LL_WINDOWS getChild<LLButton>("execute_btn")->setEnabled(false); @@ -85,6 +86,17 @@ void LLFloaterLUADebug::onBtnBrowse() (new LLFilePickerReplyThread(boost::bind(&LLFloaterLUADebug::runSelectedScript, this, _1), LLFilePicker::FFLOAD_LUA, false))->getFile(); } +void LLFloaterLUADebug::onBtnRun() +{ + std::vector<std::string> filenames; + std::string filepath = mScriptPath->getText(); + if (!filepath.empty()) + { + filenames.push_back(filepath); + runSelectedScript(filenames); + } +} + void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames) { mResultOutput->setValue(""); diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index a7a3b695d4..300d954aea 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -49,6 +49,7 @@ class LLFloaterLUADebug : void onExecuteClicked(); void onBtnBrowse(); + void onBtnRun(); void runSelectedScript(const std::vector<std::string> &filenames); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 956f5cf187..97a2be6aa3 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -67,7 +67,7 @@ void LLUIListener::call(const LLSD& event) const // API: we provide no reply. Therefore, a typo in the script will // provide no feedback whatsoever to that script. To rub the coder's // nose in such an error, crump rather than quietly ignoring it. - LL_ERRS("LLUIListener") << "function '" << event["function"] << "' not found" << LL_ENDL; + LL_WARNS("LLUIListener") << "function '" << event["function"] << "' not found" << LL_ENDL; } else { diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml index 7ed6c35151..05f4db009e 100644 --- a/indra/newview/skins/default/xui/en/floater_lua_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -95,4 +95,14 @@ name="browse_btn" top_delta="-2" width="75" /> + <button + follows="left|bottom" + height="25" + label="Run" + label_selected="Run" + layout="topleft" + left_pad="5" + name="run_btn" + top_delta="-2" + width="50" /> </floater> -- cgit v1.2.3 From e56d9576c5e57c5820a54e0eb2b0f0805b2030ff Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Mon, 18 Sep 2023 15:22:34 +0100 Subject: DRTVWR-589 - close_floater by name --- indra/newview/llluamanager.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 1a1732aa5e..401ed33c44 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -107,6 +107,20 @@ int lua_open_floater(lua_State *L) return 1; } +int lua_close_floater(lua_State *L) +{ + std::string floater_name(lua_tostring(L, 1)); + + LLSD key; + if (floater_name == "profile") + { + key["id"] = gAgentID; + } + LLFloaterReg::hideInstance(floater_name, key); + + return 1; +} + int lua_close_all_floaters(lua_State *L) { close_all_windows(); @@ -214,6 +228,7 @@ void initLUA(lua_State *L) lua_register(L, "nearby_chat_send", lua_nearby_chat_send); lua_register(L, "wear_by_name", lua_wear_by_name); lua_register(L, "open_floater", lua_open_floater); + lua_register(L, "close_floater", lua_close_floater); lua_register(L, "close_all_floaters", lua_close_all_floaters); lua_register(L, "open_wearing_tab", lua_open_wearing_tab); lua_register(L, "snapshot_to_file", lua_snapshot_to_file); -- cgit v1.2.3 From b7693cf78435c91a46eedc37d0830aed006cb2d5 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 19 Sep 2023 17:15:05 +0300 Subject: lua support for notifications --- indra/newview/llluamanager.cpp | 80 +++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 401ed33c44..6d34aaba38 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -34,6 +34,7 @@ #include "llfloaterreg.h" #include "llfloaterimnearbychat.h" #include "llfloatersidepanelcontainer.h" +#include "llnotificationsutil.h" #include "llvoavatarself.h" #include "llviewermenu.h" #include "llviewermenufile.h" @@ -64,6 +65,18 @@ int lua_printWarning(lua_State *L) return 1; } +bool checkLua(lua_State *L, int r, std::string &error_msg) +{ + if (r != LUA_OK) + { + error_msg = lua_tostring(L, -1); + + LL_WARNS() << error_msg << LL_ENDL; + return false; + } + return true; +} + int lua_avatar_sit(lua_State *L) { gAgent.sitDown(); @@ -181,6 +194,59 @@ int lua_env_setting_event(lua_State *L) return 1; } +void handle_notification_dialog(const LLSD ¬ification, const LLSD &response, lua_State *L, std::string response_cb) +{ + if (!response_cb.empty()) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + lua_pushinteger(L, option); + lua_setglobal(L, response_cb.c_str()); + } +} + +int lua_show_notification(lua_State *L) +{ + std::string notification(lua_tostring(L, 1)); + + if (lua_type(L, 2) == LUA_TTABLE) + { + LLSD args; + + // push first key + lua_pushnil(L); + while (lua_next(L, 2) != 0) + { + // right now -2 is key, -1 is value + lua_rawgeti(L, -1, 1); + lua_rawgeti(L, -2, 2); + std::string key = lua_tostring(L, -2); + std::string value = lua_tostring(L, -1); + args[key] = value; + lua_pop(L, 3); + } + + std::string response_cb; + if (lua_type(L, 3) == LUA_TSTRING) + { + response_cb = lua_tostring(L, 3); + } + + LLNotificationsUtil::add(notification, args, LLSD(), boost::bind(handle_notification_dialog, _1, _2, L, response_cb)); + } + else if (lua_type(L, 2) == LUA_TSTRING) + { + std::string response_cb = lua_tostring(L, 2); + LLNotificationsUtil::add(notification, LLSD(), LLSD(), boost::bind(handle_notification_dialog, _1, _2, L, response_cb)); + } + else + { + LLNotificationsUtil::add(notification); + } + + return 1; +} + int lua_run_ui_command(lua_State *L) { int top = lua_gettop(L); @@ -206,18 +272,6 @@ int lua_run_ui_command(lua_State *L) return 1; } -bool checkLua(lua_State *L, int r, std::string &error_msg) -{ - if (r != LUA_OK) - { - error_msg = lua_tostring(L, -1); - - LL_WARNS() << error_msg << LL_ENDL; - return false; - } - return true; -} - void initLUA(lua_State *L) { lua_register(L, "print_warning", lua_printWarning); @@ -239,6 +293,8 @@ void initLUA(lua_State *L) lua_register(L, "env_setting_event", lua_env_setting_event); lua_register(L, "set_debug_setting_bool", lua_set_debug_setting_bool); + lua_register(L, "show_notification", lua_show_notification); + lua_register(L, "run_ui_command", lua_run_ui_command); } -- cgit v1.2.3 From ba86a64f10ca4475dbfcc457de72a13694db6125 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Tue, 19 Sep 2023 16:10:17 +0100 Subject: DRTVWR-589 - click_child, limited support for pushing buttons in a floater --- indra/newview/llluamanager.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 401ed33c44..a30a321bcc 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -127,6 +127,18 @@ int lua_close_all_floaters(lua_State *L) return 1; } +int lua_click_child(lua_State *L) +{ + std::string parent_name(lua_tostring(L, 1)); + std::string child_name(lua_tostring(L, 2)); + + LLFloater *floater = LLFloaterReg::findInstance(parent_name); + LLUICtrl *child = floater->getChild<LLUICtrl>(child_name, true); + child->onCommit(); + + return 1; +} + int lua_snapshot_to_file(lua_State *L) { std::string filename(lua_tostring(L, 1)); @@ -230,6 +242,7 @@ void initLUA(lua_State *L) lua_register(L, "open_floater", lua_open_floater); lua_register(L, "close_floater", lua_close_floater); lua_register(L, "close_all_floaters", lua_close_all_floaters); + lua_register(L, "click_child", lua_click_child); lua_register(L, "open_wearing_tab", lua_open_wearing_tab); lua_register(L, "snapshot_to_file", lua_snapshot_to_file); -- cgit v1.2.3 From ac67a7c7a11c188281f357f8f2e6e10eeb3a5b78 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Wed, 20 Sep 2023 18:24:18 +0100 Subject: DRTVWR-589 - added play animation and started to collect demo scripts --- indra/newview/llinventoryfunctions.cpp | 13 ++++++++++++ indra/newview/llinventoryfunctions.h | 16 ++++++++++++++ indra/newview/llinventorymodel.cpp | 11 ++++++++++ indra/newview/llluamanager.cpp | 38 +++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 145814ab41..bf8b49e1e0 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2155,6 +2155,19 @@ bool LLNameCategoryCollector::operator()( return false; } +bool LLNameItemCollector::operator()( + LLInventoryCategory* cat, LLInventoryItem* item) +{ + if(item) + { + if (!LLStringUtil::compareInsensitive(mName, item->getName())) + { + return true; + } + } + return false; +} + bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 8c8bd789c2..1bfd0f2b93 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -312,6 +312,22 @@ protected: std::string mName; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLNameItemCollector +// +// Collects items based on case-insensitive match of prefix +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLNameItemCollector : public LLInventoryCollectFunctor +{ +public: + LLNameItemCollector(const std::string& name) : mName(name) {} + virtual ~LLNameItemCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + std::string mName; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFindCOFValidItems // diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9c4e122481..bbac9f4123 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -4421,6 +4421,17 @@ std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const return result; } +/* +const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& path) +{ + vector<std::string> path_elts; + boost::algorithm::split(path_elts, path, boost::is_any_of("/")); + for(path_elts, auto e) + { + } +} +*/ + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index a154daeeed..92a012c921 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -40,6 +40,8 @@ #include "llviewermenufile.h" #include "llviewerwindow.h" #include "lluilistener.h" +#include "llanimationstates.h" +#include "llinventoryfunctions.h" #include <boost/algorithm/string/replace.hpp> @@ -187,7 +189,7 @@ int lua_set_debug_setting_bool(lua_State *L) return 1; } - int lua_get_avatar_name(lua_State *L) +int lua_get_avatar_name(lua_State *L) { std::string name = gAgentAvatarp->getFullname(); lua_pushstring(L, name.c_str()); @@ -200,6 +202,39 @@ int lua_is_avatar_flying(lua_State *L) return 1; } +int lua_play_animation(lua_State *L) +{ + std::string anim_name = lua_tostring(L,1); + + EAnimRequest req = ANIM_REQUEST_START; + if (lua_gettop(L) > 1) + { + req = (EAnimRequest) (int) lua_tonumber(L, 2); + } + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLNameItemCollector has_name(anim_name); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + for (auto& item: item_array) + { + if (item->getType() == LLAssetType::AT_ANIMATION) + { + LLUUID anim_id = item->getAssetUUID(); + LL_INFOS() << "Playing animation " << anim_id << LL_ENDL; + gAgent.sendAnimationRequest(anim_id, req); + return 1; + } + } + LL_WARNS() << "No animation found for name " << anim_name << LL_ENDL; + + return 1; +} + int lua_env_setting_event(lua_State *L) { handle_env_setting_event(lua_tostring(L, 1)); @@ -302,6 +337,7 @@ void initLUA(lua_State *L) lua_register(L, "get_avatar_name", lua_get_avatar_name); lua_register(L, "is_avatar_flying", lua_is_avatar_flying); + lua_register(L, "play_animation", lua_play_animation); lua_register(L, "env_setting_event", lua_env_setting_event); lua_register(L, "set_debug_setting_bool", lua_set_debug_setting_bool); -- cgit v1.2.3 From e3ba75101a94cff9b1409c58f796587cf2702f10 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 21 Sep 2023 14:41:00 +0300 Subject: DRTVWR-589 - adding menu items to the top menu --- indra/newview/llluamanager.cpp | 89 ++++++++++++++++++---- .../skins/default/xui/en/floater_lua_debug.xml | 11 ++- 2 files changed, 80 insertions(+), 20 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 92a012c921..03a5d10975 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -79,6 +79,25 @@ bool checkLua(lua_State *L, int r, std::string &error_msg) return true; } +LLSD luatable_to_llsd(lua_State *L, S32 idx) +{ + LLSD args; + + // push first key + lua_pushnil(L); + while (lua_next(L, idx) != 0) + { + // right now -2 is key, -1 is value + lua_rawgeti(L, -1, 1); + lua_rawgeti(L, -2, 2); + std::string key = lua_tostring(L, -2); + std::string value = lua_tostring(L, -1); + args[key] = value; + lua_pop(L, 3); + } + return args; +} + int lua_avatar_sit(lua_State *L) { gAgent.sitDown(); @@ -258,20 +277,7 @@ int lua_show_notification(lua_State *L) if (lua_type(L, 2) == LUA_TTABLE) { - LLSD args; - - // push first key - lua_pushnil(L); - while (lua_next(L, 2) != 0) - { - // right now -2 is key, -1 is value - lua_rawgeti(L, -1, 1); - lua_rawgeti(L, -2, 2); - std::string key = lua_tostring(L, -2); - std::string value = lua_tostring(L, -1); - args[key] = value; - lua_pop(L, 3); - } + LLSD args = luatable_to_llsd(L, 2); std::string response_cb; if (lua_type(L, 3) == LUA_TSTRING) @@ -294,6 +300,57 @@ int lua_show_notification(lua_State *L) return 1; } +int lua_add_menu_item(lua_State *L) +{ + std::string menu(lua_tostring(L, 1)); + if (lua_type(L, 2) == LUA_TTABLE) + { + LLSD args = luatable_to_llsd(L, 2); + + LLMenuItemCallGL::Params item_params; + item_params.name = args["name"]; + item_params.label = args["label"]; + + LLUICtrl::CommitCallbackParam item_func; + item_func.function_name = args["function"]; + if (args.has("parameter")) + { + item_func.parameter = args["parameter"]; + } + item_params.on_click = item_func; + + LLMenuItemCallGL *menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gMenuBarView->findChildMenuByName(menu, true)->append(menu_item); + } + + return 1; +} + +int lua_add_menu_separator(lua_State *L) +{ + std::string menu(lua_tostring(L, 1)); + gMenuBarView->findChildMenuByName(menu, true)->addSeparator(); + + return 1; +} + +int lua_add_menu(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TTABLE) + { + LLSD args = luatable_to_llsd(L, 1); + + LLMenuGL::Params item_params; + item_params.name = args["name"]; + item_params.label = args["label"]; + + LLMenuGL *menu = LLUICtrlFactory::create<LLMenuGL>(item_params); + gMenuBarView->appendMenu(menu); + } + + return 1; +} + int lua_run_ui_command(lua_State *L) { int top = lua_gettop(L); @@ -343,6 +400,10 @@ void initLUA(lua_State *L) lua_register(L, "set_debug_setting_bool", lua_set_debug_setting_bool); lua_register(L, "show_notification", lua_show_notification); + lua_register(L, "add_menu_separator", lua_add_menu_separator); + lua_register(L, "add_menu_item", lua_add_menu_item); + lua_register(L, "add_menu", lua_add_menu); + lua_register(L, "run_ui_command", lua_run_ui_command); } diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml index 05f4db009e..0de26161e7 100644 --- a/indra/newview/skins/default/xui/en/floater_lua_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -10,7 +10,7 @@ save_rect="true" title="LUA DEBUG" single_instance="true" - width="530"> + width="535"> <text type="string" length="1" @@ -37,7 +37,7 @@ name="lua_cmd" select_on_focus="true" top_delta="30" - width="415" /> + width="435" /> <button follows="left|bottom" height="25" @@ -55,7 +55,7 @@ layout="topleft" name="result_text" follows="left|top" - width="495" + width="515" top_delta="40" word_wrap="true" /> <text @@ -84,7 +84,7 @@ name="script_path" select_on_focus="true" top_delta="-2" - width="315" /> + width="320" /> <button follows="left|bottom" height="25" @@ -94,7 +94,7 @@ left_pad="5" name="browse_btn" top_delta="-2" - width="75" /> + width="70" /> <button follows="left|bottom" height="25" @@ -103,6 +103,5 @@ layout="topleft" left_pad="5" name="run_btn" - top_delta="-2" width="50" /> </floater> -- cgit v1.2.3 From fac31ad392c3df22b2254a00e75c841050195763 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 21 Sep 2023 16:16:00 +0300 Subject: DRTVWR-589 - allow adding branch to the menu --- indra/newview/llluamanager.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 03a5d10975..3ca38394ea 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -79,7 +79,7 @@ bool checkLua(lua_State *L, int r, std::string &error_msg) return true; } -LLSD luatable_to_llsd(lua_State *L, S32 idx) +LLSD luatable_to_llsd_string(lua_State *L, S32 idx) { LLSD args; @@ -277,7 +277,7 @@ int lua_show_notification(lua_State *L) if (lua_type(L, 2) == LUA_TTABLE) { - LLSD args = luatable_to_llsd(L, 2); + LLSD args = luatable_to_llsd_string(L, 2); std::string response_cb; if (lua_type(L, 3) == LUA_TSTRING) @@ -305,7 +305,7 @@ int lua_add_menu_item(lua_State *L) std::string menu(lua_tostring(L, 1)); if (lua_type(L, 2) == LUA_TTABLE) { - LLSD args = luatable_to_llsd(L, 2); + LLSD args = luatable_to_llsd_string(L, 2); LLMenuItemCallGL::Params item_params; item_params.name = args["name"]; @@ -338,11 +338,12 @@ int lua_add_menu(lua_State *L) { if (lua_type(L, 1) == LUA_TTABLE) { - LLSD args = luatable_to_llsd(L, 1); + LLSD args = luatable_to_llsd_string(L, 1); LLMenuGL::Params item_params; item_params.name = args["name"]; item_params.label = args["label"]; + item_params.can_tear_off = args["tear_off"]; LLMenuGL *menu = LLUICtrlFactory::create<LLMenuGL>(item_params); gMenuBarView->appendMenu(menu); @@ -351,6 +352,25 @@ int lua_add_menu(lua_State *L) return 1; } +int lua_add_branch(lua_State *L) +{ + std::string menu(lua_tostring(L, 1)); + if (lua_type(L, 2) == LUA_TTABLE) + { + LLSD args = luatable_to_llsd_string(L, 2); + + LLMenuGL::Params item_params; + item_params.name = args["name"]; + item_params.label = args["label"]; + item_params.can_tear_off = args["tear_off"]; + + LLMenuGL *branch = LLUICtrlFactory::create<LLMenuGL>(item_params); + gMenuBarView->findChildMenuByName(menu, true)->appendMenu(branch); + } + + return 1; +} + int lua_run_ui_command(lua_State *L) { int top = lua_gettop(L); @@ -403,7 +423,7 @@ void initLUA(lua_State *L) lua_register(L, "add_menu_separator", lua_add_menu_separator); lua_register(L, "add_menu_item", lua_add_menu_item); lua_register(L, "add_menu", lua_add_menu); - + lua_register(L, "add_branch", lua_add_branch); lua_register(L, "run_ui_command", lua_run_ui_command); } -- cgit v1.2.3 From e5dd39a95e33e6b57a1cf74c32ea511edc43c68a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 21 Sep 2023 13:25:13 -0400 Subject: DRTVWR-589: Add lua_tollsd() and lua_pushllsd() functions. --- indra/newview/llluamanager.cpp | 250 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 1a1732aa5e..c4603e493c 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -49,6 +49,8 @@ extern "C" #include "lua/lualib.h" } +#include <cstring> // std::memcpy() + #if LL_WINDOWS #pragma comment(lib, "liblua54.a") #endif @@ -303,3 +305,251 @@ void LLLUAmanager::runScriptOnLogin() runScriptFile(filename); } + +std::string lua_tostdstring(lua_State* L, int index) +{ + size_t len; + const char* strval{ lua_tolstring(L, index, &len) }; + return { strval, len }; +} + +// By analogy with existing lua_tomumble() functions, return an LLSD object +// corresponding to the Lua object at stack index 'index' in state L. +// This function assumes that a Lua caller is fully aware that they're trying +// to call a viewer function. In other words, the caller must specifically +// construct Lua data convertible to LLSD. +LLSD lua_tollsd(lua_State* L, int index) +{ + switch (lua_type(L, index)) + { + case LUA_TNONE: + case LUA_TNIL: + return {}; + + case LUA_TBOOLEAN: + return bool(lua_toboolean(L, index)); + + case LUA_TNUMBER: + { + // check if integer truncation leaves the number intact + lua_Integer intval{ lua_tointeger(L, index) }; + lua_Number numval{ lua_tonumber(L, index) }; + if (lua_Number(intval) == numval) + { + return intval; + } + else + { + return numval; + } + } + + case LUA_TSTRING: + return lua_tostdstring(L, index); + + case LUA_TUSERDATA: + { + LLSD::Binary binary(lua_objlen(L, index)); + std::memcpy(binary.data(), lua_touserdata(L, index), binary.size()); + return binary; + } + + case LUA_TTABLE: + { + // A Lua table correctly constructed to convert to LLSD will have + // either consecutive integer keys starting at 1, which we represent + // as an LLSD array (with Lua index 1 at C++ index 0), or will have + // all string keys. + // Possible looseness could include: + // - All integer keys >= 1, but with "holes," could produce an LLSD + // array with isUndefined() entries at unspecified keys. We could + // specify a maximum size of allowable gap, and throw an error if a + // gap exceeds that size. + // - A mix of integer and string keys could produce an LLSD map in + // which the integer keys are converted to string. (Key conversion + // must be performed in C++, not Lua, to avoid confusing + // lua_next().) + // - However, since in Lua t[0] and t["0"] are distinct table entries, + // do not consider converting numeric string keys to int to return + // an LLSD array. + // But until we get more experience with actual Lua scripts in + // practice, let's say that any deviation is a Lua coding error. + // An important property of the strict definition above is that most + // conforming data blobs can make a round trip across the language + // boundary and still compare equal. A non-conforming data blob would + // lose that property. + // Known exceptions to round trip identity: + // - Empty LLSD map and empty LLSD array convert to empty Lua table. + // But empty Lua table converts to isUndefined() LLSD object. + // - LLSD::Real with integer value returns as LLSD::Integer. + // - LLSD::UUID, LLSD::Date and LLSD::URI all convert to Lua string, + // and so return as LLSD::String. + lua_pushnil(L); // first key + if (! lua_next(L, index)) + { + // it's a table, but the table is empty -- no idea if it should be + // modeled as empty array or empty map -- return isUndefined(), + // which can be consumed as either + return {}; + } + // key is at index -2, value at index -1 + // from here until lua_next() returns 0, have to lua_pop(2) if we + // return early + // Remember the type of the first key + auto firstkeytype{ lua_type(L, -2) }; + switch (firstkeytype) + { + case LUA_TNUMBER: + { + LLSD result{ LLSD::emptyArray() }; + // right away expand the result array to the size we'll need + result[lua_objlen(L, index) - 1] = LLSD(); + // track the consecutive indexes we require + LLSD::Integer expected_index{ 0 }; + do + { + auto arraykeytype{ lua_type(L, -2) }; + switch (arraykeytype) + { + case LUA_TNUMBER: + { + lua_Number actual_index{ lua_tonumber(L, -2) }; + if (actual_index != lua_Number(++expected_index)) + { + // key isn't consecutive starting at 1 (may not even be an + // integer) - this doesn't fit our LLSD array constraints + lua_pop(L, 2); + return luaL_error(L, "Expected array key %d, got %f instead", + int(expected_index), actual_index); + } + + result.append(lua_tollsd(L, -1)); + break; + } + + case LUA_TSTRING: + // break out strings specially to report the value + lua_pop(L, 2); + return luaL_error(L, "Cannot convert string array key '%s' to LLSD", + lua_tostring(L, -2)); + + default: + lua_pop(L, 2); + return luaL_error(L, "Cannot convert %s array key to LLSD", + lua_typename(L, arraykeytype)); + } + + // remove value, keep key for next iteration + lua_pop(L, 1); + } while (lua_next(L, index) != 0); + return result; + } + + case LUA_TSTRING: + { + LLSD result{ LLSD::emptyMap() }; + do + { + auto mapkeytype{ lua_type(L, -2) }; + if (mapkeytype != LUA_TSTRING) + { + lua_pop(L, 2); + return luaL_error(L, "Cannot convert %s map key to LLSD", + lua_typename(L, mapkeytype)); + } + + result[lua_tostdstring(L, -2)] = lua_tollsd(L, -1); + // remove value, keep key for next iteration + lua_pop(L, 1); + } while (lua_next(L, index) != 0); + return result; + } + + default: + lua_pop(L, 2); + return luaL_error(L, "Cannot convert %s table key to LLSD", + lua_typename(L, firstkeytype)); + } + } + + default: + // Other Lua entities (e.g. function, C function, light userdata, + // thread, userdata) are not convertible to LLSD, indicating a coding + // error in the caller. + return luaL_error(L, "Cannot convert type %s to LLSD", + lua_typename(L, lua_type(L, index))); + } +} + +// By analogy with existing lua_pushmumble() functions, push onto state L's +// stack a Lua object corresponding to the passed LLSD object. +int lua_pushllsd(lua_State* L, const LLSD& data) +{ + switch (data.type()) + { + case LLSD::TypeUndefined: + lua_pushnil(L); + break; + + case LLSD::TypeBoolean: + lua_pushboolean(L, data.asBoolean()); + break; + + case LLSD::TypeInteger: + lua_pushinteger(L, data.asInteger()); + break; + + case LLSD::TypeReal: + lua_pushnumber(L, data.asReal()); + break; + + case LLSD::TypeBinary: + { + auto binary{ data.asBinary() }; + std::memcpy(lua_newuserdata(L, binary.size()), binary.data(), binary.size()); + break; + } + + case LLSD::TypeMap: + { + // push a new table with space for our non-array keys + lua_createtable(L, 0, data.size()); + for (const auto& pair: llsd::inMap(data)) + { + // push value -- so now table is at -2, value at -1 + lua_pushllsd(L, pair.second); + // pop value, assign to table[key] + lua_setfield(L, -2, pair.first.c_str()); + } + break; + } + + case LLSD::TypeArray: + { + // push a new table with space for array entries + lua_createtable(L, data.size(), 0); + lua_Integer index{ 0 }; + for (const auto& item: llsd::inArray(data)) + { + // push new index value: table at -2, index at -1 + lua_pushinteger(L, ++index); + // push new array value: table at -3, index at -2, value at -1 + lua_pushllsd(L, item); + // pop key and value, assign table[key] = value + lua_settable(L, -3); + } + break; + } + + case LLSD::TypeString: + case LLSD::TypeUUID: + case LLSD::TypeDate: + case LLSD::TypeURI: + default: + { + auto strdata{ data.asString() }; + lua_pushlstring(L, strdata.c_str(), strdata.length()); + break; + } + } +} -- cgit v1.2.3 From 87d44a24d7ac6c1ac72e8b76ad66dcd890806f29 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 21 Sep 2023 22:50:07 -0400 Subject: DRTVWR-589: lua_objlen() only defined in luaconf.h --- indra/newview/llluamanager.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 0f984ca0ca..0cf2157caf 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -48,6 +48,7 @@ extern "C" { #include "lua/lua.h" +#include "lua/luaconf.h" #include "lua/lauxlib.h" #include "lua/lualib.h" } -- cgit v1.2.3 From d411240a04dbd111bdc89339a0675c8818ff2578 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 22 Sep 2023 08:47:16 -0400 Subject: DRTVWR-589: lua_objlen() removed, use lua_rawlen() instead --- indra/newview/llluamanager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 0cf2157caf..9e46982b10 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -48,7 +48,6 @@ extern "C" { #include "lua/lua.h" -#include "lua/luaconf.h" #include "lua/lauxlib.h" #include "lua/lualib.h" } @@ -551,7 +550,7 @@ LLSD lua_tollsd(lua_State* L, int index) case LUA_TUSERDATA: { - LLSD::Binary binary(lua_objlen(L, index)); + LLSD::Binary binary(lua_rawlen(L, index)); std::memcpy(binary.data(), lua_touserdata(L, index), binary.size()); return binary; } @@ -605,7 +604,7 @@ LLSD lua_tollsd(lua_State* L, int index) { LLSD result{ LLSD::emptyArray() }; // right away expand the result array to the size we'll need - result[lua_objlen(L, index) - 1] = LLSD(); + result[lua_rawlen(L, index) - 1] = LLSD(); // track the consecutive indexes we require LLSD::Integer expected_index{ 0 }; do -- cgit v1.2.3 From 9227df899fad54efbb14a235cf17bf403fae3823 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 22 Sep 2023 10:31:42 -0400 Subject: DRTVWR-589: Existing lua_pushmumble() functions usually return void. --- indra/newview/llluamanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 9e46982b10..cbce4090af 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -684,7 +684,7 @@ LLSD lua_tollsd(lua_State* L, int index) // By analogy with existing lua_pushmumble() functions, push onto state L's // stack a Lua object corresponding to the passed LLSD object. -int lua_pushllsd(lua_State* L, const LLSD& data) +void lua_pushllsd(lua_State* L, const LLSD& data) { switch (data.type()) { -- cgit v1.2.3 From 3f9c5b7f4ce114811919f0baff062b6747babfd2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 22 Sep 2023 15:57:15 -0400 Subject: DRTVWR-589: Introduce LuaFunction: simplified function registration. --- indra/newview/llluamanager.cpp | 159 ++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 73 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index cbce4090af..a9658e77e5 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -53,15 +53,74 @@ extern "C" } #include <cstring> // std::memcpy() +#include <map> +#include <string_view> #if LL_WINDOWS #pragma comment(lib, "liblua54.a") #endif +LLSD lua_tollsd(lua_State* L, int index); +void lua_pushllsd(lua_State* L, const LLSD& data); + // FIXME extremely hacky way to get to the UI Listener framework. There's almost certainly a cleaner way. extern LLUIListener sUIListener; -int lua_printWarning(lua_State *L) +/** + * LuaFunction is a base class containing a static registry of its static + * subclass call() methods. call() is NOT virtual: instead, each subclass + * constructor passes a pointer to its distinct call() method to the base- + * class constructor, along with a name by which to register that method. + * + * The init() method walks the registry and registers each such name with the + * passed lua_State. + */ +class LuaFunction +{ +public: + typedef int (*funcptr)(lua_State* L); + LuaFunction(const std::string_view& name, funcptr function) + { + getRegistry().emplace(name, function); + } + + static void init(lua_State* L) + { + for (const auto& pair: getRegistry()) + { + lua_register(L, pair.first.c_str(), pair.second); + } + } + +private: + using Registry = std::map<std::string, funcptr>; + static Registry& getRegistry() + { + // use a function-local static to ensure it's initialized + static Registry registry; + return registry; + } +}; + +/** + * lua_function(name) is a macro to facilitate defining C++ functions + * available to Lua. It defines a subclass of LuaFunction and declares a + * static instance of that subclass, thereby forcing the compiler to call its + * constructor at module initialization time. The constructor passes the + * stringized instance name to its LuaFunction base-class constructor, along + * with a pointer to the static subclass call() method. It then emits the + * call() method definition header, to be followed by a method body enclosed + * in curly braces as usual. + */ +#define lua_function(name) \ +static struct name##_ : public LuaFunction \ +{ \ + name##_(): LuaFunction(#name, &call) {} \ + static int call(lua_State* L); \ +} name; \ +int name##_::call(lua_State* L) + +lua_function(print_warning) { std::string msg(lua_tostring(L, 1)); @@ -81,38 +140,19 @@ bool checkLua(lua_State *L, int r, std::string &error_msg) return true; } -LLSD luatable_to_llsd_string(lua_State *L, S32 idx) -{ - LLSD args; - - // push first key - lua_pushnil(L); - while (lua_next(L, idx) != 0) - { - // right now -2 is key, -1 is value - lua_rawgeti(L, -1, 1); - lua_rawgeti(L, -2, 2); - std::string key = lua_tostring(L, -2); - std::string value = lua_tostring(L, -1); - args[key] = value; - lua_pop(L, 3); - } - return args; -} - -int lua_avatar_sit(lua_State *L) +lua_function(avatar_sit) { gAgent.sitDown(); return 1; } -int lua_avatar_stand(lua_State *L) +lua_function(avatar_stand) { gAgent.standUp(); return 1; } -int lua_nearby_chat_send(lua_State *L) +lua_function(nearby_chat_send) { std::string msg(lua_tostring(L, 1)); LLFloaterIMNearbyChat *nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); @@ -121,7 +161,7 @@ int lua_nearby_chat_send(lua_State *L) return 1; } -int lua_wear_by_name(lua_State *L) +lua_function(wear_by_name) { std::string folder_name(lua_tostring(L, 1)); LLAppearanceMgr::instance().wearOutfitByName(folder_name); @@ -129,7 +169,7 @@ int lua_wear_by_name(lua_State *L) return 1; } -int lua_open_floater(lua_State *L) +lua_function(open_floater) { std::string floater_name(lua_tostring(L, 1)); @@ -143,7 +183,7 @@ int lua_open_floater(lua_State *L) return 1; } -int lua_close_floater(lua_State *L) +lua_function(close_floater) { std::string floater_name(lua_tostring(L, 1)); @@ -157,13 +197,13 @@ int lua_close_floater(lua_State *L) return 1; } -int lua_close_all_floaters(lua_State *L) +lua_function(close_all_floaters) { close_all_windows(); return 1; } -int lua_click_child(lua_State *L) +lua_function(click_child) { std::string parent_name(lua_tostring(L, 1)); std::string child_name(lua_tostring(L, 2)); @@ -175,7 +215,7 @@ int lua_click_child(lua_State *L) return 1; } -int lua_snapshot_to_file(lua_State *L) +lua_function(snapshot_to_file) { std::string filename(lua_tostring(L, 1)); @@ -195,13 +235,13 @@ int lua_snapshot_to_file(lua_State *L) return 1; } -int lua_open_wearing_tab(lua_State *L) +lua_function(open_wearing_tab) { LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "now_wearing")); return 1; } -int lua_set_debug_setting_bool(lua_State *L) +lua_function(set_debug_setting_bool) { std::string setting_name(lua_tostring(L, 1)); bool value(lua_toboolean(L, 2)); @@ -210,20 +250,20 @@ int lua_set_debug_setting_bool(lua_State *L) return 1; } -int lua_get_avatar_name(lua_State *L) +lua_function(get_avatar_name) { std::string name = gAgentAvatarp->getFullname(); lua_pushstring(L, name.c_str()); return 1; } -int lua_is_avatar_flying(lua_State *L) +lua_function(is_avatar_flying) { lua_pushboolean(L, gAgent.getFlying()); return 1; } -int lua_play_animation(lua_State *L) +lua_function(play_animation) { std::string anim_name = lua_tostring(L,1); @@ -256,7 +296,7 @@ int lua_play_animation(lua_State *L) return 1; } -int lua_env_setting_event(lua_State *L) +lua_function(env_setting_event) { handle_env_setting_event(lua_tostring(L, 1)); return 1; @@ -273,13 +313,13 @@ void handle_notification_dialog(const LLSD ¬ification, const LLSD &response, } } -int lua_show_notification(lua_State *L) +lua_function(show_notification) { std::string notification(lua_tostring(L, 1)); if (lua_type(L, 2) == LUA_TTABLE) { - LLSD args = luatable_to_llsd_string(L, 2); + LLSD args = lua_tollsd(L, 2); std::string response_cb; if (lua_type(L, 3) == LUA_TSTRING) @@ -302,12 +342,12 @@ int lua_show_notification(lua_State *L) return 1; } -int lua_add_menu_item(lua_State *L) +lua_function(add_menu_item) { std::string menu(lua_tostring(L, 1)); if (lua_type(L, 2) == LUA_TTABLE) { - LLSD args = luatable_to_llsd_string(L, 2); + LLSD args = lua_tollsd(L, 2); LLMenuItemCallGL::Params item_params; item_params.name = args["name"]; @@ -328,7 +368,7 @@ int lua_add_menu_item(lua_State *L) return 1; } -int lua_add_menu_separator(lua_State *L) +lua_function(add_menu_separator) { std::string menu(lua_tostring(L, 1)); gMenuBarView->findChildMenuByName(menu, true)->addSeparator(); @@ -336,11 +376,11 @@ int lua_add_menu_separator(lua_State *L) return 1; } -int lua_add_menu(lua_State *L) +lua_function(add_menu) { if (lua_type(L, 1) == LUA_TTABLE) { - LLSD args = luatable_to_llsd_string(L, 1); + LLSD args = lua_tollsd(L, 1); LLMenuGL::Params item_params; item_params.name = args["name"]; @@ -354,12 +394,12 @@ int lua_add_menu(lua_State *L) return 1; } -int lua_add_branch(lua_State *L) +lua_function(add_branch) { std::string menu(lua_tostring(L, 1)); if (lua_type(L, 2) == LUA_TTABLE) { - LLSD args = luatable_to_llsd_string(L, 2); + LLSD args = lua_tollsd(L, 2); LLMenuGL::Params item_params; item_params.name = args["name"]; @@ -373,7 +413,7 @@ int lua_add_branch(lua_State *L) return 1; } -int lua_run_ui_command(lua_State *L) +lua_function(run_ui_command) { int top = lua_gettop(L); std::string func_name; @@ -400,34 +440,7 @@ int lua_run_ui_command(lua_State *L) void initLUA(lua_State *L) { - lua_register(L, "print_warning", lua_printWarning); - - lua_register(L, "avatar_sit", lua_avatar_sit); - lua_register(L, "avatar_stand", lua_avatar_stand); - - lua_register(L, "nearby_chat_send", lua_nearby_chat_send); - lua_register(L, "wear_by_name", lua_wear_by_name); - lua_register(L, "open_floater", lua_open_floater); - lua_register(L, "close_floater", lua_close_floater); - lua_register(L, "close_all_floaters", lua_close_all_floaters); - lua_register(L, "click_child", lua_click_child); - lua_register(L, "open_wearing_tab", lua_open_wearing_tab); - lua_register(L, "snapshot_to_file", lua_snapshot_to_file); - - lua_register(L, "get_avatar_name", lua_get_avatar_name); - lua_register(L, "is_avatar_flying", lua_is_avatar_flying); - lua_register(L, "play_animation", lua_play_animation); - - lua_register(L, "env_setting_event", lua_env_setting_event); - lua_register(L, "set_debug_setting_bool", lua_set_debug_setting_bool); - - lua_register(L, "show_notification", lua_show_notification); - lua_register(L, "add_menu_separator", lua_add_menu_separator); - lua_register(L, "add_menu_item", lua_add_menu_item); - lua_register(L, "add_menu", lua_add_menu); - lua_register(L, "add_branch", lua_add_branch); - - lua_register(L, "run_ui_command", lua_run_ui_command); + LuaFunction::init(L); } void LLLUAmanager::runScriptFile(const std::string &filename, script_finished_fn cb) -- cgit v1.2.3 From f48dd40db06d15e5da7fd3a98324e284a0640b2d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 25 Sep 2023 22:28:58 -0400 Subject: DRTVWR-589: Fix Lua table to LLSD array conversion. The previous implementation assumed that the Lua length function would correctly report the number of entries in a table, and that traversing a table with integer keys would produce them in numeric order. Neither assumption is true. Instead, make a preliminary pass to validate and collect indexes, and to discover the highest integer index. Armed with that, we can construct a contiguous LLSD array of correct size, and populate it with a second pass. Also add Lua-callable post_on_pump(pumpname, datablob) function. --- indra/newview/llluamanager.cpp | 152 ++++++++++++++++++++++++++++++++--------- 1 file changed, 120 insertions(+), 32 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index a9658e77e5..fc53117599 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llappearancemgr.h" #include "llcallbacklist.h" +#include "llevents.h" #include "llfloaterreg.h" #include "llfloaterimnearbychat.h" #include "llfloatersidepanelcontainer.h" @@ -54,6 +55,7 @@ extern "C" #include <cstring> // std::memcpy() #include <map> +#include <set> #include <string_view> #if LL_WINDOWS @@ -66,6 +68,35 @@ void lua_pushllsd(lua_State* L, const LLSD& data); // FIXME extremely hacky way to get to the UI Listener framework. There's almost certainly a cleaner way. extern LLUIListener sUIListener; +/** + * LuaPopper is an RAII struct whose role is to pop some number of entries + * from the Lua stack if the calling function exits early. + */ +struct LuaPopper +{ + LuaPopper(lua_State* L, int count): + mState(L), + mCount(count) + {} + + LuaPopper(const LuaPopper&) = delete; + LuaPopper& operator=(const LuaPopper&) = delete; + + ~LuaPopper() + { + if (mCount) + { + lua_pop(mState, mCount); + } + } + + void disarm() { set(0); } + void set(int count) { mCount = count; } + + lua_State* mState; + int mCount; +}; + /** * LuaFunction is a base class containing a static registry of its static * subclass call() methods. call() is NOT virtual: instead, each subclass @@ -78,8 +109,7 @@ extern LLUIListener sUIListener; class LuaFunction { public: - typedef int (*funcptr)(lua_State* L); - LuaFunction(const std::string_view& name, funcptr function) + LuaFunction(const std::string_view& name, lua_CFunction function) { getRegistry().emplace(name, function); } @@ -93,7 +123,7 @@ public: } private: - using Registry = std::map<std::string, funcptr>; + using Registry = std::map<std::string, lua_CFunction>; static Registry& getRegistry() { // use a function-local static to ensure it's initialized @@ -438,6 +468,15 @@ lua_function(run_ui_command) return 1; } +lua_function(post_on_pump) +{ + std::string pumpname{ lua_tostring(L, -2) }; + LLSD data{ lua_tollsd(L, -1) }; + lua_pop(L, 2); + LLEventPumps::instance().obtain(pumpname).post(data); + return 1; +} + void initLUA(lua_State *L) { LuaFunction::init(L); @@ -537,6 +576,7 @@ LLSD lua_tollsd(lua_State* L, int index) switch (lua_type(L, index)) { case LUA_TNONE: + // Should LUA_TNONE be an error instead of returning isUndefined()? case LUA_TNIL: return {}; @@ -546,15 +586,15 @@ LLSD lua_tollsd(lua_State* L, int index) case LUA_TNUMBER: { // check if integer truncation leaves the number intact - lua_Integer intval{ lua_tointeger(L, index) }; - lua_Number numval{ lua_tonumber(L, index) }; - if (lua_Number(intval) == numval) + int isint; + lua_Integer intval{ lua_tointegerx(L, index, &isint) }; + if (isint) { - return intval; + return LLSD::Integer(intval); } else { - return numval; + return lua_tonumber(L, index); } } @@ -574,11 +614,17 @@ LLSD lua_tollsd(lua_State* L, int index) // either consecutive integer keys starting at 1, which we represent // as an LLSD array (with Lua index 1 at C++ index 0), or will have // all string keys. + // + // In the belief that Lua table traversal skips "holes," that is, it + // doesn't report any key/value pair whose value is nil, we allow a + // table with integer keys >= 1 but with "holes." This produces an + // LLSD array with isUndefined() entries at unspecified keys. There + // would be no other way for a Lua caller to construct an + // isUndefined() LLSD array entry. However, to guard against crazy int + // keys, we forbid gaps larger than a certain size: crazy int keys + // could result in a crazy large contiguous LLSD array. + // // Possible looseness could include: - // - All integer keys >= 1, but with "holes," could produce an LLSD - // array with isUndefined() entries at unspecified keys. We could - // specify a maximum size of allowable gap, and throw an error if a - // gap exceeds that size. // - A mix of integer and string keys could produce an LLSD map in // which the integer keys are converted to string. (Key conversion // must be performed in C++, not Lua, to avoid confusing @@ -609,17 +655,24 @@ LLSD lua_tollsd(lua_State* L, int index) // key is at index -2, value at index -1 // from here until lua_next() returns 0, have to lua_pop(2) if we // return early + LuaPopper popper(L, 2); // Remember the type of the first key auto firstkeytype{ lua_type(L, -2) }; switch (firstkeytype) { case LUA_TNUMBER: { - LLSD result{ LLSD::emptyArray() }; - // right away expand the result array to the size we'll need - result[lua_rawlen(L, index) - 1] = LLSD(); - // track the consecutive indexes we require - LLSD::Integer expected_index{ 0 }; + // First Lua key is a number: try to convert table to LLSD array. + // This is tricky because we don't know in advance the size of the + // array. The Lua reference manual says that lua_rawlen() is the + // same as the length operator '#'; but the length operator states + // that it might stop at any "hole" in the subject table. + // Moreover, the Lua next() function (and presumably lua_next()) + // traverses a table in unspecified order, even for numeric + // indices (emphasized in the doc). + // Make a preliminary pass over the whole table to validate and to + // collect indexes. + std::set<LLSD::Integer> indexes; do { auto arraykeytype{ lua_type(L, -2) }; @@ -627,28 +680,30 @@ LLSD lua_tollsd(lua_State* L, int index) { case LUA_TNUMBER: { - lua_Number actual_index{ lua_tonumber(L, -2) }; - if (actual_index != lua_Number(++expected_index)) + int isnum; + lua_Integer indexint{ lua_tointegerx(L, -2, &isnum) }; + if (! isnum) + { + // key isn't an integer - this doesn't fit our LLSD + // array constraints + return luaL_error(L, "Expected integer array key, got %f instead", + lua_tonumber(L, -2)); + } + if (indexint < 1) { - // key isn't consecutive starting at 1 (may not even be an - // integer) - this doesn't fit our LLSD array constraints - lua_pop(L, 2); - return luaL_error(L, "Expected array key %d, got %f instead", - int(expected_index), actual_index); + return luaL_error(L, "array key %d out of bounds", int(indexint)); } - result.append(lua_tollsd(L, -1)); + indexes.insert(LLSD::Integer(indexint)); break; } case LUA_TSTRING: // break out strings specially to report the value - lua_pop(L, 2); return luaL_error(L, "Cannot convert string array key '%s' to LLSD", lua_tostring(L, -2)); default: - lua_pop(L, 2); return luaL_error(L, "Cannot convert %s array key to LLSD", lua_typename(L, arraykeytype)); } @@ -656,18 +711,50 @@ LLSD lua_tollsd(lua_State* L, int index) // remove value, keep key for next iteration lua_pop(L, 1); } while (lua_next(L, index) != 0); + popper.disarm(); + // Table keys are all integers: are they reasonable integers? + // Arbitrary max: may bite us, but more likely to protect us + size_t array_max{ 10000 }; + if (indexes.size() > array_max) + { + return luaL_error(L, "Conversion from Lua to LLSD array limited to %d entries", + int(array_max)); + } + // We know the smallest index is >= 1. Check the largest. We also + // know the set is NOT empty, else we wouldn't have gotten here. + LLSD::Integer highindex = *indexes.rbegin(); + if ((highindex - LLSD::Integer(indexes.size())) > 100) + { + // Looks like we've gone beyond intentional array gaps into + // crazy index territory. + return luaL_error(L, "Gaps in Lua table too large for conversion to LLSD array"); + } + // right away expand the result array to the size we'll need + LLSD result{ LLSD::emptyArray() }; + result[highindex - 1] = LLSD(); + // Traverse the table again, and this time populate result array. + lua_pushnil(L); // first key + while (lua_next(L, index)) + { + // key at index -2, value at index -1 + // We've already validated lua_tointegerx() for each key. + // Don't forget to subtract 1 from Lua key for LLSD subscript! + result[LLSD::Integer(lua_tointeger(L, -2)) - 1] = lua_tollsd(L, -1); + // remove value, keep key for next iteration + lua_pop(L, 1); + } return result; } case LUA_TSTRING: { + // First Lua key is a string: try to convert table to LLSD map LLSD result{ LLSD::emptyMap() }; do { auto mapkeytype{ lua_type(L, -2) }; if (mapkeytype != LUA_TSTRING) { - lua_pop(L, 2); return luaL_error(L, "Cannot convert %s map key to LLSD", lua_typename(L, mapkeytype)); } @@ -676,11 +763,12 @@ LLSD lua_tollsd(lua_State* L, int index) // remove value, keep key for next iteration lua_pop(L, 1); } while (lua_next(L, index) != 0); + popper.disarm(); return result; } default: - lua_pop(L, 2); + // First Lua key isn't number or string: sorry return luaL_error(L, "Cannot convert %s table key to LLSD", lua_typename(L, firstkeytype)); } @@ -690,8 +778,7 @@ LLSD lua_tollsd(lua_State* L, int index) // Other Lua entities (e.g. function, C function, light userdata, // thread, userdata) are not convertible to LLSD, indicating a coding // error in the caller. - return luaL_error(L, "Cannot convert type %s to LLSD", - lua_typename(L, lua_type(L, index))); + return luaL_error(L, "Cannot convert type %s to LLSD", luaL_typename(L, index)); } } @@ -720,7 +807,8 @@ void lua_pushllsd(lua_State* L, const LLSD& data) case LLSD::TypeBinary: { auto binary{ data.asBinary() }; - std::memcpy(lua_newuserdata(L, binary.size()), binary.data(), binary.size()); + std::memcpy(lua_newuserdata(L, binary.size()), + binary.data(), binary.size()); break; } -- cgit v1.2.3 From 0d5f5f6380a7087f86c5fcd7c761ea5a175c3f17 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 26 Sep 2023 11:40:56 -0400 Subject: DRTVWR-589: Collect int table keys in vector<int>, not set<int>. Given that we at least have a possibility of determining the length of a Lua table in advance, we might be able to populate a vector of keys with a single initial allocation. Even if Lua reports the length incorrectly, vector::push_back() is one of the bread-and-butter operations of the library, optimized to the extent possible. Inserting elements into a set seems more likely to incur allocations. Of course, we must then sort() the vector to determine its largest key value. Also document the requirement that we use a Lua runtime compiled for C++, that is, compiled to raise errors by C++ exceptions rather than by longjmp(). We rely on temporary stack objects being properly destroyed even if errors are raised. Conventionally, with lua_tomumble(L, index), 'index' refers to the stack index of the Lua object being converted to C++. For a Lua table, talk about table keys rather than table indexes to avoid confusing the maintainer. --- indra/newview/llluamanager.cpp | 70 +++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index fc53117599..f94b26f32e 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -53,10 +53,11 @@ extern "C" #include "lua/lualib.h" } +#include <algorithm> #include <cstring> // std::memcpy() #include <map> -#include <set> #include <string_view> +#include <vector> #if LL_WINDOWS #pragma comment(lib, "liblua54.a") @@ -477,6 +478,17 @@ lua_function(post_on_pump) return 1; } +lua_function(listen_events) +{ + if (! lua_isfunction(L, -1)) + { + return luaL_typerror(L, 1, "function"); + } + // return the distinct LLEventPump name so Lua code can post that with a + // request as the reply pump + return 1; +} + void initLUA(lua_State *L) { LuaFunction::init(L); @@ -571,6 +583,16 @@ std::string lua_tostdstring(lua_State* L, int index) // This function assumes that a Lua caller is fully aware that they're trying // to call a viewer function. In other words, the caller must specifically // construct Lua data convertible to LLSD. +// +// For proper error handling, we REQUIRE that the Lua runtime be compiled as +// C++ so errors are raised as C++ exceptions rather than as longjmp() calls: +// http://www.lua.org/manual/5.4/manual.html#4.4 +// "Internally, Lua uses the C longjmp facility to handle errors. (Lua will +// use exceptions if you compile it as C++; search for LUAI_THROW in the +// source code for details.)" +// Some blocks within this function construct temporary C++ objects in the +// expectation that these objects will be properly destroyed even if code +// reached by that block raises a Lua error. LLSD lua_tollsd(lua_State* L, int index) { switch (lua_type(L, index)) @@ -612,7 +634,7 @@ LLSD lua_tollsd(lua_State* L, int index) { // A Lua table correctly constructed to convert to LLSD will have // either consecutive integer keys starting at 1, which we represent - // as an LLSD array (with Lua index 1 at C++ index 0), or will have + // as an LLSD array (with Lua key 1 at C++ index 0), or will have // all string keys. // // In the belief that Lua table traversal skips "holes," that is, it @@ -652,7 +674,7 @@ LLSD lua_tollsd(lua_State* L, int index) // which can be consumed as either return {}; } - // key is at index -2, value at index -1 + // key is at stack index -2, value at index -1 // from here until lua_next() returns 0, have to lua_pop(2) if we // return early LuaPopper popper(L, 2); @@ -668,11 +690,16 @@ LLSD lua_tollsd(lua_State* L, int index) // same as the length operator '#'; but the length operator states // that it might stop at any "hole" in the subject table. // Moreover, the Lua next() function (and presumably lua_next()) - // traverses a table in unspecified order, even for numeric - // indices (emphasized in the doc). + // traverses a table in unspecified order, even for numeric keys + // (emphasized in the doc). // Make a preliminary pass over the whole table to validate and to - // collect indexes. - std::set<LLSD::Integer> indexes; + // collect keys. + std::vector<LLSD::Integer> keys; + // Try to determine the length of the table. If the length + // operator is truthful, avoid allocations while we grow the keys + // vector. Even if it's not, we can still grow the vector, albeit + // a little less efficiently. + keys.reserve(luaL_len(L, index)); do { auto arraykeytype{ lua_type(L, -2) }; @@ -680,21 +707,21 @@ LLSD lua_tollsd(lua_State* L, int index) { case LUA_TNUMBER: { - int isnum; - lua_Integer indexint{ lua_tointegerx(L, -2, &isnum) }; - if (! isnum) + int isint; + lua_Integer intkey{ lua_tointegerx(L, -2, &isint) }; + if (! isint) { // key isn't an integer - this doesn't fit our LLSD // array constraints return luaL_error(L, "Expected integer array key, got %f instead", lua_tonumber(L, -2)); } - if (indexint < 1) + if (intkey < 1) { - return luaL_error(L, "array key %d out of bounds", int(indexint)); + return luaL_error(L, "array key %d out of bounds", int(intkey)); } - indexes.insert(LLSD::Integer(indexint)); + keys.push_back(LLSD::Integer(intkey)); break; } @@ -715,28 +742,29 @@ LLSD lua_tollsd(lua_State* L, int index) // Table keys are all integers: are they reasonable integers? // Arbitrary max: may bite us, but more likely to protect us size_t array_max{ 10000 }; - if (indexes.size() > array_max) + if (keys.size() > array_max) { return luaL_error(L, "Conversion from Lua to LLSD array limited to %d entries", int(array_max)); } - // We know the smallest index is >= 1. Check the largest. We also - // know the set is NOT empty, else we wouldn't have gotten here. - LLSD::Integer highindex = *indexes.rbegin(); - if ((highindex - LLSD::Integer(indexes.size())) > 100) + // We know the smallest key is >= 1. Check the largest. We also + // know the vector is NOT empty, else we wouldn't have gotten here. + std::sort(keys.begin(), keys.end()); + LLSD::Integer highkey = *keys.rbegin(); + if ((highkey - LLSD::Integer(keys.size())) > 100) { // Looks like we've gone beyond intentional array gaps into - // crazy index territory. + // crazy key territory. return luaL_error(L, "Gaps in Lua table too large for conversion to LLSD array"); } // right away expand the result array to the size we'll need LLSD result{ LLSD::emptyArray() }; - result[highindex - 1] = LLSD(); + result[highkey - 1] = LLSD(); // Traverse the table again, and this time populate result array. lua_pushnil(L); // first key while (lua_next(L, index)) { - // key at index -2, value at index -1 + // key at stack index -2, value at index -1 // We've already validated lua_tointegerx() for each key. // Don't forget to subtract 1 from Lua key for LLSD subscript! result[LLSD::Integer(lua_tointeger(L, -2)) - 1] = lua_tollsd(L, -1); -- cgit v1.2.3 From da8a79f2a2d4a3b35762fbc77f2b69852db3af5d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 26 Sep 2023 14:53:20 -0400 Subject: DRTVWR-589: Fix typo due to old documentation. The function formerly known as luaL_typerror() is now luaL_typeerror(). --- indra/newview/llluamanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index f94b26f32e..c783b1fab6 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -482,7 +482,7 @@ lua_function(listen_events) { if (! lua_isfunction(L, -1)) { - return luaL_typerror(L, 1, "function"); + return luaL_typeerror(L, 1, "function"); } // return the distinct LLEventPump name so Lua code can post that with a // request as the reply pump -- cgit v1.2.3 From 354585d6ad1e7cf5caaa6a35740966e238d14989 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Sep 2023 12:41:45 -0400 Subject: DRTVWR-589: Add Lua-callable listen_events() function. Add LuaListener, based on LLLeap. LuaListener has an int key so the second and subsequent calls to listen_events() can find a previously-created one. LuaListener listens on its LLEventPump and arranges to call the specified Lua callback with any incoming event. It also instantiates an LLLeapListener. listen_events() locates the main thread for its state: we only want to call callbacks on the Lua chunk's main thread, not on a (possibly suspended) coroutine. It finds or creates a LuaListener and stashes it in the main thread's registry, along with the passed Lua callback function. Finally it returns the names of the LuaListener's reply pump and the LLLeapListener's command pump. Add LuaState RAII class to manage the lifespan of each lua_State we create. This encapsulates much of the boilerplate common to runScriptFile() and runScriptLine(). In addition, LuaState's destructor checks for a LuaListener key and, if found, destroys the referenced LuaListener. LuaState's constructor requires a description to clarify log messages. Move the checkLua() free function to a member of LuaState. This allows capturing an error message to pass to the C++ completion callback, if any. Use LuaState in runScriptFile() and runScriptLine(), synthesizing a suitable description in each case. Add print_debug() and print_info() logging calls, analogous to print_warning(). Add luaL_where() prefix to every such message. Add lua_pushstdstring(), like lua_tostdstring(): convenience for working with the pointer and length used by lua_pushlstring() and lua_tolstring(). Clean up return values of lua_functions. A lua_CFunction returns the number of return values it has pushed, so any 'void' lua_CFunction should pop its arguments and return 0. --- indra/newview/llluamanager.cpp | 372 +++++++++++++++++++++++++++++++++-------- 1 file changed, 304 insertions(+), 68 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c783b1fab6..7838e57216 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -31,11 +31,15 @@ #include "llagent.h" #include "llappearancemgr.h" #include "llcallbacklist.h" +#include "llerror.h" #include "llevents.h" #include "llfloaterreg.h" #include "llfloaterimnearbychat.h" #include "llfloatersidepanelcontainer.h" +#include "llinstancetracker.h" +#include "llleaplistener.h" #include "llnotificationsutil.h" +#include "lluuid.h" #include "llvoavatarself.h" #include "llviewermenu.h" #include "llviewermenufile.h" @@ -43,6 +47,7 @@ #include "lluilistener.h" #include "llanimationstates.h" #include "llinventoryfunctions.h" +#include "stringize.h" #include <boost/algorithm/string/replace.hpp> @@ -54,8 +59,10 @@ extern "C" } #include <algorithm> +#include <cstdlib> // std::rand() #include <cstring> // std::memcpy() #include <map> +#include <memory> // std::unique_ptr #include <string_view> #include <vector> @@ -63,12 +70,106 @@ extern "C" #pragma comment(lib, "liblua54.a") #endif +std::string lua_tostdstring(lua_State* L, int index); +void lua_pushstdstring(lua_State* L, const std::string& str); LLSD lua_tollsd(lua_State* L, int index); void lua_pushllsd(lua_State* L, const LLSD& data); // FIXME extremely hacky way to get to the UI Listener framework. There's almost certainly a cleaner way. extern LLUIListener sUIListener; +/** + * LuaListener is based on LLLeap. It serves an analogous function. + * + * Each LuaListener instance has an int key, generated randomly to + * inconvenience malicious Lua scripts wanting to mess with others. The idea + * is that a given lua_State stores in its Registry: + * - "event.listener": the int key of the corresponding LuaListener, if any + * - "event.function": the Lua function to be called with incoming events + * The original thought was that LuaListener would itself store the Lua + * function -- but surprisingly, there is no C/C++ type in the API that stores + * a Lua function. + * + * (We considered storing in "event.listener" the LuaListener pointer itself + * as a light userdata, but the problem would be if Lua code overwrote that. + * We want to prevent any Lua script from crashing the viewer, intentionally + * or otherwise. Safer to use a key lookup.) + * + * Like LLLeap, each LuaListener instance also has an associated + * LLLeapListener to respond to LLEventPump management commands. + */ +class LuaListener: public LLInstanceTracker<LuaListener, int> +{ + using super = LLInstanceTracker<LuaListener, int>; +public: + LuaListener(lua_State* L): + super(getUniqueKey()), + mState(L), + mReplyPump(LLUUID::generateNewID().asString()), + mListener(new LLLeapListener(std::bind(&LuaListener::connect, this, _1, _2))) + { + mReplyConnection = connect(mReplyPump, "LuaListener"); + } + + std::string getReplyName() const { return mReplyPump.getName(); } + std::string getCommandName() const { return mListener->getPumpName(); } + +private: + static int getUniqueKey() + { + // Find a random key that does NOT already correspond to a LuaListener + // instance. Passing a duplicate key to LLInstanceTracker would do Bad + // Things. + int key; + do + { + key = std::rand(); + } while (LuaListener::getInstance(key)); + // This is theoretically racy, if we were instantiating new + // LuaListeners on multiple threads. Don't. + return key; + } + + LLBoundListener connect(LLEventPump& pump, const std::string_view& listener) + { + return pump.listen(listener, + std::bind(&LuaListener::call_lua, mState, pump.getName(), _1)); + } + + static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data) + { + // push the registered Lua callback function stored in our registry as + // "event.function" + lua_getfield(L, LUA_REGISTRYINDEX, "event.function"); + llassert(lua_isfunction(L, -1)); + // pass pump name + lua_pushstdstring(L, pump); + // then the data blob + lua_pushllsd(L, data); + // call the registered Lua listener function; allow it to return bool; + // no message handler + auto status = lua_pcall(L, 2, 1, 0); + bool result{ false }; + if (status != LUA_OK) + { + LL_WARNS("Lua") << "Error in listen_events() callback: " + << lua_tostdstring(L, -1) << LL_ENDL; + } + else + { + result = lua_toboolean(L, -1); + } + // discard either the error message or the bool return value + lua_pop(L, 1); + return result; + } + + lua_State* mState; + LLEventStream mReplyPump; + LLTempBoundListener mReplyConnection; + std::unique_ptr<LLLeapListener> mListener; +}; + /** * LuaPopper is an RAII struct whose role is to pop some number of entries * from the Lua stack if the calling function exits early. @@ -150,37 +251,41 @@ static struct name##_ : public LuaFunction \ static int call(lua_State* L); \ } name; \ int name##_::call(lua_State* L) +// { +// ... supply method body here, referencing 'L' ... +// } -lua_function(print_warning) +lua_function(print_debug) { - std::string msg(lua_tostring(L, 1)); - - LL_WARNS() << msg << LL_ENDL; - return 1; + LL_DEBUGS("Lua") << luaL_where(L, 1) << ": " << lua_tostring(L, 1) << LL_ENDL; + lua_pop(L, 1); + return 0; } -bool checkLua(lua_State *L, int r, std::string &error_msg) +lua_function(print_info) { - if (r != LUA_OK) - { - error_msg = lua_tostring(L, -1); + LL_INFOS("Lua") << luaL_where(L, 1) << ": " << lua_tostring(L, 1) << LL_ENDL; + lua_pop(L, 1); + return 0; +} - LL_WARNS() << error_msg << LL_ENDL; - return false; - } - return true; +lua_function(print_warning) +{ + LL_WARNS("Lua") << luaL_where(L, 1) << ": " << lua_tostring(L, 1) << LL_ENDL; + lua_pop(L, 1); + return 0; } lua_function(avatar_sit) { gAgent.sitDown(); - return 1; + return 0; } lua_function(avatar_stand) { gAgent.standUp(); - return 1; + return 0; } lua_function(nearby_chat_send) @@ -189,7 +294,8 @@ lua_function(nearby_chat_send) LLFloaterIMNearbyChat *nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); nearby_chat->sendChatFromViewer(msg, CHAT_TYPE_NORMAL, gSavedSettings.getBOOL("PlayChatAnim")); - return 1; + lua_pop(L, 1); + return 0; } lua_function(wear_by_name) @@ -197,7 +303,8 @@ lua_function(wear_by_name) std::string folder_name(lua_tostring(L, 1)); LLAppearanceMgr::instance().wearOutfitByName(folder_name); - return 1; + lua_pop(L, 1); + return 0; } lua_function(open_floater) @@ -211,7 +318,8 @@ lua_function(open_floater) } LLFloaterReg::showInstance(floater_name, key); - return 1; + lua_pop(L, 1); + return 0; } lua_function(close_floater) @@ -225,13 +333,14 @@ lua_function(close_floater) } LLFloaterReg::hideInstance(floater_name, key); - return 1; + lua_pop(L, 1); + return 0; } lua_function(close_all_floaters) { close_all_windows(); - return 1; + return 0; } lua_function(click_child) @@ -243,7 +352,8 @@ lua_function(click_child) LLUICtrl *child = floater->getChild<LLUICtrl>(child_name, true); child->onCommit(); - return 1; + lua_pop(L, 2); + return 0; } lua_function(snapshot_to_file) @@ -263,13 +373,14 @@ lua_function(snapshot_to_file) LLSnapshotModel::SNAPSHOT_FORMAT_PNG); }); - return 1; + lua_pop(L, 1); + return 0; } lua_function(open_wearing_tab) { LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "now_wearing")); - return 1; + return 0; } lua_function(set_debug_setting_bool) @@ -278,7 +389,8 @@ lua_function(set_debug_setting_bool) bool value(lua_toboolean(L, 2)); gSavedSettings.setBOOL(setting_name, value); - return 1; + lua_pop(L, 2); + return 0; } lua_function(get_avatar_name) @@ -296,6 +408,9 @@ lua_function(is_avatar_flying) lua_function(play_animation) { + // on exit, pop all passed arguments, so always return 0 + LuaPopper popper(L, lua_gettop(L)); + std::string anim_name = lua_tostring(L,1); EAnimRequest req = ANIM_REQUEST_START; @@ -319,18 +434,19 @@ lua_function(play_animation) LLUUID anim_id = item->getAssetUUID(); LL_INFOS() << "Playing animation " << anim_id << LL_ENDL; gAgent.sendAnimationRequest(anim_id, req); - return 1; + return 0; } } LL_WARNS() << "No animation found for name " << anim_name << LL_ENDL; - return 1; + return 0; } lua_function(env_setting_event) { handle_env_setting_event(lua_tostring(L, 1)); - return 1; + lua_pop(L, 1); + return 0; } void handle_notification_dialog(const LLSD ¬ification, const LLSD &response, lua_State *L, std::string response_cb) @@ -370,7 +486,8 @@ lua_function(show_notification) LLNotificationsUtil::add(notification); } - return 1; + lua_pop(L, lua_gettop(L)); + return 0; } lua_function(add_menu_item) @@ -396,7 +513,8 @@ lua_function(add_menu_item) gMenuBarView->findChildMenuByName(menu, true)->append(menu_item); } - return 1; + lua_pop(L, lua_gettop(L)); + return 0; } lua_function(add_menu_separator) @@ -404,7 +522,8 @@ lua_function(add_menu_separator) std::string menu(lua_tostring(L, 1)); gMenuBarView->findChildMenuByName(menu, true)->addSeparator(); - return 1; + lua_pop(L, 1); + return 0; } lua_function(add_menu) @@ -422,7 +541,8 @@ lua_function(add_menu) gMenuBarView->appendMenu(menu); } - return 1; + lua_pop(L, lua_gettop(L)); + return 0; } lua_function(add_branch) @@ -441,7 +561,8 @@ lua_function(add_branch) gMenuBarView->findChildMenuByName(menu, true)->appendMenu(branch); } - return 1; + lua_pop(L, lua_gettop(L)); + return 0; } lua_function(run_ui_command) @@ -466,7 +587,8 @@ lua_function(run_ui_command) } sUIListener.call(event); - return 1; + lua_pop(L, top); + return 0; } lua_function(post_on_pump) @@ -475,18 +597,69 @@ lua_function(post_on_pump) LLSD data{ lua_tollsd(L, -1) }; lua_pop(L, 2); LLEventPumps::instance().obtain(pumpname).post(data); - return 1; + return 0; } lua_function(listen_events) { - if (! lua_isfunction(L, -1)) + if (! lua_isfunction(L, 1)) { return luaL_typeerror(L, 1, "function"); } - // return the distinct LLEventPump name so Lua code can post that with a - // request as the reply pump - return 1; + + // Get the lua_State* for the main thread of this state, in case we were + // called from a coroutine thread. We're going to make callbacks into Lua + // code, and we want to do it on the main thread rather than a (possibly + // suspended) coroutine thread. + // Registry table is at pseudo-index LUA_REGISTRYINDEX + // Main thread is at registry key LUA_RIDX_MAINTHREAD + auto regtype{ lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD) }; + // Not finding the main thread at the documented place isn't a user error, + // it's a Problem + llassert(regtype == LUA_TTHREAD); + lua_State* mainthread{ lua_tothread(L, -1) }; + // pop the main thread + lua_pop(L, 1); + + LuaListener::ptr_t listener; + // Does the main thread already have a LuaListener stored in the registry? + // That is, has this Lua chunk already called listen_events()? + auto keytype{ lua_getfield(mainthread, LUA_REGISTRYINDEX, "event.listener") }; + llassert(keytype == LUA_TNIL || keytype == LUA_TINTEGER); + if (keytype == LUA_TINTEGER) + { + // We do already have a LuaListener. Retrieve it. + listener = LuaListener::getInstance(lua_tointeger(mainthread, -1)); + // pop the int "event.listener" key + lua_pop(mainthread, 1); + // Nobody should have destroyed this LuaListener instance! + llassert(listener); + } + else + { + // pop the nil "event.listener" key + lua_pop(mainthread, 1); + // instantiate a new LuaListener, binding the mainthread state + listener.reset(new LuaListener(mainthread)); + // set its key in the field where we'll look for it later + lua_pushinteger(mainthread, listener->getKey()); + lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.listener"); + } + + // Now that we've found or created our LuaListener, store the passed Lua + // function as the callback. Beware: our caller passed the function on L's + // stack, but we want to store it on the mainthread registry. + if (L != mainthread) + { + // push 1 value (the Lua function) from L's stack to mainthread's + lua_xmove(L, mainthread, 1) + } + lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.function"); + + // return the reply pump name and the command pump name on caller's lua_State + lua_pushstdstring(L, listener->getReplyPump()); + lua_pushstdstring(L, listener->getCommandPump()); + return 2; } void initLUA(lua_State *L) @@ -494,61 +667,119 @@ void initLUA(lua_State *L) LuaFunction::init(L); } -void LLLUAmanager::runScriptFile(const std::string &filename, script_finished_fn cb) +/** + * RAII class to manage the lifespan of a lua_State + */ +class LuaState +{ +public: + LuaState(const std::string_view& desc, script_finished_fn cb): + mDesc(desc), + mCallback(cb), + mState(luaL_newstate()) + { + luaL_openlibs(mState); + initLUA(mState); + } + + LuaState(const LuaState&) = delete; + LuaState& operator=(const LuaState&) = delete; + + ~LuaState() + { + // Did somebody call listen_events() on this LuaState? + // That is, is there a LuaListener key in its registry? + auto keytype{ lua_getfield(mState, LUA_REGISTRYINDEX, "event.listener") }; + if (keytype == LUA_TINTEGER) + { + // We do have a LuaListener. Retrieve it. + auto listener{ LuaListener::getInstance(lua_tointeger(mState, -1)) }; + // pop the int "event.listener" key + lua_pop(mState, 1); + // destroy this LuaListener instance + if (listener) + { + auto lptr{ listener.get() }; + listener.reset(); + delete lptr; + } + } + + lua_close(mState); + + if (mCallback) + { + // mError potentially set by previous checkLua() call(s) + mCallback(mError); + } + } + + bool checkLua(int r) + { + if (r != LUA_OK) + { + mError = lua_tostring(mState, -1); + lua_pop(mState, 1); + + LL_WARNS() << mDesc << ": " << mError << LL_ENDL; + return false; + } + return true; + } + + operator lua_State*() const { return mState; } + +private: + std::string mDesc; + script_finished_fn mCallback; + lua_State* mState; + std::string mError; +}; + +void LLLUAmanager::runScriptFile(const std::string_view &filename, script_finished_fn cb) { LLCoros::instance().launch("LUAScriptFileCoro", [filename, cb]() { - lua_State *L = luaL_newstate(); - luaL_openlibs(L); - initLUA(L); + LuaState L(stringize("runScriptFile('", filename, "')"), cb); auto LUA_sleep_func = [](lua_State *L) { F32 seconds = lua_tonumber(L, -1); + lua_pop(L, 1); llcoro::suspendUntilTimeout(seconds); return 0; }; lua_register(L, "sleep", LUA_sleep_func); - std::string lua_error; - if (checkLua(L, luaL_dofile(L, filename.c_str()), lua_error)) + if (L.checkLua(luaL_dofile(L, filename.c_str()))) { lua_getglobal(L, "call_once_func"); if (lua_isfunction(L, -1)) { - if (checkLua(L, lua_pcall(L, 0, 0, 0), lua_error)) {} + // call call_once_func(), setting internal error message if + // error + L.checkLua(lua_pcall(L, 0, 0, 0)); } } - lua_close(L); - - if (cb) - { - cb(lua_error); - } }); } -void LLLUAmanager::runScriptLine(const std::string &cmd, script_finished_fn cb) +void LLLUAmanager::runScriptLine(const std::string_view &cmd, script_finished_fn cb) { LLCoros::instance().launch("LUAScriptFileCoro", [cmd, cb]() { - lua_State *L = luaL_newstate(); - luaL_openlibs(L); - initLUA(L); - int r = luaL_dostring(L, cmd.c_str()); - - std::string lua_error; - if (r != LUA_OK) - { - lua_error = lua_tostring(L, -1); - } - lua_close(L); - - if (cb) - { - cb(lua_error); - } + // find a suitable abbreviation for the cmd string + std::string_view shortcmd{ cmd }; + const size_t shortlen = 40; + std::string::size_type eol = shortcmd.find_first_of("\r\n"); + if (eol != std::string::npos) + shortcmd = shortcmd.substr(0, eol); + if (shortcmd.length() > shortlen) + shortcmd = shortcmd.substr(0, shortlen) + "..."; + + LuaState L(stringize("runScriptLine('", shortcmd, "')"), cb); + L.checkLua(luaL_dostring(L, cmd.c_str())); }); } @@ -578,6 +809,11 @@ std::string lua_tostdstring(lua_State* L, int index) return { strval, len }; } +void lua_pushstdstring(lua_State* L, const std::string& str) +{ + lua_pushlstring(L, str.c_str(), str.length()); +} + // By analogy with existing lua_tomumble() functions, return an LLSD object // corresponding to the Lua object at stack index 'index' in state L. // This function assumes that a Lua caller is fully aware that they're trying -- cgit v1.2.3 From dbf9898aa15db9ec9f1ee12627afbc0565301235 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Sep 2023 15:41:12 -0400 Subject: DRTVWR-589: Fix compile errors in 354585d. --- indra/newview/llluamanager.cpp | 53 ++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 23 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 7838e57216..d7893ce863 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -130,7 +130,7 @@ private: return key; } - LLBoundListener connect(LLEventPump& pump, const std::string_view& listener) + LLBoundListener connect(LLEventPump& pump, const std::string& listener) { return pump.listen(listener, std::bind(&LuaListener::call_lua, mState, pump.getName(), _1)); @@ -257,22 +257,25 @@ int name##_::call(lua_State* L) lua_function(print_debug) { - LL_DEBUGS("Lua") << luaL_where(L, 1) << ": " << lua_tostring(L, 1) << LL_ENDL; - lua_pop(L, 1); + luaL_where(L, 1); + LL_DEBUGS("Lua") << lua_tostring(L, 2) << ": " << lua_tostring(L, 1) << LL_ENDL; + lua_pop(L, 2); return 0; } lua_function(print_info) { - LL_INFOS("Lua") << luaL_where(L, 1) << ": " << lua_tostring(L, 1) << LL_ENDL; - lua_pop(L, 1); + luaL_where(L, 1); + LL_INFOS("Lua") << lua_tostring(L, 2) << ": " << lua_tostring(L, 1) << LL_ENDL; + lua_pop(L, 2); return 0; } lua_function(print_warning) { - LL_WARNS("Lua") << luaL_where(L, 1) << ": " << lua_tostring(L, 1) << LL_ENDL; - lua_pop(L, 1); + luaL_where(L, 1); + LL_WARNS("Lua") << lua_tostring(L, 2) << ": " << lua_tostring(L, 1) << LL_ENDL; + lua_pop(L, 2); return 0; } @@ -625,15 +628,16 @@ lua_function(listen_events) // Does the main thread already have a LuaListener stored in the registry? // That is, has this Lua chunk already called listen_events()? auto keytype{ lua_getfield(mainthread, LUA_REGISTRYINDEX, "event.listener") }; - llassert(keytype == LUA_TNIL || keytype == LUA_TINTEGER); - if (keytype == LUA_TINTEGER) + llassert(keytype == LUA_TNIL || keytype == LUA_TNUMBER); + if (keytype == LUA_TNUMBER) { // We do already have a LuaListener. Retrieve it. - listener = LuaListener::getInstance(lua_tointeger(mainthread, -1)); + int isint; + listener = LuaListener::getInstance(lua_tointegerx(mainthread, -1, &isint)); // pop the int "event.listener" key lua_pop(mainthread, 1); // Nobody should have destroyed this LuaListener instance! - llassert(listener); + llassert(isint && listener); } else { @@ -652,13 +656,13 @@ lua_function(listen_events) if (L != mainthread) { // push 1 value (the Lua function) from L's stack to mainthread's - lua_xmove(L, mainthread, 1) + lua_xmove(L, mainthread, 1); } lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.function"); // return the reply pump name and the command pump name on caller's lua_State - lua_pushstdstring(L, listener->getReplyPump()); - lua_pushstdstring(L, listener->getCommandPump()); + lua_pushstdstring(L, listener->getReplyName()); + lua_pushstdstring(L, listener->getCommandName()); return 2; } @@ -673,7 +677,7 @@ void initLUA(lua_State *L) class LuaState { public: - LuaState(const std::string_view& desc, script_finished_fn cb): + LuaState(const std::string_view& desc, LLLUAmanager::script_finished_fn cb): mDesc(desc), mCallback(cb), mState(luaL_newstate()) @@ -690,14 +694,17 @@ public: // Did somebody call listen_events() on this LuaState? // That is, is there a LuaListener key in its registry? auto keytype{ lua_getfield(mState, LUA_REGISTRYINDEX, "event.listener") }; - if (keytype == LUA_TINTEGER) + if (keytype == LUA_TNUMBER) { // We do have a LuaListener. Retrieve it. - auto listener{ LuaListener::getInstance(lua_tointeger(mState, -1)) }; + int isint; + auto listener{ LuaListener::getInstance(lua_tointegerx(mState, -1, &isint)) }; // pop the int "event.listener" key lua_pop(mState, 1); - // destroy this LuaListener instance - if (listener) + // if we got a LuaListener instance, destroy it + // (if (! isint), lua_tointegerx() returned 0, but key 0 might + // validly designate someone ELSE's LuaListener) + if (isint && listener) { auto lptr{ listener.get() }; listener.reset(); @@ -731,12 +738,12 @@ public: private: std::string mDesc; - script_finished_fn mCallback; + LLLUAmanager::script_finished_fn mCallback; lua_State* mState; std::string mError; }; -void LLLUAmanager::runScriptFile(const std::string_view &filename, script_finished_fn cb) +void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb) { LLCoros::instance().launch("LUAScriptFileCoro", [filename, cb]() { @@ -765,7 +772,7 @@ void LLLUAmanager::runScriptFile(const std::string_view &filename, script_finish }); } -void LLLUAmanager::runScriptLine(const std::string_view &cmd, script_finished_fn cb) +void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) { LLCoros::instance().launch("LUAScriptFileCoro", [cmd, cb]() { @@ -776,7 +783,7 @@ void LLLUAmanager::runScriptLine(const std::string_view &cmd, script_finished_fn if (eol != std::string::npos) shortcmd = shortcmd.substr(0, eol); if (shortcmd.length() > shortlen) - shortcmd = shortcmd.substr(0, shortlen) + "..."; + shortcmd = stringize(shortcmd.substr(0, shortlen), "..."); LuaState L(stringize("runScriptLine('", shortcmd, "')"), cb); L.checkLua(luaL_dostring(L, cmd.c_str())); -- cgit v1.2.3 From 70d8316da87b01a13781c829fee08e61931b1e37 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Sep 2023 16:21:32 -0400 Subject: DRTVWR-589: Use std::placeholders::_1, etc., for std::bind() --- indra/newview/llluamanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index d7893ce863..26e29a4ae1 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -106,7 +106,8 @@ public: super(getUniqueKey()), mState(L), mReplyPump(LLUUID::generateNewID().asString()), - mListener(new LLLeapListener(std::bind(&LuaListener::connect, this, _1, _2))) + mListener(new LLLeapListener(std::bind(&LuaListener::connect, this, + std::placeholders::_1, std::placeholders::_2))) { mReplyConnection = connect(mReplyPump, "LuaListener"); } @@ -133,7 +134,8 @@ private: LLBoundListener connect(LLEventPump& pump, const std::string& listener) { return pump.listen(listener, - std::bind(&LuaListener::call_lua, mState, pump.getName(), _1)); + std::bind(&LuaListener::call_lua, mState, pump.getName(), + std::placeholders::_1)); } static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data) -- cgit v1.2.3 From 6a3bb72620ccefe316e9c011df5191f7a16f358c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Sep 2023 18:13:16 -0400 Subject: DRTVWR-589: Always check regtype to avoid unref error --- indra/newview/llluamanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 26e29a4ae1..c1e111f0ac 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -621,7 +621,7 @@ lua_function(listen_events) auto regtype{ lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD) }; // Not finding the main thread at the documented place isn't a user error, // it's a Problem - llassert(regtype == LUA_TTHREAD); + llassert_always(regtype == LUA_TTHREAD); lua_State* mainthread{ lua_tothread(L, -1) }; // pop the main thread lua_pop(L, 1); -- cgit v1.2.3 From 1564146fe801d9827cf21440058060a4a1c2cc63 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 28 Sep 2023 12:56:25 +0300 Subject: DRTVWR-589 - support for rezing prims --- indra/newview/llluamanager.cpp | 23 +++++++++++++++++++++++ indra/newview/lltoolplacer.cpp | 8 +++++++- indra/newview/lltoolplacer.h | 8 ++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c1e111f0ac..bdf8fc0278 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -48,6 +48,7 @@ #include "llanimationstates.h" #include "llinventoryfunctions.h" #include "stringize.h" +#include "lltoolplacer.h" #include <boost/algorithm/string/replace.hpp> @@ -570,6 +571,28 @@ lua_function(add_branch) return 0; } +// rez_prim({x, y}, prim_type) +// avatar is the reference point +lua_function(rez_prim) +{ + lua_rawgeti(L, 1, 1); + F32 x = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 1, 2); + F32 y = lua_tonumber(L, -1); + lua_pop(L, 1); + + S32 type(lua_tonumber(L, 2)); // primitive shapes 1-8 + + LLVector3 obj_pos = gAgent.getPositionAgent() + LLVector3(x, y, -0.5); + bool res = LLToolPlacer::rezNewObject(type, NULL, 0, TRUE, gAgent.getPositionAgent(), obj_pos, gAgent.getRegion(), 0); + + LL_INFOS() << "Rezing a prim: type " << LLPrimitive::pCodeToString(type) << ", coordinates: " << obj_pos << " Success: " << res << LL_ENDL; + + lua_pop(L, lua_gettop(L)); + return 0; +} + lua_function(run_ui_command) { int top = lua_gettop(L); diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 7cdd7cc5c8..a4e6d20181 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -164,13 +164,17 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) BOOL b_hit_land = FALSE; S32 hit_face = -1; LLViewerObject* hit_obj = NULL; - U8 state = 0; BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); if( !success ) { return FALSE; } + return rezNewObject(pcode,hit_obj, hit_face, b_hit_land, ray_start_region, ray_end_region, regionp, use_physics); +} +BOOL LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, + LLVector3 ray_end_region, LLViewerRegion* regionp, U8 use_physics) +{ if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) { // Can't create objects on avatars or attachments @@ -194,6 +198,8 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) U8 material = LL_MCODE_WOOD; BOOL create_selected = FALSE; LLVolumeParams volume_params; + + U8 state = 0; switch (pcode) { diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index ad59cb0daa..d20d682710 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -50,12 +50,16 @@ public: static void setObjectType( LLPCode type ) { sObjectType = type; } static LLPCode getObjectType() { return sObjectType; } + static BOOL addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics); + static BOOL rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, + LLVector3 ray_end_region, LLViewerRegion *regionp, U8 use_physics); + protected: static LLPCode sObjectType; private: - BOOL addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ); - BOOL raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, + + static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); BOOL addDuplicate(S32 x, S32 y); }; -- cgit v1.2.3 From 7fccd662df48e5ddef0ec7e14a43289024bd27e1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Sep 2023 09:40:09 -0400 Subject: DRTVWR-589: Try to override Lua's built-in print() with print_info() so Lua print() output will go to the viewer log, instead of getting discarded and possibly causing failures when the buffer fills and there's no open stdout file handle. Also name each Lua C++ coroutine with the description we give the LuaState instance. --- indra/newview/llluamanager.cpp | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c1e111f0ac..931faadf4b 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -226,6 +226,15 @@ public: } } + static lua_CFunction get(const std::string& key) + { + // use find() instead of subscripting to avoid creating an entry for + // unknown key + const auto& registry{ getRegistry() }; + auto found{ registry.find(key) }; + return (found == registry.end())? nullptr : found->second; + } + private: using Registry = std::map<std::string, lua_CFunction>; static Registry& getRegistry() @@ -668,11 +677,6 @@ lua_function(listen_events) return 2; } -void initLUA(lua_State *L) -{ - LuaFunction::init(L); -} - /** * RAII class to manage the lifespan of a lua_State */ @@ -685,7 +689,9 @@ public: mState(luaL_newstate()) { luaL_openlibs(mState); - initLUA(mState); + LuaFunction::init(mState); + // Try to make print() write to our log. + lua_register(mState, "print", LuaFunction::get("print_info")); } LuaState(const LuaState&) = delete; @@ -747,9 +753,10 @@ private: void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb) { - LLCoros::instance().launch("LUAScriptFileCoro", [filename, cb]() + std::string desc{ stringize("runScriptFile('", filename, "')") }; + LLCoros::instance().launch(desc, [desc, filename, cb]() { - LuaState L(stringize("runScriptFile('", filename, "')"), cb); + LuaState L(desc, cb); auto LUA_sleep_func = [](lua_State *L) { @@ -776,18 +783,19 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) { - LLCoros::instance().launch("LUAScriptFileCoro", [cmd, cb]() + // find a suitable abbreviation for the cmd string + std::string_view shortcmd{ cmd }; + const size_t shortlen = 40; + std::string::size_type eol = shortcmd.find_first_of("\r\n"); + if (eol != std::string::npos) + shortcmd = shortcmd.substr(0, eol); + if (shortcmd.length() > shortlen) + shortcmd = stringize(shortcmd.substr(0, shortlen), "..."); + + std::string desc{ stringize("runScriptLine('", shortcmd, "')") }; + LLCoros::instance().launch(desc, [desc, cmd, cb]() { - // find a suitable abbreviation for the cmd string - std::string_view shortcmd{ cmd }; - const size_t shortlen = 40; - std::string::size_type eol = shortcmd.find_first_of("\r\n"); - if (eol != std::string::npos) - shortcmd = shortcmd.substr(0, eol); - if (shortcmd.length() > shortlen) - shortcmd = stringize(shortcmd.substr(0, shortlen), "..."); - - LuaState L(stringize("runScriptLine('", shortcmd, "')"), cb); + LuaState L(desc, cb); L.checkLua(luaL_dostring(L, cmd.c_str())); }); } -- cgit v1.2.3 From 968a39245ae53136dc9263e3e1f4255f2e0bd41a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Sep 2023 10:57:32 -0400 Subject: DRTVWR-589: Add Lua-callable await_event() function. This suspends the calling Lua coroutine (and C++ coroutine on which the Lua state is running) until an event is received on the named LLEventPump. Returns the event. Pass optional timeout in seconds as a second argument. With no timeout, waits indefinitely. Pass optional timeout discriminator return value as a third argument (default nil). --- indra/newview/llluamanager.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 931faadf4b..483075583c 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -32,6 +32,7 @@ #include "llappearancemgr.h" #include "llcallbacklist.h" #include "llerror.h" +#include "lleventcoro.h" #include "llevents.h" #include "llfloaterreg.h" #include "llfloaterimnearbychat.h" @@ -274,6 +275,7 @@ lua_function(print_debug) return 0; } +// also used for print(); see LuaState constructor lua_function(print_info) { luaL_where(L, 1); @@ -677,6 +679,29 @@ lua_function(listen_events) return 2; } +lua_function(await_event) +{ + // await_event(pumpname [, timeout [, value to return if timeout (default nil)]]) + auto pumpname{ lua_tostdstring(L, 1) }; + LLSD result; + if (lua_gettop(L) > 1) + { + auto timeout{ lua_tonumber(L, 2) }; + // with no 3rd argument, should be LLSD() + auto dftval{ lua_tollsd(L, 3) }; + lua_pop(L, lua_gettop(L)); + result = llcoro::suspendUntilEventOnWithTimeout(pumpname, timeout, dftval); + } + else + { + // no timeout + lua_pop(L, 1); + result = llcoro::suspendUntilEventOn(pumpname); + } + lua_pushllsd(L, result); + return 1; +} + /** * RAII class to manage the lifespan of a lua_State */ -- cgit v1.2.3 From c4f2be4b5479d9436edb13e56a1337502b10ff66 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Sep 2023 11:48:27 -0400 Subject: DRTVWR-589: Rename post_on_pump() to post_on() Sprinkle lua_checkstack() calls into functions that push to the Lua stack -- particularly important when traversing nested data structures of unknown depth! Tweak lua_pushllsd() handling of LLSD arrays. --- indra/newview/llluamanager.cpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 483075583c..7d54f6bf8f 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -141,6 +141,12 @@ private: static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data) { + if (! lua_checkstack(L, 3)) + { + LL_WARNS("Lua") << "Cannot extend Lua stack to call listen_events() callback" + << LL_ENDL; + return false; + } // push the registered Lua callback function stored in our registry as // "event.function" lua_getfield(L, LUA_REGISTRYINDEX, "event.function"); @@ -412,12 +418,14 @@ lua_function(set_debug_setting_bool) lua_function(get_avatar_name) { std::string name = gAgentAvatarp->getFullname(); + luaL_checkstack(L, 1, nullptr); lua_pushstring(L, name.c_str()); return 1; } lua_function(is_avatar_flying) { + luaL_checkstack(L, 1, nullptr); lua_pushboolean(L, gAgent.getFlying()); return 1; } @@ -471,6 +479,7 @@ void handle_notification_dialog(const LLSD ¬ification, const LLSD &response, { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + luaL_checkstack(L, 1, nullptr); lua_pushinteger(L, option); lua_setglobal(L, response_cb.c_str()); } @@ -607,10 +616,10 @@ lua_function(run_ui_command) return 0; } -lua_function(post_on_pump) +lua_function(post_on) { - std::string pumpname{ lua_tostring(L, -2) }; - LLSD data{ lua_tollsd(L, -1) }; + std::string pumpname{ lua_tostring(L, 1) }; + LLSD data{ lua_tollsd(L, 2) }; lua_pop(L, 2); LLEventPumps::instance().obtain(pumpname).post(data); return 0; @@ -622,6 +631,7 @@ lua_function(listen_events) { return luaL_typeerror(L, 1, "function"); } + luaL_checkstack(L, 2, nullptr); // Get the lua_State* for the main thread of this state, in case we were // called from a coroutine thread. We're going to make callbacks into Lua @@ -637,6 +647,7 @@ lua_function(listen_events) // pop the main thread lua_pop(L, 1); + luaL_checkstack(mainthread, 1, nullptr); LuaListener::ptr_t listener; // Does the main thread already have a LuaListener stored in the registry? // That is, has this Lua chunk already called listen_events()? @@ -853,6 +864,7 @@ std::string lua_tostdstring(lua_State* L, int index) void lua_pushstdstring(lua_State* L, const std::string& str) { + luaL_checkstack(L, 1, nullptr); lua_pushlstring(L, str.c_str(), str.length()); } @@ -944,6 +956,11 @@ LLSD lua_tollsd(lua_State* L, int index) // - LLSD::Real with integer value returns as LLSD::Integer. // - LLSD::UUID, LLSD::Date and LLSD::URI all convert to Lua string, // and so return as LLSD::String. + + // This is the most important of the luaL_checkstack() calls because a + // deeply nested Lua structure will enter this case at each level, and + // we'll need another 2 stack slots to traverse each nested table. + luaL_checkstack(L, 2, nullptr); lua_pushnil(L); // first key if (! lua_next(L, index)) { @@ -1092,6 +1109,8 @@ LLSD lua_tollsd(lua_State* L, int index) // stack a Lua object corresponding to the passed LLSD object. void lua_pushllsd(lua_State* L, const LLSD& data) { + // might need 2 slots for array or map + luaL_checkstack(L, 2, nullptr); switch (data.type()) { case LLSD::TypeUndefined: @@ -1136,15 +1155,13 @@ void lua_pushllsd(lua_State* L, const LLSD& data) { // push a new table with space for array entries lua_createtable(L, data.size(), 0); - lua_Integer index{ 0 }; + lua_Integer key{ 0 }; for (const auto& item: llsd::inArray(data)) { - // push new index value: table at -2, index at -1 - lua_pushinteger(L, ++index); - // push new array value: table at -3, index at -2, value at -1 + // push new array value: table at -2, value at -1 lua_pushllsd(L, item); - // pop key and value, assign table[key] = value - lua_settable(L, -3); + // pop value, assign table[key] = value + lua_seti(L, -2, ++key); } break; } @@ -1155,8 +1172,7 @@ void lua_pushllsd(lua_State* L, const LLSD& data) case LLSD::TypeURI: default: { - auto strdata{ data.asString() }; - lua_pushlstring(L, strdata.c_str(), strdata.length()); + lua_pushstdstring(data.asString()); break; } } -- cgit v1.2.3 From 3cc437e862a7c9fb2c839a89bcbddaf129a9f3ff Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Sep 2023 13:14:43 -0400 Subject: DRTVWR-589: Call lua_pushstdstring() correctly. --- indra/newview/llluamanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index a105eebf67..bf04f6a079 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -1195,7 +1195,7 @@ void lua_pushllsd(lua_State* L, const LLSD& data) case LLSD::TypeURI: default: { - lua_pushstdstring(data.asString()); + lua_pushstdstring(L, data.asString()); break; } } -- cgit v1.2.3 From 48dc344a9e65451c9e2b267fba7d3e01bdbbf801 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 28 Sep 2023 20:22:49 +0300 Subject: DRTVWR-589 - support for moving to dest --- indra/newview/llluamanager.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index bf04f6a079..b18708bd84 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -50,6 +50,7 @@ #include "llinventoryfunctions.h" #include "stringize.h" #include "lltoolplacer.h" +#include "llviewerregion.h" #include <boost/algorithm/string/replace.hpp> @@ -613,6 +614,86 @@ lua_function(rez_prim) return 0; } + +void move_to_dest(const LLVector3d &target_global, lua_State *L, std::string response_cb) +{ + struct Data + { + lua_State *L; + std::string response_cb; + }; + + Data *data = new Data(); + data->L = L; + if (!response_cb.empty()) + { + data->response_cb = response_cb; + } + + auto handle_dest_reached = [](BOOL success, void *user_data) + { + Data *cb_data = static_cast<Data *>(user_data); + if (!cb_data->response_cb.empty()) + { + S32 result = success ? 1 : -1; + lua_pushinteger(cb_data->L, result); + lua_setglobal(cb_data->L, cb_data->response_cb.c_str()); + } + }; + + gAgent.startAutoPilotGlobal(target_global, std::string(), NULL, handle_dest_reached, data, 0.f, 0.03f, FALSE); +} + +// move_by({x,y}, "lua_cb_func") +// avatar is the reference point +lua_function(move_by) +{ + lua_rawgeti(L, 1, 1); + F32 x = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 1, 2); + F32 y = lua_tonumber(L, -1); + lua_pop(L, 1); + + LLVector3d dest = gAgent.getRegion()->getPosGlobalFromRegion(gAgent.getPositionAgent() + LLVector3(x, y, 0)); + + std::string response_cb; + if (lua_type(L, 2) == LUA_TSTRING) + { + response_cb = lua_tostring(L, 2); + } + move_to_dest(dest, L, response_cb); + + lua_pop(L, lua_gettop(L)); + return 0; +} + +// move_to({x,y,z}, "lua_cb_func") +// region coordinates are used +lua_function(move_to) +{ + lua_rawgeti(L, 1, 1); + F32 x = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 1, 2); + F32 y = lua_tonumber(L, -1); + lua_rawgeti(L, 1, 3); + F32 z = lua_tonumber(L, -1); + lua_pop(L, 1); + + LLVector3d dest = gAgent.getRegion()->getPosGlobalFromRegion(LLVector3(x, y, z)); + + std::string response_cb; + if (lua_type(L, 2) == LUA_TSTRING) + { + response_cb = lua_tostring(L, 2); + } + move_to_dest(dest, L, response_cb); + + lua_pop(L, lua_gettop(L)); + return 0; +} + lua_function(run_ui_command) { int top = lua_gettop(L); -- cgit v1.2.3 From de61551df3219dae2238591bae5fa7b6c857e6b0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Sat, 30 Sep 2023 11:51:09 -0400 Subject: DRTVWR-589: Emulate print() better, show output on Lua floater. Break out a lua_print_msg() function common to print_debug(), print_info() and print_warning(). Instead of accepting a single argument, lua_print_msg() accepts arbitrary arguments, passing each to the Lua tostring() function and concatenating the results. In addition to returning the combined string to its caller for level-appropriate logging, it also posts the message to a "lua output" LLEventPump for any interested party. Make LLFloaterLUADebug listen on "lua output" when the floater is constructed, storing the connection in an LLTempBoundListener to stop listening when the floater is destroyed. Append each message to the floater's output panel with a line break. Make LLTextEditor::addLineBreakChar() public. insertText("\n") only appends a little rectangle glyph. Enlarge the text capacity of the floater's output panel to be able to report whatever messages a Lua script wants to print. Add diagnostic logging for posting events from Lua, and receiving events to forward to Lua. Since lua_pop() is a macro implemented on lua_settop(), replace the awkward construct lua_pop(L, lua_gettop(L)) with lua_settop(L, 0). Use lambdas instead of std::bind() to connect LuaListener and LLLeapListener. --- indra/newview/llfloaterluadebug.cpp | 12 ++- indra/newview/llfloaterluadebug.h | 3 + indra/newview/llluamanager.cpp | 91 ++++++++++++++++------ .../skins/default/xui/en/floater_lua_debug.xml | 1 + 4 files changed, 80 insertions(+), 27 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 9ca554d4ad..44454d7be0 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -54,6 +54,14 @@ BOOL LLFloaterLUADebug::postBuild() mResultOutput = getChild<LLTextEditor>("result_text"); mLineInput = getChild<LLLineEditor>("lua_cmd"); mScriptPath = getChild<LLLineEditor>("script_path"); + mOutConnection = LLEventPumps::instance().obtain("lua output") + .listen("LLFloaterLUADebug", + [mResultOutput=mResultOutput](const LLSD& data) + { + mResultOutput->insertText(data.asString()); + mResultOutput->addLineBreakChar(true); + return false; + }); getChild<LLButton>("execute_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); getChild<LLButton>("browse_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnBrowse, this)); @@ -77,7 +85,7 @@ void LLFloaterLUADebug::onExecuteClicked() std::string cmd = mLineInput->getText(); LLLUAmanager::runScriptLine(cmd, [this](std::string msg) { - mResultOutput->setText(msg); + mResultOutput->insertText(msg); }); } @@ -107,7 +115,7 @@ void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filena mScriptPath->setText(filepath); LLLUAmanager::runScriptFile(filepath, [this](std::string msg) { - mResultOutput->setText(msg); + mResultOutput->insertText(msg); }); } } diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 300d954aea..fd61e29ebe 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -26,6 +26,7 @@ #ifndef LL_LLFLOATERLUADEBUG_H #define LL_LLFLOATERLUADEBUG_H +#include "llevents.h" #include "llfloater.h" extern "C" @@ -54,6 +55,8 @@ class LLFloaterLUADebug : void runSelectedScript(const std::vector<std::string> &filenames); private: + LLTempBoundListener mOutConnection; + LLTextEditor* mResultOutput; LLLineEditor* mLineInput; LLLineEditor* mScriptPath; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index b18708bd84..2cc809ff0f 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -66,6 +66,7 @@ extern "C" #include <cstring> // std::memcpy() #include <map> #include <memory> // std::unique_ptr +#include <sstream> #include <string_view> #include <vector> @@ -109,8 +110,10 @@ public: super(getUniqueKey()), mState(L), mReplyPump(LLUUID::generateNewID().asString()), - mListener(new LLLeapListener(std::bind(&LuaListener::connect, this, - std::placeholders::_1, std::placeholders::_2))) + mListener( + new LLLeapListener( + [this](LLEventPump& pump, const std::string& listener) + { return connect(pump, listener); })) { mReplyConnection = connect(mReplyPump, "LuaListener"); } @@ -136,13 +139,15 @@ private: LLBoundListener connect(LLEventPump& pump, const std::string& listener) { - return pump.listen(listener, - std::bind(&LuaListener::call_lua, mState, pump.getName(), - std::placeholders::_1)); + return pump.listen( + listener, + [mState=mState, pumpname=pump.getName()](const LLSD& data) + { return call_lua(mState, pumpname, data); }); } static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data) { + LL_INFOS("Lua") << "LuaListener::call_lua('" << pump << "', " << data << ")" << LL_ENDL; if (! lua_checkstack(L, 3)) { LL_WARNS("Lua") << "Cannot extend Lua stack to call listen_events() callback" @@ -275,28 +280,63 @@ int name##_::call(lua_State* L) // ... supply method body here, referencing 'L' ... // } -lua_function(print_debug) +// This function consumes ALL Lua stack arguments and returns concatenated +// message string +std::string lua_print_msg(lua_State* L, const std::string_view& level) { + // On top of existing Lua arguments, push 'where' info + luaL_checkstack(L, 1, nullptr); luaL_where(L, 1); - LL_DEBUGS("Lua") << lua_tostring(L, 2) << ": " << lua_tostring(L, 1) << LL_ENDL; - lua_pop(L, 2); + // start with the 'where' info at the top of the stack + std::ostringstream out; + out << lua_tostring(L, -1); + lua_pop(L, 1); + const char* sep = ""; // 'where' info ends with ": " + // now iterate over arbitrary args, calling Lua tostring() on each and + // concatenating with separators + for (int p = 1; p <= lua_gettop(L); ++p) + { + out << sep; + sep = " "; + // push Lua tostring() function -- note, semantically different from + // lua_tostring()! + lua_getglobal(L, "tostring"); + // Now the stack is arguments 1 .. N, plus tostring(). + // Rotate downwards, producing stack args 2 .. N, tostring(), arg1. + lua_rotate(L, 1, -1); + // pop tostring() and arg1, pushing tostring(arg1) + // (ignore potential error code from lua_pcall() because, if there was + // an error, we expect the stack top to be an error message -- which + // we'll print) + lua_pcall(L, 1, 1, 0); + // stack now holds args 2 .. N, tostring(arg1) + out << lua_tostring(L, -1); + } + // pop everything + lua_settop(L, 0); + // capture message string + std::string msg{ out.str() }; + // put message out there for any interested party (*koff* LLFloaterLUADebug *koff*) + LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); + return msg; +} + +lua_function(print_debug) +{ + LL_DEBUGS("Lua") << lua_print_msg(L, "DEBUG") << LL_ENDL; return 0; } // also used for print(); see LuaState constructor lua_function(print_info) { - luaL_where(L, 1); - LL_INFOS("Lua") << lua_tostring(L, 2) << ": " << lua_tostring(L, 1) << LL_ENDL; - lua_pop(L, 2); + LL_INFOS("Lua") << lua_print_msg(L, "INFO") << LL_ENDL; return 0; } lua_function(print_warning) { - luaL_where(L, 1); - LL_WARNS("Lua") << lua_tostring(L, 2) << ": " << lua_tostring(L, 1) << LL_ENDL; - lua_pop(L, 2); + LL_WARNS("Lua") << lua_print_msg(L, "WARN") << LL_ENDL; return 0; } @@ -421,7 +461,7 @@ lua_function(get_avatar_name) { std::string name = gAgentAvatarp->getFullname(); luaL_checkstack(L, 1, nullptr); - lua_pushstring(L, name.c_str()); + lua_pushstdstring(L, name); return 1; } @@ -513,7 +553,7 @@ lua_function(show_notification) LLNotificationsUtil::add(notification); } - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -540,7 +580,7 @@ lua_function(add_menu_item) gMenuBarView->findChildMenuByName(menu, true)->append(menu_item); } - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -568,7 +608,7 @@ lua_function(add_menu) gMenuBarView->appendMenu(menu); } - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -588,7 +628,7 @@ lua_function(add_branch) gMenuBarView->findChildMenuByName(menu, true)->appendMenu(branch); } - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -610,7 +650,7 @@ lua_function(rez_prim) LL_INFOS() << "Rezing a prim: type " << LLPrimitive::pCodeToString(type) << ", coordinates: " << obj_pos << " Success: " << res << LL_ENDL; - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -664,7 +704,7 @@ lua_function(move_by) } move_to_dest(dest, L, response_cb); - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -690,7 +730,7 @@ lua_function(move_to) } move_to_dest(dest, L, response_cb); - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); return 0; } @@ -716,15 +756,16 @@ lua_function(run_ui_command) } sUIListener.call(event); - lua_pop(L, top); + lua_settop(L, 0); return 0; } lua_function(post_on) { - std::string pumpname{ lua_tostring(L, 1) }; + std::string pumpname{ lua_tostdstring(L, 1) }; LLSD data{ lua_tollsd(L, 2) }; lua_pop(L, 2); + LL_INFOS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL; LLEventPumps::instance().obtain(pumpname).post(data); return 0; } @@ -804,7 +845,7 @@ lua_function(await_event) auto timeout{ lua_tonumber(L, 2) }; // with no 3rd argument, should be LLSD() auto dftval{ lua_tollsd(L, 3) }; - lua_pop(L, lua_gettop(L)); + lua_settop(L, 0); result = llcoro::suspendUntilEventOnWithTimeout(pumpname, timeout, dftval); } else diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml index 0de26161e7..f03739f7c2 100644 --- a/indra/newview/skins/default/xui/en/floater_lua_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -55,6 +55,7 @@ layout="topleft" name="result_text" follows="left|top" + max_length="65536" width="515" top_delta="40" word_wrap="true" /> -- cgit v1.2.3 From bd20c548dd02778a2c7a6c318e2b8df6b2fc36c3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 2 Oct 2023 13:09:02 -0400 Subject: DRTVWR-589: Add initial integration test for LLLUAmanager. The first test runs a Lua script that calls post_on(), listen_events() and await_event() to engage in LLEventPump handshakes with the test program. Make llluamanager.cpp testable by putting LL_TEST conditionals around lots of viewer-internals headers and the lua_function definitions that engage them. Since LuaListener::connect() is called by its constructor, make it a static method that explicitly accepts the lua_State* (instead of finding it as mState). Add that parameter to its two existing calls. Add a debug log message when LuaListener is destroyed. This surfaced the need to pass a no-op deleter when listen_events() constructs a LuaListener::ptr_t. When compiled for LL_TEST, make LuaListener::mReplyPump an LLEventLogProxyFor<LLEventStream> instead of a plain LLEventStream. For debugging purposes, add a type string "LLEventLogProxy" for LLEventPumps::make(). A make() call with this type will return an LLEventLogProxyFor<LLEventStream>. --- indra/newview/CMakeLists.txt | 5 ++ indra/newview/llluamanager.cpp | 63 +++++++++++++------ indra/newview/llluamanager.h | 3 + indra/newview/tests/llluamanager_test.cpp | 101 ++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 20 deletions(-) create mode 100644 indra/newview/tests/llluamanager_test.cpp (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ca0b7692c4..22ee2fd295 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2291,6 +2291,11 @@ if (LL_TESTS) "${test_libs}" ) + LL_ADD_INTEGRATION_TEST(llluamanager + "llluamanager.cpp" + "${test_libs}" + ) + LL_ADD_INTEGRATION_TEST(llsechandler_basic llsechandler_basic.cpp "${test_libs}" diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 2cc809ff0f..2244fa32f6 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -28,19 +28,24 @@ #include "llviewerprecompiledheaders.h" #include "llluamanager.h" -#include "llagent.h" -#include "llappearancemgr.h" -#include "llcallbacklist.h" #include "llerror.h" #include "lleventcoro.h" +#include "lleventfilter.h" #include "llevents.h" +#include "llinstancetracker.h" +#include "llleaplistener.h" +#include "lluuid.h" +#include "stringize.h" + +// skip all these link dependencies for integration testing +#ifndef LL_TEST +#include "llagent.h" +#include "llappearancemgr.h" +#include "llcallbacklist.h" #include "llfloaterreg.h" #include "llfloaterimnearbychat.h" #include "llfloatersidepanelcontainer.h" -#include "llinstancetracker.h" -#include "llleaplistener.h" #include "llnotificationsutil.h" -#include "lluuid.h" #include "llvoavatarself.h" #include "llviewermenu.h" #include "llviewermenufile.h" @@ -48,10 +53,14 @@ #include "lluilistener.h" #include "llanimationstates.h" #include "llinventoryfunctions.h" -#include "stringize.h" #include "lltoolplacer.h" #include "llviewerregion.h" +// FIXME extremely hacky way to get to the UI Listener framework. There's +// a cleaner way. +extern LLUIListener sUIListener; +#endif // ! LL_TEST + #include <boost/algorithm/string/replace.hpp> extern "C" @@ -79,9 +88,6 @@ void lua_pushstdstring(lua_State* L, const std::string& str); LLSD lua_tollsd(lua_State* L, int index); void lua_pushllsd(lua_State* L, const LLSD& data); -// FIXME extremely hacky way to get to the UI Listener framework. There's almost certainly a cleaner way. -extern LLUIListener sUIListener; - /** * LuaListener is based on LLLeap. It serves an analogous function. * @@ -109,13 +115,20 @@ public: LuaListener(lua_State* L): super(getUniqueKey()), mState(L), - mReplyPump(LLUUID::generateNewID().asString()), mListener( new LLLeapListener( - [this](LLEventPump& pump, const std::string& listener) - { return connect(pump, listener); })) + [L](LLEventPump& pump, const std::string& listener) + { return connect(L, pump, listener); })) + { + mReplyConnection = connect(L, mReplyPump, "LuaListener"); + } + + LuaListener(const LuaListener&) = delete; + LuaListener& operator=(const LuaListener&) = delete; + + ~LuaListener() { - mReplyConnection = connect(mReplyPump, "LuaListener"); + LL_DEBUGS("Lua") << "~LuaListener('" << mReplyPump.getName() << "')" << LL_ENDL; } std::string getReplyName() const { return mReplyPump.getName(); } @@ -137,12 +150,12 @@ private: return key; } - LLBoundListener connect(LLEventPump& pump, const std::string& listener) + static LLBoundListener connect(lua_State* L, LLEventPump& pump, const std::string& listener) { return pump.listen( listener, - [mState=mState, pumpname=pump.getName()](const LLSD& data) - { return call_lua(mState, pumpname, data); }); + [L, pumpname=pump.getName()](const LLSD& data) + { return call_lua(L, pumpname, data); }); } static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data) @@ -181,7 +194,11 @@ private: } lua_State* mState; - LLEventStream mReplyPump; +#ifndef LL_TEST + LLEventStream mReplyPump{ LLUUID::generateNewID().asString() }; +#else + LLEventLogProxyFor<LLEventStream> mReplyPump{ "luapump", false }; +#endif LLTempBoundListener mReplyConnection; std::unique_ptr<LLLeapListener> mListener; }; @@ -340,6 +357,7 @@ lua_function(print_warning) return 0; } +#ifndef LL_TEST lua_function(avatar_sit) { gAgent.sitDown(); @@ -759,6 +777,7 @@ lua_function(run_ui_command) lua_settop(L, 0); return 0; } +#endif // ! LL_TEST lua_function(post_on) { @@ -812,8 +831,10 @@ lua_function(listen_events) { // pop the nil "event.listener" key lua_pop(mainthread, 1); - // instantiate a new LuaListener, binding the mainthread state - listener.reset(new LuaListener(mainthread)); + // instantiate a new LuaListener, binding the mainthread state -- but + // use a no-op deleter: we do NOT want to delete this new LuaListener + // on return from listen_events()! + listener.reset(new LuaListener(mainthread), [](LuaListener*){}); // set its key in the field where we'll look for it later lua_pushinteger(mainthread, listener->getKey()); lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.listener"); @@ -983,6 +1004,7 @@ void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) void LLLUAmanager::runScriptOnLogin() { +#ifndef LL_TEST std::string filename = gSavedSettings.getString("AutorunLuaScriptName"); if (filename.empty()) { @@ -998,6 +1020,7 @@ void LLLUAmanager::runScriptOnLogin() } runScriptFile(filename); +#endif // ! LL_TEST } std::string lua_tostdstring(lua_State* L, int index) diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 4581c33ff2..08d9876ce2 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -27,6 +27,9 @@ #ifndef LL_LLLUAMANAGER_H #define LL_LLLUAMANAGER_H +#include <functional> +#include <string> + class LLLUAmanager { public: diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp new file mode 100644 index 0000000000..e5e06b095c --- /dev/null +++ b/indra/newview/tests/llluamanager_test.cpp @@ -0,0 +1,101 @@ +/** + * @file llluamanager_test.cpp + * @author Nat Goodspeed + * @date 2023-09-28 + * @brief Test for llluamanager. + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Copyright (c) 2023, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +//#include "llviewerprecompiledheaders.h" +// associated header +#include "../newview/llluamanager.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "llapp.h" +#include "llevents.h" +#include "lleventcoro.h" +#include "stringize.h" +#include "../llcommon/tests/StringVec.h" + +class LLTestApp : public LLApp +{ +public: + bool init() override { return true; } + bool cleanup() override { return true; } + bool frame() override { return true; } +}; + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct llluamanager_data + { + // We need an LLApp instance because LLLUAmanager uses coroutines, + // which suspend, and when a coroutine suspends it checks LLApp state, + // and if it's not APP_STATUS_RUNNING the coroutine terminates. + LLTestApp mApp; + }; + typedef test_group<llluamanager_data> llluamanager_group; + typedef llluamanager_group::object object; + llluamanager_group llluamanagergrp("llluamanager"); + + template<> template<> + void object::test<1>() + { + set_test_name("test post_on(), listen_events(), await_event()"); + StringVec posts; + LLEventStream replypump("testpump"); + LLTempBoundListener conn( + replypump.listen("test<1>", + [&posts](const LLSD& post) + { + posts.push_back(post.asString()); + return false; + })); + const std::string lua( + "-- test post_on,listen_events,await_event\n" + "post_on('testpump', 'entry')\n" + "callback = function(pump, data)\n" + " -- just echo the data we received\n" + " post_on('testpump', data)\n" + "end\n" + "post_on('testpump', 'listen_events()')\n" + "replypump, cmdpump = listen_events(callback)\n" + "post_on('testpump', replypump)\n" + "post_on('testpump', 'await_event()')\n" + "await_event(replypump)\n" + "post_on('testpump', 'exit')\n" + ); + LLLUAmanager::runScriptLine(lua); + StringVec expected{ + "entry", + "listen_events()", + "", + "await_event()", + "message", + "exit" + }; + for (int i = 0; i < 10 && posts.size() <= 2 && posts[2].empty(); ++i) + { + llcoro::suspend(); + } + expected[2] = posts.at(2); + LL_DEBUGS() << "Found pumpname '" << expected[2] << "'" << LL_ENDL; + LLEventPump& luapump{ LLEventPumps::instance().obtain(expected[2]) }; + LL_DEBUGS() << "Found pump '" << luapump.getName() << "', type '" + << LLError::Log::classname(luapump) + << "': post('" << expected[4] << "')" << LL_ENDL; + luapump.post(expected[4]); + llcoro::suspend(); + ensure_equals("post_on() sequence", posts, expected); + } +} // namespace tut -- cgit v1.2.3 From b9c60817bbd4e5f293236dc8133c7bf5d3f264c1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Oct 2023 14:47:20 -0400 Subject: DRTVWR-589: Clean up from merge from updated main. --- indra/newview/llviewermenufile.cpp | 14 -------------- indra/newview/llviewermenufile.h | 2 -- 2 files changed, 16 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 15088244f9..17e89e1850 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -741,20 +741,6 @@ class LLFileEnableCloseAllWindows : public view_listener_t } }; -void close_all_windows() -{ - bool app_quitting = false; - gFloaterView->closeAllChildren(app_quitting); - LLFloaterSnapshot *floater_snapshot = LLFloaterSnapshot::findInstance(); - if (floater_snapshot) - floater_snapshot->closeFloater(app_quitting); - LLFloaterSimpleOutfitSnapshot *floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance(); - if (floater_outfit_snapshot) - floater_outfit_snapshot->closeFloater(app_quitting); - if (gMenuHolder) - gMenuHolder->hideMenus(); -} - class LLFileCloseAllWindows : public view_listener_t { bool handleEvent(const LLSD& userdata) diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index fd13eef8b7..61572b9996 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -72,8 +72,6 @@ void assign_defaults_and_show_upload_message( const std::string& display_name, std::string& description); -void close_all_windows(); - //consider moving all file pickers below to more suitable place class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) -- cgit v1.2.3 From 38a6ef9921e6b305bdb8a3165cf45da0aa76adee Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" <vir@lindenlab.com> Date: Tue, 3 Oct 2023 21:47:00 +0100 Subject: DRTVWR-589 - more demo work --- indra/newview/llluamanager.cpp | 50 +++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index b18708bd84..eb6923ebe2 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -596,16 +596,50 @@ lua_function(add_branch) // avatar is the reference point lua_function(rez_prim) { - lua_rawgeti(L, 1, 1); - F32 x = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_rawgeti(L, 1, 2); - F32 y = lua_tonumber(L, -1); - lua_pop(L, 1); + lua_rawgeti(L, 1, 1); + F32 x = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 1, 2); + F32 y = lua_tonumber(L, -1); + lua_pop(L, 1); + + S32 type(lua_tonumber(L, 2)); // primitive shapes 1-8 + + LLVector3 obj_pos = gAgent.getPositionAgent() + LLVector3(x, y, -0.5); + bool res = LLToolPlacer::rezNewObject(type, NULL, 0, TRUE, gAgent.getPositionAgent(), obj_pos, gAgent.getRegion(), 0); + + LL_INFOS() << "Rezing a prim: type " << LLPrimitive::pCodeToString(type) << ", coordinates: " << obj_pos << " Success: " << res << LL_ENDL; - S32 type(lua_tonumber(L, 2)); // primitive shapes 1-8 + lua_pop(L, lua_gettop(L)); + return 0; +} - LLVector3 obj_pos = gAgent.getPositionAgent() + LLVector3(x, y, -0.5); +// rez_prim2({x, y,z}, prim_type) +// avatar is the reference point +lua_function(rez_prim2) +{ + luaL_checktype(L, 1, LUA_TTABLE); + S32 type(lua_tonumber(L,2)); + lua_pop(L,1); + + lua_pushinteger(L, 1); + lua_gettable(L, -2); + F32 x = lua_tonumber(L,-1); + lua_pop(L,1); + + lua_pushinteger(L, 2); + lua_gettable(L, -2); + F32 y = lua_tonumber(L,-1); + lua_pop(L,1); + + lua_pushinteger(L, 3); + lua_gettable(L, -2); + F32 z = lua_tonumber(L,-1); + lua_pop(L,1); + + LL_INFOS() << "x " << x << " y " << y << " z " << z << " type " << type << LL_ENDL; + + LLVector3 obj_pos = gAgent.getPositionAgent() + LLVector3(x, y, z); bool res = LLToolPlacer::rezNewObject(type, NULL, 0, TRUE, gAgent.getPositionAgent(), obj_pos, gAgent.getRegion(), 0); LL_INFOS() << "Rezing a prim: type " << LLPrimitive::pCodeToString(type) << ", coordinates: " << obj_pos << " Success: " << res << LL_ENDL; -- cgit v1.2.3 From ec979ba1b3b97211badf103dcb075ce28e5a2bc9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 4 Oct 2023 13:36:15 +0300 Subject: DRTVWR-589 - restore close_all_swindows() --- indra/newview/llviewermenufile.cpp | 18 ++++++++++++------ indra/newview/llviewermenufile.h | 2 ++ 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 17e89e1850..724f19c7d6 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -741,16 +741,22 @@ class LLFileEnableCloseAllWindows : public view_listener_t } }; +void close_all_windows() +{ + bool app_quitting = false; + gFloaterView->closeAllChildren(app_quitting); + LLFloaterSnapshot *floater_snapshot = LLFloaterSnapshot::findInstance(); + if (floater_snapshot) + floater_snapshot->closeFloater(app_quitting); + if (gMenuHolder) + gMenuHolder->hideMenus(); +} + class LLFileCloseAllWindows : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool app_quitting = false; - gFloaterView->closeAllChildren(app_quitting); - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); - if (floater_snapshot) - floater_snapshot->closeFloater(app_quitting); - if (gMenuHolder) gMenuHolder->hideMenus(); + close_all_windows(); return true; } }; diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 61572b9996..fd13eef8b7 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -72,6 +72,8 @@ void assign_defaults_and_show_upload_message( const std::string& display_name, std::string& description); +void close_all_windows(); + //consider moving all file pickers below to more suitable place class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) -- cgit v1.2.3 From 01a59bab1a4b7c4645271a21cfaadc3735b6029c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Oct 2023 21:46:31 -0400 Subject: DRTVWR-589: Add tests for LLSD-to-Lua round-trip conversions. Add from_lua() function to run a small Lua script that constructs a specified Lua object and posts it back to the test program via a temporary LLEventPump. Call this with a variety of Lua objects, comparing to the expected LLSD. Add round_trip() function to run another small Lua script that listens for incoming LLEventPump events and, for each, posts the received Lua data back to the test program as LLSD. Call this with a variety of LLSD objects, comparing to the expected LLSD. Also collect these objects into an LLSD array and send that for a round trip; also collect into an LLSD map and send that. Sadly, tests currently drive an access violation when trying to convert a nested Lua table to LLSD. Add verbose debug logging to lua_tollsd() to identify the context at which we hit the access violation. Add comments describing further exceptions to LLSD-to-Lua round trip identity. Add lua_what() iostream manipulator to stream whatever we can readily discover about a value at a specified Lua stack index. Add lua_stack() to report the contents of the Lua stack. Since the stack is created anew for every call to a C function, this shouldn't usually be enormous. Add hexdump.h with iostream manipulators to dump a byte range as hex digits, or to produce readable text from a mix of printing and nonprinting ASCII characters. --- indra/newview/llluamanager.cpp | 152 ++++++++++++++++++++- indra/newview/tests/llluamanager_test.cpp | 215 +++++++++++++++++++++++++++++- 2 files changed, 359 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 61c0ecf1ed..5efe4ac7a6 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -28,6 +28,7 @@ #include "llviewerprecompiledheaders.h" #include "llluamanager.h" +#include "hexdump.h" #include "llerror.h" #include "lleventcoro.h" #include "lleventfilter.h" @@ -1070,6 +1071,122 @@ void lua_pushstdstring(lua_State* L, const std::string& str) lua_pushlstring(L, str.c_str(), str.length()); } +// Usage: std::cout << lua_what(L, stackindex) << ...; +// Reports on the Lua value found at the passed stackindex. +// If cast to std::string, returns the corresponding string value. +class lua_what +{ +public: + lua_what(lua_State* state, int idx): + L(state), + index(idx) + {} + + friend std::ostream& operator<<(std::ostream& out, const lua_what& self) + { + switch (lua_type(self.L, self.index)) + { + case LUA_TNONE: + // distinguish acceptable but non-valid index + out << "none"; + break; + + case LUA_TNIL: + out << "nil"; + break; + + case LUA_TBOOLEAN: + { + auto oldflags { out.flags() }; + out << std::boolalpha << lua_toboolean(self.L, self.index); + out.flags(oldflags); + break; + } + + case LUA_TNUMBER: + out << lua_tonumber(self.L, self.index); + break; + + case LUA_TSTRING: + out << std::quoted(lua_tostdstring(self.L, self.index)); + break; + + case LUA_TUSERDATA: + { + const size_t maxlen = 20; + auto binlen{ lua_rawlen(self.L, self.index) }; + LLSD::Binary binary(std::min(maxlen, binlen)); + std::memcpy(binary.data(), lua_touserdata(self.L, self.index), binary.size()); + out << LL::hexdump(binary); + if (binlen > maxlen) + { + out << "...(" << (binlen - maxlen) << " more)"; + } + break; + } + + case LUA_TLIGHTUSERDATA: + out << lua_touserdata(self.L, self.index); + break; + + default: + // anything else, don't bother trying to report value, just type + out << lua_typename(self.L, lua_type(self.L, self.index)); + break; + } + return out; + } + + operator std::string() const { return stringize(*this); } + +private: + lua_State* L; + int index; +}; + +// Usage: std::cout << lua_stack(L) << ...; +// Reports on the contents of the Lua stack. +// If cast to std::string, returns the corresponding string value. +class lua_stack +{ +public: + lua_stack(lua_State* state): + L(state) + {} + + friend std::ostream& operator<<(std::ostream& out, const lua_stack& self) + { + const char* sep = "stack: ["; + for (int index = 1; index <= lua_gettop(self.L); ++index) + { + out << sep << lua_what(self.L, index); + sep = ", "; + } + out << ']'; + return out; + } + + operator std::string() const { return stringize(*this); } + +private: + lua_State* L; +}; + +// log exit from any block declaring an instance of DebugExit, regardless of +// how control leaves that block +struct DebugExit +{ + DebugExit(const std::string& name): mName(name) {} + DebugExit(const DebugExit&) = delete; + DebugExit& operator=(const DebugExit&) = delete; + ~DebugExit() + { + LL_DEBUGS("Lua") << "exit " << mName << LL_ENDL; + } + + std::string mName; +}; + // By analogy with existing lua_tomumble() functions, return an LLSD object // corresponding to the Lua object at stack index 'index' in state L. // This function assumes that a Lua caller is fully aware that they're trying @@ -1087,6 +1204,9 @@ void lua_pushstdstring(lua_State* L, const std::string& str) // reached by that block raises a Lua error. LLSD lua_tollsd(lua_State* L, int index) { + LL_DEBUGS("Lua") << "lua_tollsd(" << index << ") of " << lua_gettop(L) << " stack entries: " + << lua_what(L, index) << LL_ENDL; + DebugExit log_exit("lua_tollsd()"); switch (lua_type(L, index)) { case LUA_TNONE: @@ -1158,17 +1278,36 @@ LLSD lua_tollsd(lua_State* L, int index) // - LLSD::Real with integer value returns as LLSD::Integer. // - LLSD::UUID, LLSD::Date and LLSD::URI all convert to Lua string, // and so return as LLSD::String. + // - Lua does not store any table key whose value is nil. An LLSD + // array with isUndefined() entries produces a Lua table with + // "holes" in the int key sequence; this converts back to an LLSD + // array containing corresponding isUndefined() entries -- except + // when one or more of the final entries isUndefined(). These are + // simply dropped, producing a shorter LLSD array than the original. + // - For the same reason, any keys in an LLSD map whose value + // isUndefined() are simply discarded in the converted Lua table. + // This converts back to an LLSD map lacking those keys. + // - If it's important to preserve the original length of an LLSD + // array whose final entries are undefined, or the full set of keys + // for an LLSD map some of whose values are undefined, store an + // LLSD::emptyArray() or emptyMap() instead. These will be + // represented in Lua as empty table, which should convert back to + // undefined LLSD. Naturally, though, those won't survive a second + // round trip. // This is the most important of the luaL_checkstack() calls because a // deeply nested Lua structure will enter this case at each level, and // we'll need another 2 stack slots to traverse each nested table. luaL_checkstack(L, 2, nullptr); + LL_DEBUGS("Lua") << "checking for empty table" << LL_ENDL; lua_pushnil(L); // first key + LL_DEBUGS("Lua") << lua_stack(L) << LL_ENDL; if (! lua_next(L, index)) { // it's a table, but the table is empty -- no idea if it should be // modeled as empty array or empty map -- return isUndefined(), // which can be consumed as either + LL_DEBUGS("Lua") << "empty table" << LL_ENDL; return {}; } // key is at stack index -2, value at index -1 @@ -1177,6 +1316,8 @@ LLSD lua_tollsd(lua_State* L, int index) LuaPopper popper(L, 2); // Remember the type of the first key auto firstkeytype{ lua_type(L, -2) }; + LL_DEBUGS("Lua") << "table not empty, first key type " << lua_typename(L, firstkeytype) + << LL_ENDL; switch (firstkeytype) { case LUA_TNUMBER: @@ -1254,6 +1395,7 @@ LLSD lua_tollsd(lua_State* L, int index) // crazy key territory. return luaL_error(L, "Gaps in Lua table too large for conversion to LLSD array"); } + LL_DEBUGS("Lua") << "collected " << keys.size() << " keys, max " << highkey << LL_ENDL; // right away expand the result array to the size we'll need LLSD result{ LLSD::emptyArray() }; result[highkey - 1] = LLSD(); @@ -1263,8 +1405,10 @@ LLSD lua_tollsd(lua_State* L, int index) { // key at stack index -2, value at index -1 // We've already validated lua_tointegerx() for each key. + auto key{ lua_tointeger(L, -2) }; + LL_DEBUGS("Lua") << "key " << key << ':' << LL_ENDL; // Don't forget to subtract 1 from Lua key for LLSD subscript! - result[LLSD::Integer(lua_tointeger(L, -2)) - 1] = lua_tollsd(L, -1); + result[LLSD::Integer(key) - 1] = lua_tollsd(L, -1); // remove value, keep key for next iteration lua_pop(L, 1); } @@ -1283,8 +1427,10 @@ LLSD lua_tollsd(lua_State* L, int index) return luaL_error(L, "Cannot convert %s map key to LLSD", lua_typename(L, mapkeytype)); } - - result[lua_tostdstring(L, -2)] = lua_tollsd(L, -1); + + auto key{ lua_tostdstring(L, -2) }; + LL_DEBUGS("Lua") << "map key " << std::quoted(key) << ':' << LL_ENDL; + result[key] = lua_tollsd(L, -1); // remove value, keep key for next iteration lua_pop(L, 1); } while (lua_next(L, index) != 0); diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index e5e06b095c..1363f114c1 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -15,12 +15,17 @@ #include "../newview/llluamanager.h" // STL headers // std headers +#include <vector> // external library headers // other Linden headers #include "../test/lltut.h" #include "llapp.h" +#include "lldate.h" #include "llevents.h" #include "lleventcoro.h" +#include "llsdutil.h" +#include "lluri.h" +#include "lluuid.h" #include "stringize.h" #include "../llcommon/tests/StringVec.h" @@ -32,6 +37,17 @@ public: bool frame() override { return true; } }; +template <typename CALLABLE> +auto listener(CALLABLE&& callable) +{ + return [callable=std::forward<CALLABLE>(callable)] + (const LLSD& data) + { + callable(data); + return false; + }; +} + /***************************************************************************** * TUT *****************************************************************************/ @@ -56,11 +72,8 @@ namespace tut LLEventStream replypump("testpump"); LLTempBoundListener conn( replypump.listen("test<1>", - [&posts](const LLSD& post) - { - posts.push_back(post.asString()); - return false; - })); + listener([&posts](const LLSD& data) + { posts.push_back(data.asString()); }))); const std::string lua( "-- test post_on,listen_events,await_event\n" "post_on('testpump', 'entry')\n" @@ -98,4 +111,196 @@ namespace tut llcoro::suspend(); ensure_equals("post_on() sequence", posts, expected); } + + void from_lua(const std::string& desc, const std::string_view& construct, const LLSD& expect) + { + LLSD fromlua; + LLEventStream replypump("testpump"); + LLTempBoundListener conn( + replypump.listen("llluamanager_test", + listener([&fromlua](const LLSD& data){ fromlua = data; }))); + const std::string lua(stringize( + "-- test LLSD synthesized by Lua\n", + // we expect the caller's Lua snippet to construct a Lua object + // called 'data' + construct, "\n" + "post_on('testpump', data)\n" + )); + LLLUAmanager::runScriptLine(lua); + // At this point LLLUAmanager::runScriptLine() has launched a new C++ + // coroutine to run the passed Lua snippet, but that coroutine hasn't + // yet had a chance to run. Poke the coroutine scheduler until the Lua + // script has sent its data. + for (int i = 0; i < 10 && fromlua.isUndefined(); ++i) + { + llcoro::suspend(); + } + // We woke up again ourselves because the coroutine running Lua has + // finished. + ensure_equals(desc, fromlua, expect); + } + + template<> template<> + void object::test<2>() + { + set_test_name("LLSD from Lua"); + from_lua("nil", "data = nil", LLSD()); + from_lua("true", "data = true", true); + from_lua("false", "data = false", false); + from_lua("int", "data = 17", 17); + from_lua("real", "data = 3.14", 3.14); + from_lua("string", "data = 'string'", "string"); + // can't synthesize Lua userdata in Lua code: that can only be + // constructed by a C function + from_lua("empty table", "data = {}", LLSD()); + from_lua("nested empty table", "data = { 1, 2, 3, {}, 5 }", + llsd::array(1, 2, 3, LLSD(), 5)); + from_lua("nested non-empty table", "data = { 1, 2, 3, {a=0, b=1}, 5 }", + llsd::array(1, 2, 3, llsd::map("a", 0, "b", 1), 5)); + } + + void round_trip(const std::string& desc, const LLSD& send, const LLSD& expect) + { + LLSD reply; + LLEventStream replypump("testpump"); + LLTempBoundListener conn( + replypump.listen("llluamanager_test", + listener([&reply](const LLSD& post){ reply = post; }))); + const std::string lua( + "-- test LLSD round trip\n" + "callback = function(pump, data)\n" + " -- just echo the data we received\n" + " post_on('testpump', data)\n" + "end\n" + "replypump, cmdpump = listen_events(callback)\n" + "post_on('testpump', replypump)\n" + "await_event(replypump)\n" + ); + LLLUAmanager::runScriptLine(lua); + // At this point LLLUAmanager::runScriptLine() has launched a new C++ + // coroutine to run the passed Lua snippet, but that coroutine hasn't + // yet had a chance to run. Poke the coroutine scheduler until the Lua + // script has sent its reply pump name. + for (int i = 0; i < 10 && reply.isUndefined(); ++i) + { + llcoro::suspend(); + } + // We woke up again ourselves because the coroutine running Lua has + // reached the await_event() call, which suspends the calling C++ + // coroutine (including the Lua code running on it) until we post + // something to that reply pump. + auto luapump{ reply.asString() }; + reply.clear(); + LLEventPumps::instance().post(luapump, send); + // The C++ coroutine running the Lua script is now ready to run. Run + // it so it will echo the LLSD back to us. + llcoro::suspend(); + ensure_equals(desc, reply, expect); + } + + // Define an RTItem to be used for round-trip LLSD testing: what it is, + // what we send to Lua, what we expect to get back. They could be the + // same. + struct RTItem + { + RTItem(const std::string& name, const LLSD& send, const LLSD& expect): + mName(name), + mSend(send), + mExpect(expect) + {} + RTItem(const std::string& name, const LLSD& both): + mName(name), + mSend(both), + mExpect(both) + {} + + std::string mName; + LLSD mSend, mExpect; + }; + + bool will_be_nil(const LLSD& data) + { + // undefined LLSD converts to Lua nil. + // empty LLSD array or empty LLSD map converts to nil. + return (data.isUndefined() || + ((data.isArray() || data.isMap()) && data.size() == 0)); + } + + template<> template<> + void object::test<3>() + { + set_test_name("LLSD round trip"); + LLSD::Binary binary{ 3, 1, 4, 1, 5, 9, 2, 6, 5 }; + const char* uuid{ "01234567-abcd-0123-4567-0123456789ab" }; + const char* date{ "2023-10-04T21:06:00Z" }; + const char* uri{ "https://secondlife.com/index.html" }; + std::vector<RTItem> items{ + RTItem("undefined", LLSD()), + RTItem("true", true), + RTItem("false", false), + RTItem("int", 17), + RTItem("real", 3.14), + RTItem("int real", 27.0, 27), + RTItem("string", "string"), + RTItem("binary", binary), + RTItem("empty array", LLSD::emptyArray(), LLSD()), + RTItem("empty map", LLSD::emptyMap(), LLSD()), + RTItem("UUID", LLUUID(uuid), uuid), + RTItem("date", LLDate(date), date), + RTItem("uri", LLURI(uri), uri) + }; + // scalars + for (const auto& item: items) + { + round_trip(item.mName, item.mSend, item.mExpect); + } + + // array + LLSD send_array{ LLSD::emptyArray() }, expect_array{ LLSD::emptyArray() }; + for (const auto& item: items) + { + // BUG AVOIDANCE: + // As of 2023-10-04, lua_tollsd() hits access violation in + // lua_next() when handed a table nested in another table. + if (! (item.mSend.isArray() || item.mSend.isMap())) + { + send_array.append(item.mSend); + expect_array.append(item.mExpect); + } + } + // Lua takes a table value of nil to mean: don't store this key. An + // LLSD array containing undefined entries (converted to nil) leaves + // "holes" in the Lua table. These will be converted back to undefined + // LLSD entries -- except at the end. Trailing undefined entries are + // simply omitted from the table -- so the table converts back to a + // shorter LLSD array. We've constructed send_array and expect_array + // according to 'items' above -- but truncate from expect_array any + // trailing entries that will map to Lua nil. + while (expect_array.size() > 0 && + will_be_nil(expect_array[expect_array.size() - 1])) + { + expect_array.erase(expect_array.size() - 1); + } + round_trip("array", send_array, expect_array); + + // map + LLSD send_map{ LLSD::emptyMap() }, expect_map{ LLSD::emptyMap() }; + for (const auto& item: items) + { + // BUG AVOIDANCE: + // see comment in the send_array construction loop above + if (! (item.mSend.isArray() || item.mSend.isMap())) + { + send_map[item.mName] = item.mSend; + // see comment in the expect_array truncation loop above -- + // keep this test because Lua never stores table entries with + // nil values + if (! will_be_nil(item.mExpect)) + { + expect_map[item.mName] = item.mExpect; + } + } + } + round_trip("map", send_map, expect_map); + } } // namespace tut -- cgit v1.2.3 From d1b7bbc7efcaf0e7b449ba00aa9f1246504b0a13 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Thu, 5 Oct 2023 20:08:36 +0300 Subject: SL-19826 Fix mac build issue (unused variable) (cherry picked from commit 08a3b56669880101aa705c98e60b76e92d26c93b) --- indra/newview/llinventorygallery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 4838ba7a47..0e4c64a641 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2420,7 +2420,7 @@ void LLInventoryGallery::startDrag() ids.push_back(selected_id); } } - LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT); + LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, src); } bool LLInventoryGallery::areViewsInitialized() -- cgit v1.2.3 From b8697234e095b3a8de579a3259dd99d00b1a36b4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Sat, 7 Oct 2023 09:42:36 -0400 Subject: DRTVWR-589: Solved the bug in traversing nested Lua tables. When lua_tollsd() makes a recursive call, it passes -1 as the index of the newly-encountered nested table. To traverse the nested table, lua_tollsd() starts by pushing nil as the initial key. But then calling lua_next(-1) finds nil -- NOT the nested table! Converting the index parameter to absolute before pushing nil solves. --- indra/newview/llluamanager.cpp | 5 +++ indra/newview/tests/llluamanager_test.cpp | 53 ++++++++++++++----------------- 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 5efe4ac7a6..de02fe4646 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -1299,6 +1299,11 @@ LLSD lua_tollsd(lua_State* L, int index) // deeply nested Lua structure will enter this case at each level, and // we'll need another 2 stack slots to traverse each nested table. luaL_checkstack(L, 2, nullptr); + // BEFORE we push nil to initialize the lua_next() traversal, convert + // 'index' to absolute! Our caller might have passed a relative index; + // we do, below: lua_tollsd(L, -1). If 'index' is -1, then when we + // push nil, what we find at index -1 is nil, not the table! + index = lua_absindex(L, index); LL_DEBUGS("Lua") << "checking for empty table" << LL_ENDL; lua_pushnil(L); // first key LL_DEBUGS("Lua") << lua_stack(L) << LL_ENDL; diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 1363f114c1..6433ff1118 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -218,14 +218,6 @@ namespace tut LLSD mSend, mExpect; }; - bool will_be_nil(const LLSD& data) - { - // undefined LLSD converts to Lua nil. - // empty LLSD array or empty LLSD map converts to nil. - return (data.isUndefined() || - ((data.isArray() || data.isMap()) && data.size() == 0)); - } - template<> template<> void object::test<3>() { @@ -259,15 +251,12 @@ namespace tut LLSD send_array{ LLSD::emptyArray() }, expect_array{ LLSD::emptyArray() }; for (const auto& item: items) { - // BUG AVOIDANCE: - // As of 2023-10-04, lua_tollsd() hits access violation in - // lua_next() when handed a table nested in another table. - if (! (item.mSend.isArray() || item.mSend.isMap())) - { - send_array.append(item.mSend); - expect_array.append(item.mExpect); - } + send_array.append(item.mSend); + expect_array.append(item.mExpect); } + // exercise the array tail trimming below + send_array.append(items[0].mSend); + expect_array.append(items[0].mExpect); // Lua takes a table value of nil to mean: don't store this key. An // LLSD array containing undefined entries (converted to nil) leaves // "holes" in the Lua table. These will be converted back to undefined @@ -275,9 +264,9 @@ namespace tut // simply omitted from the table -- so the table converts back to a // shorter LLSD array. We've constructed send_array and expect_array // according to 'items' above -- but truncate from expect_array any - // trailing entries that will map to Lua nil. + // trailing entries whose mSend will map to Lua nil. while (expect_array.size() > 0 && - will_be_nil(expect_array[expect_array.size() - 1])) + send_array[expect_array.size() - 1].isUndefined()) { expect_array.erase(expect_array.size() - 1); } @@ -287,20 +276,26 @@ namespace tut LLSD send_map{ LLSD::emptyMap() }, expect_map{ LLSD::emptyMap() }; for (const auto& item: items) { - // BUG AVOIDANCE: - // see comment in the send_array construction loop above - if (! (item.mSend.isArray() || item.mSend.isMap())) + send_map[item.mName] = item.mSend; + // see comment in the expect_array truncation loop above -- + // Lua never stores table entries with nil values + if (item.mSend.isDefined()) { - send_map[item.mName] = item.mSend; - // see comment in the expect_array truncation loop above -- - // keep this test because Lua never stores table entries with - // nil values - if (! will_be_nil(item.mExpect)) - { - expect_map[item.mName] = item.mExpect; - } + expect_map[item.mName] = item.mExpect; } } round_trip("map", send_map, expect_map); + + // deeply nested map: exceed Lua's default stack space (20), + // i.e. verify that we have the right checkstack() calls + for (int i = 0; i < 20; ++i) + { + LLSD new_send_map{ send_map }, new_expect_map{ expect_map }; + new_send_map["nested map"] = send_map; + new_expect_map["nested map"] = expect_map; + send_map = new_send_map; + expect_map = new_expect_map; + } + round_trip("nested map", send_map, expect_map); } } // namespace tut -- cgit v1.2.3 From 1f3c0a4cd0c324e9c46c3811404357e8a6790b26 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 19 Oct 2023 11:50:50 -0400 Subject: DRTVWR-589: Fix unreferenced LuaListener::mState member. --- indra/newview/llluamanager.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index de02fe4646..0475122832 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -115,7 +115,6 @@ class LuaListener: public LLInstanceTracker<LuaListener, int> public: LuaListener(lua_State* L): super(getUniqueKey()), - mState(L), mListener( new LLLeapListener( [L](LLEventPump& pump, const std::string& listener) @@ -194,7 +193,6 @@ private: return result; } - lua_State* mState; #ifndef LL_TEST LLEventStream mReplyPump{ LLUUID::generateNewID().asString() }; #else @@ -1114,7 +1112,7 @@ public: case LUA_TUSERDATA: { const size_t maxlen = 20; - auto binlen{ lua_rawlen(self.L, self.index) }; + size_t binlen{ lua_rawlen(self.L, self.index) }; LLSD::Binary binary(std::min(maxlen, binlen)); std::memcpy(binary.data(), lua_touserdata(self.L, self.index), binary.size()); out << LL::hexdump(binary); -- cgit v1.2.3 From cf0838cd6917b7dd2c8f056d6cb3ef9f59d92fda Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 2 Nov 2023 09:05:41 -0400 Subject: DRTVWR-589: StringVec's operator<<() overload must precede lltut.h. If not, the resulting error message is so mysterious that it's worth adding an error check to explain how to avoid it. --- indra/newview/tests/llluamanager_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 6433ff1118..98a2726af7 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -18,6 +18,7 @@ #include <vector> // external library headers // other Linden headers +#include "../llcommon/tests/StringVec.h" #include "../test/lltut.h" #include "llapp.h" #include "lldate.h" @@ -27,7 +28,6 @@ #include "lluri.h" #include "lluuid.h" #include "stringize.h" -#include "../llcommon/tests/StringVec.h" class LLTestApp : public LLApp { -- cgit v1.2.3 From bb51ead8815d6f1843bed3f16dfae94aa0e85950 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 2 Nov 2023 09:08:25 -0400 Subject: DRTVWR-589: Switch to the lua package built by new 3p-lua repo. Also ditch crufty CMake logic related to lleventhost, which we haven't used for years. --- indra/newview/CMakeLists.txt | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6fc0f28a89..aa723c62cd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1804,20 +1804,6 @@ if (WINDOWS) endif (NOT UNATTENDED) if (PACKAGE) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2 - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py - ${CMAKE_CURRENT_SOURCE_DIR}/.. - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CFG_INTDIR} - DEPENDS - lleventhost - ${EVENT_HOST_SCRIPTS} - ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py - ) - add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/touched.bat COMMAND ${PYTHON_EXECUTABLE} @@ -1847,9 +1833,6 @@ if (WINDOWS) add_custom_target(llpackage ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat ) - # temporarily disable packaging of event_host until hg subrepos get - # sorted out on the parabuild cluster... - #${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2) endif (PACKAGE) elseif (DARWIN) @@ -1917,6 +1900,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLPHYSICSEXTENSIONS_LIBRARIES} ll::bugsplat ll::tracy + ll::lualibs ) if( TARGET ll::intel_memops ) @@ -2287,7 +2271,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llluamanager "llluamanager.cpp" - "${test_libs}" + "${test_libs};ll::lualibs" ) LL_ADD_INTEGRATION_TEST(llsechandler_basic -- cgit v1.2.3 From f80ede0a752447d81086f672001a562e4492553f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 2 Nov 2023 17:46:04 -0400 Subject: DRTVWR-589: Update Lualibs.cmake to use lua54.lib from 3p-lua. Also remove #pragma comment(lib, "liblua54.a") from relevant source files. --- indra/newview/llfloaterluadebug.cpp | 4 ---- indra/newview/llluamanager.cpp | 4 ---- 2 files changed, 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 44454d7be0..32e9e4f1b7 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -38,10 +38,6 @@ #include "llluamanager.h" -#if LL_WINDOWS -#pragma comment(lib, "liblua54.a") -#endif - LLFloaterLUADebug::LLFloaterLUADebug(const LLSD &key) : LLFloater(key) diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 0475122832..abef3ce368 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -80,10 +80,6 @@ extern "C" #include <string_view> #include <vector> -#if LL_WINDOWS -#pragma comment(lib, "liblua54.a") -#endif - std::string lua_tostdstring(lua_State* L, int index); void lua_pushstdstring(lua_State* L, const std::string& str); LLSD lua_tollsd(lua_State* L, int index); -- cgit v1.2.3 From 0a731cd765cb05820e5e08956ba66cc85e987d3c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 9 Nov 2023 13:39:03 +0200 Subject: DRTVWR-589 - don't prevent mangling names as we use C++ lib --- indra/newview/llluamanager.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index abef3ce368..2bdf4fd0b0 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -64,12 +64,9 @@ extern LLUIListener sUIListener; #include <boost/algorithm/string/replace.hpp> -extern "C" -{ #include "lua/lua.h" #include "lua/lauxlib.h" #include "lua/lualib.h" -} #include <algorithm> #include <cstdlib> // std::rand() -- cgit v1.2.3 From 9cfe9e8f78a22d78004d1549bfaaf313bc645e1a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 5 Jan 2024 14:11:17 +0200 Subject: DRTVWR-589: Post-merge fix --- indra/newview/llfloaterluadebug.cpp | 2 +- indra/newview/llinventorygallery.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 32e9e4f1b7..64f169777d 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -87,7 +87,7 @@ void LLFloaterLUADebug::onExecuteClicked() void LLFloaterLUADebug::onBtnBrowse() { - (new LLFilePickerReplyThread(boost::bind(&LLFloaterLUADebug::runSelectedScript, this, _1), LLFilePicker::FFLOAD_LUA, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterLUADebug::runSelectedScript, this, _1), LLFilePicker::FFLOAD_LUA, false); } void LLFloaterLUADebug::onBtnRun() diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 8e7c97b6d5..68581d04eb 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2421,7 +2421,7 @@ void LLInventoryGallery::startDrag() ids.push_back(selected_id); } } - LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, src); + LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT); } bool LLInventoryGallery::areViewsInitialized() -- cgit v1.2.3 From 81e1963f57d3a8a189cc78beb9c6acee1b0e129b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 26 Jan 2024 16:49:19 +0200 Subject: DRTVWR-589: update to start using Luau libs --- indra/newview/CMakeLists.txt | 1 - indra/newview/llfloaterluadebug.h | 7 ++- indra/newview/llluamanager.cpp | 114 ++++++++++++++++++++++++++------------ indra/newview/viewer_manifest.py | 3 - 4 files changed, 84 insertions(+), 41 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b45841eb6b..ba2f252593 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1729,7 +1729,6 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/openjp2.dll ${SHARED_LIB_STAGING_DIR}/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/uriparser.dll - ${SHARED_LIB_STAGING_DIR}/lua54.dll #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index fd61e29ebe..1e26828c83 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -31,9 +31,10 @@ extern "C" { -#include "lua/lua.h" -#include "lua/lauxlib.h" -#include "lua/lualib.h" +#include "luau/luacode.h" +#include "luau/lua.h" +#include "luau/luaconf.h" +#include "luau/lualib.h" } class LLLineEditor; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 2bdf4fd0b0..49bc83c66b 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -64,9 +64,21 @@ extern LLUIListener sUIListener; #include <boost/algorithm/string/replace.hpp> -#include "lua/lua.h" -#include "lua/lauxlib.h" -#include "lua/lualib.h" +#include "luau/luacode.h" +#include "luau/lua.h" +#include "luau/luaconf.h" +#include "luau/lualib.h" + +#if LL_WINDOWS +#pragma comment(lib, "Luau.Compiler.lib") +#pragma comment(lib, "Luau.Ast.lib") +#pragma comment(lib, "Luau.CodeGen.lib") +#pragma comment(lib, "Luau.Config.lib") +#pragma comment(lib, "Luau.VM.lib") +#endif + +#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) +#define lua_rawlen lua_objlen #include <algorithm> #include <cstdlib> // std::rand() @@ -289,9 +301,10 @@ int name##_::call(lua_State* L) // ... supply method body here, referencing 'L' ... // } +/* // This function consumes ALL Lua stack arguments and returns concatenated // message string -std::string lua_print_msg(lua_State* L, const std::string_view& level) +std::string lua_print_msg_args(lua_State* L, const std::string_view& level) { // On top of existing Lua arguments, push 'where' info luaL_checkstack(L, 1, nullptr); @@ -329,6 +342,20 @@ std::string lua_print_msg(lua_State* L, const std::string_view& level) LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); return msg; } +*/ + +std::string lua_print_msg(lua_State *L, const std::string_view &level) +{ + lua_getglobal(L, "tostring"); + + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, 1); /* value to print */ + lua_call(L, 1, 1); + std::string msg = lua_tostring(L, -1); + + LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); + return msg; +} lua_function(print_debug) { @@ -819,7 +846,8 @@ lua_function(listen_events) { if (! lua_isfunction(L, 1)) { - return luaL_typeerror(L, 1, "function"); + luaL_typeerror(L, 1, "function"); + return 0; } luaL_checkstack(L, 2, nullptr); @@ -829,7 +857,7 @@ lua_function(listen_events) // suspended) coroutine thread. // Registry table is at pseudo-index LUA_REGISTRYINDEX // Main thread is at registry key LUA_RIDX_MAINTHREAD - auto regtype{ lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD) }; + auto regtype {lua_rawgeti(L, LUA_REGISTRYINDEX, 1 /*LUA_RIDX_MAINTHREAD*/)}; // Not finding the main thread at the documented place isn't a user error, // it's a Problem llassert_always(regtype == LUA_TTHREAD); @@ -996,15 +1024,25 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn lua_register(L, "sleep", LUA_sleep_func); - if (L.checkLua(luaL_dofile(L, filename.c_str()))) + llifstream in_file; + in_file.open(filename.c_str()); + + if (in_file.is_open()) { - lua_getglobal(L, "call_once_func"); - if (lua_isfunction(L, -1)) - { - // call call_once_func(), setting internal error message if - // error - L.checkLua(lua_pcall(L, 0, 0, 0)); - } + std::string text((std::istreambuf_iterator<char>(in_file)), std::istreambuf_iterator<char>()); + + size_t bytecodeSize = 0; + char *bytecode = luau_compile(text.c_str(), text.length(), NULL, &bytecodeSize); + L.checkLua(luau_load(L, desc.c_str(), bytecode, bytecodeSize, 0)); + free(bytecode); + + L.checkLua(lua_pcall(L, 0, 0, 0)); + + in_file.close(); + } + else + { + LL_WARNS("Lua") << "unable to open script file '" << filename << "'" << LL_ENDL; } }); } @@ -1024,7 +1062,12 @@ void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) LLCoros::instance().launch(desc, [desc, cmd, cb]() { LuaState L(desc, cb); - L.checkLua(luaL_dostring(L, cmd.c_str())); + + size_t bytecodeSize = 0; + char *bytecode = luau_compile(cmd.c_str(), cmd.length(), NULL, &bytecodeSize); + L.checkLua(luau_load(L, desc.c_str(), bytecode, bytecodeSize, 0)); + free(bytecode); + L.checkLua(lua_pcall(L, 0, 0, 0)); }); } @@ -1104,8 +1147,8 @@ public: case LUA_TUSERDATA: { - const size_t maxlen = 20; - size_t binlen{ lua_rawlen(self.L, self.index) }; + const S32 maxlen = 20; + S32 binlen{ lua_rawlen(self.L, self.index) }; LLSD::Binary binary(std::min(maxlen, binlen)); std::memcpy(binary.data(), lua_touserdata(self.L, self.index), binary.size()); out << LL::hexdump(binary); @@ -1333,7 +1376,7 @@ LLSD lua_tollsd(lua_State* L, int index) // operator is truthful, avoid allocations while we grow the keys // vector. Even if it's not, we can still grow the vector, albeit // a little less efficiently. - keys.reserve(luaL_len(L, index)); + keys.reserve(lua_objlen(L, index)); do { auto arraykeytype{ lua_type(L, -2) }; @@ -1347,12 +1390,13 @@ LLSD lua_tollsd(lua_State* L, int index) { // key isn't an integer - this doesn't fit our LLSD // array constraints - return luaL_error(L, "Expected integer array key, got %f instead", - lua_tonumber(L, -2)); + luaL_error(L, "Expected integer array key, got %f instead", lua_tonumber(L, -2)); + return 0; } if (intkey < 1) { - return luaL_error(L, "array key %d out of bounds", int(intkey)); + luaL_error(L, "array key %d out of bounds", int(intkey)); + return 0; } keys.push_back(LLSD::Integer(intkey)); @@ -1361,12 +1405,12 @@ LLSD lua_tollsd(lua_State* L, int index) case LUA_TSTRING: // break out strings specially to report the value - return luaL_error(L, "Cannot convert string array key '%s' to LLSD", - lua_tostring(L, -2)); + luaL_error(L, "Cannot convert string array key '%s' to LLSD", lua_tostring(L, -2)); + return 0; default: - return luaL_error(L, "Cannot convert %s array key to LLSD", - lua_typename(L, arraykeytype)); + luaL_error(L, "Cannot convert %s array key to LLSD", lua_typename(L, arraykeytype)); + return 0; } // remove value, keep key for next iteration @@ -1378,8 +1422,8 @@ LLSD lua_tollsd(lua_State* L, int index) size_t array_max{ 10000 }; if (keys.size() > array_max) { - return luaL_error(L, "Conversion from Lua to LLSD array limited to %d entries", - int(array_max)); + luaL_error(L, "Conversion from Lua to LLSD array limited to %d entries", int(array_max)); + return 0; } // We know the smallest key is >= 1. Check the largest. We also // know the vector is NOT empty, else we wouldn't have gotten here. @@ -1389,7 +1433,8 @@ LLSD lua_tollsd(lua_State* L, int index) { // Looks like we've gone beyond intentional array gaps into // crazy key territory. - return luaL_error(L, "Gaps in Lua table too large for conversion to LLSD array"); + luaL_error(L, "Gaps in Lua table too large for conversion to LLSD array"); + return 0; } LL_DEBUGS("Lua") << "collected " << keys.size() << " keys, max " << highkey << LL_ENDL; // right away expand the result array to the size we'll need @@ -1420,8 +1465,8 @@ LLSD lua_tollsd(lua_State* L, int index) auto mapkeytype{ lua_type(L, -2) }; if (mapkeytype != LUA_TSTRING) { - return luaL_error(L, "Cannot convert %s map key to LLSD", - lua_typename(L, mapkeytype)); + luaL_error(L, "Cannot convert %s map key to LLSD", lua_typename(L, mapkeytype)); + return 0; } auto key{ lua_tostdstring(L, -2) }; @@ -1436,8 +1481,8 @@ LLSD lua_tollsd(lua_State* L, int index) default: // First Lua key isn't number or string: sorry - return luaL_error(L, "Cannot convert %s table key to LLSD", - lua_typename(L, firstkeytype)); + luaL_error(L, "Cannot convert %s table key to LLSD", lua_typename(L, firstkeytype)); + return 0; } } @@ -1445,7 +1490,8 @@ LLSD lua_tollsd(lua_State* L, int index) // Other Lua entities (e.g. function, C function, light userdata, // thread, userdata) are not convertible to LLSD, indicating a coding // error in the caller. - return luaL_error(L, "Cannot convert type %s to LLSD", luaL_typename(L, index)); + luaL_error(L, "Cannot convert type %s to LLSD", luaL_typename(L, index)); + return 0; } } @@ -1505,7 +1551,7 @@ void lua_pushllsd(lua_State* L, const LLSD& data) // push new array value: table at -2, value at -1 lua_pushllsd(L, item); // pop value, assign table[key] = value - lua_seti(L, -2, ++key); + lua_rawseti(L, -2, ++key); } break; } diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 98240d3a78..1fa4df1682 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -565,9 +565,6 @@ class Windows_x86_64_Manifest(ViewerManifest): # Uriparser self.path("uriparser.dll") - # lua libs - self.path("lua54.dll") - # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx self.path("msvcp140.dll") -- cgit v1.2.3 From 2acb8bdf937dda337a591caa227d604efec5ca4a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 29 Jan 2024 20:50:30 +0200 Subject: DRTVWR-589: get rid of pragma and update windows libs --- indra/newview/llfloaterluadebug.cpp | 5 ----- indra/newview/llluamanager.cpp | 8 -------- 2 files changed, 13 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 64f169777d..58639490db 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -63,11 +63,6 @@ BOOL LLFloaterLUADebug::postBuild() getChild<LLButton>("browse_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnBrowse, this)); getChild<LLButton>("run_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnRun, this)); -#if !LL_WINDOWS - getChild<LLButton>("execute_btn")->setEnabled(false); - getChild<LLButton>("browse_btn")->setEnabled(false); -#endif - return TRUE; } diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 49bc83c66b..09ca6e10a7 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -69,14 +69,6 @@ extern LLUIListener sUIListener; #include "luau/luaconf.h" #include "luau/lualib.h" -#if LL_WINDOWS -#pragma comment(lib, "Luau.Compiler.lib") -#pragma comment(lib, "Luau.Ast.lib") -#pragma comment(lib, "Luau.CodeGen.lib") -#pragma comment(lib, "Luau.Config.lib") -#pragma comment(lib, "Luau.VM.lib") -#endif - #define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) #define lua_rawlen lua_objlen -- cgit v1.2.3 From ab1f2c2f6f9b854b95db3733fd6ff6d02e677ebd Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 30 Jan 2024 15:44:08 +0200 Subject: strip lua testing functions --- indra/newview/llluamanager.cpp | 443 +---------------------------------------- 1 file changed, 1 insertion(+), 442 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 09ca6e10a7..3e3ce45cb0 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -40,22 +40,8 @@ // skip all these link dependencies for integration testing #ifndef LL_TEST -#include "llagent.h" -#include "llappearancemgr.h" -#include "llcallbacklist.h" -#include "llfloaterreg.h" -#include "llfloaterimnearbychat.h" -#include "llfloatersidepanelcontainer.h" -#include "llnotificationsutil.h" -#include "llvoavatarself.h" -#include "llviewermenu.h" -#include "llviewermenufile.h" -#include "llviewerwindow.h" #include "lluilistener.h" -#include "llanimationstates.h" -#include "llinventoryfunctions.h" -#include "lltoolplacer.h" -#include "llviewerregion.h" +#include "llviewercontrol.h" // FIXME extremely hacky way to get to the UI Listener framework. There's // a cleaner way. @@ -369,433 +355,6 @@ lua_function(print_warning) } #ifndef LL_TEST -lua_function(avatar_sit) -{ - gAgent.sitDown(); - return 0; -} - -lua_function(avatar_stand) -{ - gAgent.standUp(); - return 0; -} - -lua_function(nearby_chat_send) -{ - std::string msg(lua_tostring(L, 1)); - LLFloaterIMNearbyChat *nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); - nearby_chat->sendChatFromViewer(msg, CHAT_TYPE_NORMAL, gSavedSettings.getBOOL("PlayChatAnim")); - - lua_pop(L, 1); - return 0; -} - -lua_function(wear_by_name) -{ - std::string folder_name(lua_tostring(L, 1)); - LLAppearanceMgr::instance().wearOutfitByName(folder_name); - - lua_pop(L, 1); - return 0; -} - -lua_function(open_floater) -{ - std::string floater_name(lua_tostring(L, 1)); - - LLSD key; - if (floater_name == "profile") - { - key["id"] = gAgentID; - } - LLFloaterReg::showInstance(floater_name, key); - - lua_pop(L, 1); - return 0; -} - -lua_function(close_floater) -{ - std::string floater_name(lua_tostring(L, 1)); - - LLSD key; - if (floater_name == "profile") - { - key["id"] = gAgentID; - } - LLFloaterReg::hideInstance(floater_name, key); - - lua_pop(L, 1); - return 0; -} - -lua_function(close_all_floaters) -{ - close_all_windows(); - return 0; -} - -lua_function(click_child) -{ - std::string parent_name(lua_tostring(L, 1)); - std::string child_name(lua_tostring(L, 2)); - - LLFloater *floater = LLFloaterReg::findInstance(parent_name); - LLUICtrl *child = floater->getChild<LLUICtrl>(child_name, true); - child->onCommit(); - - lua_pop(L, 2); - return 0; -} - -lua_function(snapshot_to_file) -{ - std::string filename(lua_tostring(L, 1)); - - //don't take snapshot from coroutine - doOnIdleOneTime([filename]() - { - gViewerWindow->saveSnapshot(filename, - gViewerWindow->getWindowWidthRaw(), - gViewerWindow->getWindowHeightRaw(), - gSavedSettings.getBOOL("RenderUIInSnapshot"), - gSavedSettings.getBOOL("RenderHUDInSnapshot"), - FALSE, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - }); - - lua_pop(L, 1); - return 0; -} - -lua_function(open_wearing_tab) -{ - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "now_wearing")); - return 0; -} - -lua_function(set_debug_setting_bool) -{ - std::string setting_name(lua_tostring(L, 1)); - bool value(lua_toboolean(L, 2)); - - gSavedSettings.setBOOL(setting_name, value); - lua_pop(L, 2); - return 0; -} - -lua_function(get_avatar_name) -{ - std::string name = gAgentAvatarp->getFullname(); - luaL_checkstack(L, 1, nullptr); - lua_pushstdstring(L, name); - return 1; -} - -lua_function(is_avatar_flying) -{ - luaL_checkstack(L, 1, nullptr); - lua_pushboolean(L, gAgent.getFlying()); - return 1; -} - -lua_function(play_animation) -{ - // on exit, pop all passed arguments, so always return 0 - LuaPopper popper(L, lua_gettop(L)); - - std::string anim_name = lua_tostring(L,1); - - EAnimRequest req = ANIM_REQUEST_START; - if (lua_gettop(L) > 1) - { - req = (EAnimRequest) (int) lua_tonumber(L, 2); - } - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameItemCollector has_name(anim_name); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - for (auto& item: item_array) - { - if (item->getType() == LLAssetType::AT_ANIMATION) - { - LLUUID anim_id = item->getAssetUUID(); - LL_INFOS() << "Playing animation " << anim_id << LL_ENDL; - gAgent.sendAnimationRequest(anim_id, req); - return 0; - } - } - LL_WARNS() << "No animation found for name " << anim_name << LL_ENDL; - - return 0; -} - -lua_function(env_setting_event) -{ - handle_env_setting_event(lua_tostring(L, 1)); - lua_pop(L, 1); - return 0; -} - -void handle_notification_dialog(const LLSD ¬ification, const LLSD &response, lua_State *L, std::string response_cb) -{ - if (!response_cb.empty()) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - luaL_checkstack(L, 1, nullptr); - lua_pushinteger(L, option); - lua_setglobal(L, response_cb.c_str()); - } -} - -lua_function(show_notification) -{ - std::string notification(lua_tostring(L, 1)); - - if (lua_type(L, 2) == LUA_TTABLE) - { - LLSD args = lua_tollsd(L, 2); - - std::string response_cb; - if (lua_type(L, 3) == LUA_TSTRING) - { - response_cb = lua_tostring(L, 3); - } - - LLNotificationsUtil::add(notification, args, LLSD(), boost::bind(handle_notification_dialog, _1, _2, L, response_cb)); - } - else if (lua_type(L, 2) == LUA_TSTRING) - { - std::string response_cb = lua_tostring(L, 2); - LLNotificationsUtil::add(notification, LLSD(), LLSD(), boost::bind(handle_notification_dialog, _1, _2, L, response_cb)); - } - else - { - LLNotificationsUtil::add(notification); - } - - lua_settop(L, 0); - return 0; -} - -lua_function(add_menu_item) -{ - std::string menu(lua_tostring(L, 1)); - if (lua_type(L, 2) == LUA_TTABLE) - { - LLSD args = lua_tollsd(L, 2); - - LLMenuItemCallGL::Params item_params; - item_params.name = args["name"]; - item_params.label = args["label"]; - - LLUICtrl::CommitCallbackParam item_func; - item_func.function_name = args["function"]; - if (args.has("parameter")) - { - item_func.parameter = args["parameter"]; - } - item_params.on_click = item_func; - - LLMenuItemCallGL *menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); - gMenuBarView->findChildMenuByName(menu, true)->append(menu_item); - } - - lua_settop(L, 0); - return 0; -} - -lua_function(add_menu_separator) -{ - std::string menu(lua_tostring(L, 1)); - gMenuBarView->findChildMenuByName(menu, true)->addSeparator(); - - lua_pop(L, 1); - return 0; -} - -lua_function(add_menu) -{ - if (lua_type(L, 1) == LUA_TTABLE) - { - LLSD args = lua_tollsd(L, 1); - - LLMenuGL::Params item_params; - item_params.name = args["name"]; - item_params.label = args["label"]; - item_params.can_tear_off = args["tear_off"]; - - LLMenuGL *menu = LLUICtrlFactory::create<LLMenuGL>(item_params); - gMenuBarView->appendMenu(menu); - } - - lua_settop(L, 0); - return 0; -} - -lua_function(add_branch) -{ - std::string menu(lua_tostring(L, 1)); - if (lua_type(L, 2) == LUA_TTABLE) - { - LLSD args = lua_tollsd(L, 2); - - LLMenuGL::Params item_params; - item_params.name = args["name"]; - item_params.label = args["label"]; - item_params.can_tear_off = args["tear_off"]; - - LLMenuGL *branch = LLUICtrlFactory::create<LLMenuGL>(item_params); - gMenuBarView->findChildMenuByName(menu, true)->appendMenu(branch); - } - - lua_settop(L, 0); - return 0; -} - -// rez_prim({x, y}, prim_type) -// avatar is the reference point -lua_function(rez_prim) -{ - lua_rawgeti(L, 1, 1); - F32 x = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_rawgeti(L, 1, 2); - F32 y = lua_tonumber(L, -1); - lua_pop(L, 1); - - S32 type(lua_tonumber(L, 2)); // primitive shapes 1-8 - - LLVector3 obj_pos = gAgent.getPositionAgent() + LLVector3(x, y, -0.5); - bool res = LLToolPlacer::rezNewObject(type, NULL, 0, TRUE, gAgent.getPositionAgent(), obj_pos, gAgent.getRegion(), 0); - - LL_INFOS() << "Rezing a prim: type " << LLPrimitive::pCodeToString(type) << ", coordinates: " << obj_pos << " Success: " << res << LL_ENDL; - - lua_pop(L, lua_gettop(L)); - return 0; -} - -// rez_prim2({x, y,z}, prim_type) -// avatar is the reference point -lua_function(rez_prim2) -{ - luaL_checktype(L, 1, LUA_TTABLE); - S32 type(lua_tonumber(L,2)); - lua_pop(L,1); - - lua_pushinteger(L, 1); - lua_gettable(L, -2); - F32 x = lua_tonumber(L,-1); - lua_pop(L,1); - - lua_pushinteger(L, 2); - lua_gettable(L, -2); - F32 y = lua_tonumber(L,-1); - lua_pop(L,1); - - lua_pushinteger(L, 3); - lua_gettable(L, -2); - F32 z = lua_tonumber(L,-1); - lua_pop(L,1); - - LL_INFOS() << "x " << x << " y " << y << " z " << z << " type " << type << LL_ENDL; - - LLVector3 obj_pos = gAgent.getPositionAgent() + LLVector3(x, y, z); - bool res = LLToolPlacer::rezNewObject(type, NULL, 0, TRUE, gAgent.getPositionAgent(), obj_pos, gAgent.getRegion(), 0); - - LL_INFOS() << "Rezing a prim: type " << LLPrimitive::pCodeToString(type) << ", coordinates: " << obj_pos << " Success: " << res << LL_ENDL; - - lua_settop(L, 0); - return 0; -} - - -void move_to_dest(const LLVector3d &target_global, lua_State *L, std::string response_cb) -{ - struct Data - { - lua_State *L; - std::string response_cb; - }; - - Data *data = new Data(); - data->L = L; - if (!response_cb.empty()) - { - data->response_cb = response_cb; - } - - auto handle_dest_reached = [](BOOL success, void *user_data) - { - Data *cb_data = static_cast<Data *>(user_data); - if (!cb_data->response_cb.empty()) - { - S32 result = success ? 1 : -1; - lua_pushinteger(cb_data->L, result); - lua_setglobal(cb_data->L, cb_data->response_cb.c_str()); - } - }; - - gAgent.startAutoPilotGlobal(target_global, std::string(), NULL, handle_dest_reached, data, 0.f, 0.03f, FALSE); -} - -// move_by({x,y}, "lua_cb_func") -// avatar is the reference point -lua_function(move_by) -{ - lua_rawgeti(L, 1, 1); - F32 x = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_rawgeti(L, 1, 2); - F32 y = lua_tonumber(L, -1); - lua_pop(L, 1); - - LLVector3d dest = gAgent.getRegion()->getPosGlobalFromRegion(gAgent.getPositionAgent() + LLVector3(x, y, 0)); - - std::string response_cb; - if (lua_type(L, 2) == LUA_TSTRING) - { - response_cb = lua_tostring(L, 2); - } - move_to_dest(dest, L, response_cb); - - lua_settop(L, 0); - return 0; -} - -// move_to({x,y,z}, "lua_cb_func") -// region coordinates are used -lua_function(move_to) -{ - lua_rawgeti(L, 1, 1); - F32 x = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_rawgeti(L, 1, 2); - F32 y = lua_tonumber(L, -1); - lua_rawgeti(L, 1, 3); - F32 z = lua_tonumber(L, -1); - lua_pop(L, 1); - - LLVector3d dest = gAgent.getRegion()->getPosGlobalFromRegion(LLVector3(x, y, z)); - - std::string response_cb; - if (lua_type(L, 2) == LUA_TSTRING) - { - response_cb = lua_tostring(L, 2); - } - move_to_dest(dest, L, response_cb); - - lua_settop(L, 0); - return 0; -} lua_function(run_ui_command) { -- cgit v1.2.3 From f664c2ea26fb63f162f3d988b6d00f1483be5d45 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 6 Feb 2024 14:49:45 -0500 Subject: Break out lua_function.h,.cpp and lualistener.h,.cpp. The intention is to decentralize Luau entry points into our C++ code, permitting a given entry point to be added to the .cpp file that already deals with that class or functional area. Continuing to add every such entry point to llluamanager.cpp doesn't scale well. Extract LuaListener class from llluamanager.cpp to its own header and .cpp file. Extract from llluamanager into lua_function.h (and .cpp) declarations useful for adding a lua_function Luau entry point, e.g.: lua_register() lua_rawlen() lua_tostdstring() lua_pushstdstring() lua_tollsd() lua_pushllsd() LuaPopper lua_function() and LuaFunction class LuaState lua_what lua_stack DebugExit --- indra/newview/llluamanager.cpp | 798 +---------------------------------------- 1 file changed, 6 insertions(+), 792 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 3e3ce45cb0..596d8cab56 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -28,14 +28,10 @@ #include "llviewerprecompiledheaders.h" #include "llluamanager.h" -#include "hexdump.h" #include "llerror.h" #include "lleventcoro.h" -#include "lleventfilter.h" -#include "llevents.h" -#include "llinstancetracker.h" -#include "llleaplistener.h" -#include "lluuid.h" +#include "lua_function.h" +#include "lualistener.h" #include "stringize.h" // skip all these link dependencies for integration testing @@ -55,230 +51,10 @@ extern LLUIListener sUIListener; #include "luau/luaconf.h" #include "luau/lualib.h" -#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) -#define lua_rawlen lua_objlen - -#include <algorithm> -#include <cstdlib> // std::rand() -#include <cstring> // std::memcpy() -#include <map> -#include <memory> // std::unique_ptr #include <sstream> #include <string_view> #include <vector> -std::string lua_tostdstring(lua_State* L, int index); -void lua_pushstdstring(lua_State* L, const std::string& str); -LLSD lua_tollsd(lua_State* L, int index); -void lua_pushllsd(lua_State* L, const LLSD& data); - -/** - * LuaListener is based on LLLeap. It serves an analogous function. - * - * Each LuaListener instance has an int key, generated randomly to - * inconvenience malicious Lua scripts wanting to mess with others. The idea - * is that a given lua_State stores in its Registry: - * - "event.listener": the int key of the corresponding LuaListener, if any - * - "event.function": the Lua function to be called with incoming events - * The original thought was that LuaListener would itself store the Lua - * function -- but surprisingly, there is no C/C++ type in the API that stores - * a Lua function. - * - * (We considered storing in "event.listener" the LuaListener pointer itself - * as a light userdata, but the problem would be if Lua code overwrote that. - * We want to prevent any Lua script from crashing the viewer, intentionally - * or otherwise. Safer to use a key lookup.) - * - * Like LLLeap, each LuaListener instance also has an associated - * LLLeapListener to respond to LLEventPump management commands. - */ -class LuaListener: public LLInstanceTracker<LuaListener, int> -{ - using super = LLInstanceTracker<LuaListener, int>; -public: - LuaListener(lua_State* L): - super(getUniqueKey()), - mListener( - new LLLeapListener( - [L](LLEventPump& pump, const std::string& listener) - { return connect(L, pump, listener); })) - { - mReplyConnection = connect(L, mReplyPump, "LuaListener"); - } - - LuaListener(const LuaListener&) = delete; - LuaListener& operator=(const LuaListener&) = delete; - - ~LuaListener() - { - LL_DEBUGS("Lua") << "~LuaListener('" << mReplyPump.getName() << "')" << LL_ENDL; - } - - std::string getReplyName() const { return mReplyPump.getName(); } - std::string getCommandName() const { return mListener->getPumpName(); } - -private: - static int getUniqueKey() - { - // Find a random key that does NOT already correspond to a LuaListener - // instance. Passing a duplicate key to LLInstanceTracker would do Bad - // Things. - int key; - do - { - key = std::rand(); - } while (LuaListener::getInstance(key)); - // This is theoretically racy, if we were instantiating new - // LuaListeners on multiple threads. Don't. - return key; - } - - static LLBoundListener connect(lua_State* L, LLEventPump& pump, const std::string& listener) - { - return pump.listen( - listener, - [L, pumpname=pump.getName()](const LLSD& data) - { return call_lua(L, pumpname, data); }); - } - - static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data) - { - LL_INFOS("Lua") << "LuaListener::call_lua('" << pump << "', " << data << ")" << LL_ENDL; - if (! lua_checkstack(L, 3)) - { - LL_WARNS("Lua") << "Cannot extend Lua stack to call listen_events() callback" - << LL_ENDL; - return false; - } - // push the registered Lua callback function stored in our registry as - // "event.function" - lua_getfield(L, LUA_REGISTRYINDEX, "event.function"); - llassert(lua_isfunction(L, -1)); - // pass pump name - lua_pushstdstring(L, pump); - // then the data blob - lua_pushllsd(L, data); - // call the registered Lua listener function; allow it to return bool; - // no message handler - auto status = lua_pcall(L, 2, 1, 0); - bool result{ false }; - if (status != LUA_OK) - { - LL_WARNS("Lua") << "Error in listen_events() callback: " - << lua_tostdstring(L, -1) << LL_ENDL; - } - else - { - result = lua_toboolean(L, -1); - } - // discard either the error message or the bool return value - lua_pop(L, 1); - return result; - } - -#ifndef LL_TEST - LLEventStream mReplyPump{ LLUUID::generateNewID().asString() }; -#else - LLEventLogProxyFor<LLEventStream> mReplyPump{ "luapump", false }; -#endif - LLTempBoundListener mReplyConnection; - std::unique_ptr<LLLeapListener> mListener; -}; - -/** - * LuaPopper is an RAII struct whose role is to pop some number of entries - * from the Lua stack if the calling function exits early. - */ -struct LuaPopper -{ - LuaPopper(lua_State* L, int count): - mState(L), - mCount(count) - {} - - LuaPopper(const LuaPopper&) = delete; - LuaPopper& operator=(const LuaPopper&) = delete; - - ~LuaPopper() - { - if (mCount) - { - lua_pop(mState, mCount); - } - } - - void disarm() { set(0); } - void set(int count) { mCount = count; } - - lua_State* mState; - int mCount; -}; - -/** - * LuaFunction is a base class containing a static registry of its static - * subclass call() methods. call() is NOT virtual: instead, each subclass - * constructor passes a pointer to its distinct call() method to the base- - * class constructor, along with a name by which to register that method. - * - * The init() method walks the registry and registers each such name with the - * passed lua_State. - */ -class LuaFunction -{ -public: - LuaFunction(const std::string_view& name, lua_CFunction function) - { - getRegistry().emplace(name, function); - } - - static void init(lua_State* L) - { - for (const auto& pair: getRegistry()) - { - lua_register(L, pair.first.c_str(), pair.second); - } - } - - static lua_CFunction get(const std::string& key) - { - // use find() instead of subscripting to avoid creating an entry for - // unknown key - const auto& registry{ getRegistry() }; - auto found{ registry.find(key) }; - return (found == registry.end())? nullptr : found->second; - } - -private: - using Registry = std::map<std::string, lua_CFunction>; - static Registry& getRegistry() - { - // use a function-local static to ensure it's initialized - static Registry registry; - return registry; - } -}; - -/** - * lua_function(name) is a macro to facilitate defining C++ functions - * available to Lua. It defines a subclass of LuaFunction and declares a - * static instance of that subclass, thereby forcing the compiler to call its - * constructor at module initialization time. The constructor passes the - * stringized instance name to its LuaFunction base-class constructor, along - * with a pointer to the static subclass call() method. It then emits the - * call() method definition header, to be followed by a method body enclosed - * in curly braces as usual. - */ -#define lua_function(name) \ -static struct name##_ : public LuaFunction \ -{ \ - name##_(): LuaFunction(#name, &call) {} \ - static int call(lua_State* L); \ -} name; \ -int name##_::call(lua_State* L) -// { -// ... supply method body here, referencing 'L' ... -// } - /* // This function consumes ALL Lua stack arguments and returns concatenated // message string @@ -484,80 +260,6 @@ lua_function(await_event) return 1; } -/** - * RAII class to manage the lifespan of a lua_State - */ -class LuaState -{ -public: - LuaState(const std::string_view& desc, LLLUAmanager::script_finished_fn cb): - mDesc(desc), - mCallback(cb), - mState(luaL_newstate()) - { - luaL_openlibs(mState); - LuaFunction::init(mState); - // Try to make print() write to our log. - lua_register(mState, "print", LuaFunction::get("print_info")); - } - - LuaState(const LuaState&) = delete; - LuaState& operator=(const LuaState&) = delete; - - ~LuaState() - { - // Did somebody call listen_events() on this LuaState? - // That is, is there a LuaListener key in its registry? - auto keytype{ lua_getfield(mState, LUA_REGISTRYINDEX, "event.listener") }; - if (keytype == LUA_TNUMBER) - { - // We do have a LuaListener. Retrieve it. - int isint; - auto listener{ LuaListener::getInstance(lua_tointegerx(mState, -1, &isint)) }; - // pop the int "event.listener" key - lua_pop(mState, 1); - // if we got a LuaListener instance, destroy it - // (if (! isint), lua_tointegerx() returned 0, but key 0 might - // validly designate someone ELSE's LuaListener) - if (isint && listener) - { - auto lptr{ listener.get() }; - listener.reset(); - delete lptr; - } - } - - lua_close(mState); - - if (mCallback) - { - // mError potentially set by previous checkLua() call(s) - mCallback(mError); - } - } - - bool checkLua(int r) - { - if (r != LUA_OK) - { - mError = lua_tostring(mState, -1); - lua_pop(mState, 1); - - LL_WARNS() << mDesc << ": " << mError << LL_ENDL; - return false; - } - return true; - } - - operator lua_State*() const { return mState; } - -private: - std::string mDesc; - LLLUAmanager::script_finished_fn mCallback; - lua_State* mState; - std::string mError; -}; - void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb) { std::string desc{ stringize("runScriptFile('", filename, "')") }; @@ -580,16 +282,9 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn if (in_file.is_open()) { - std::string text((std::istreambuf_iterator<char>(in_file)), std::istreambuf_iterator<char>()); - - size_t bytecodeSize = 0; - char *bytecode = luau_compile(text.c_str(), text.length(), NULL, &bytecodeSize); - L.checkLua(luau_load(L, desc.c_str(), bytecode, bytecodeSize, 0)); - free(bytecode); - - L.checkLua(lua_pcall(L, 0, 0, 0)); - - in_file.close(); + std::string text{std::istreambuf_iterator<char>(in_file), + std::istreambuf_iterator<char>()}; + L.checkLua(lluau::dostring(L, desc, text)); } else { @@ -613,12 +308,7 @@ void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) LLCoros::instance().launch(desc, [desc, cmd, cb]() { LuaState L(desc, cb); - - size_t bytecodeSize = 0; - char *bytecode = luau_compile(cmd.c_str(), cmd.length(), NULL, &bytecodeSize); - L.checkLua(luau_load(L, desc.c_str(), bytecode, bytecodeSize, 0)); - free(bytecode); - L.checkLua(lua_pcall(L, 0, 0, 0)); + L.checkLua(lluau::dostring(L, desc, cmd)); }); } @@ -642,479 +332,3 @@ void LLLUAmanager::runScriptOnLogin() runScriptFile(filename); #endif // ! LL_TEST } - -std::string lua_tostdstring(lua_State* L, int index) -{ - size_t len; - const char* strval{ lua_tolstring(L, index, &len) }; - return { strval, len }; -} - -void lua_pushstdstring(lua_State* L, const std::string& str) -{ - luaL_checkstack(L, 1, nullptr); - lua_pushlstring(L, str.c_str(), str.length()); -} - -// Usage: std::cout << lua_what(L, stackindex) << ...; -// Reports on the Lua value found at the passed stackindex. -// If cast to std::string, returns the corresponding string value. -class lua_what -{ -public: - lua_what(lua_State* state, int idx): - L(state), - index(idx) - {} - - friend std::ostream& operator<<(std::ostream& out, const lua_what& self) - { - switch (lua_type(self.L, self.index)) - { - case LUA_TNONE: - // distinguish acceptable but non-valid index - out << "none"; - break; - - case LUA_TNIL: - out << "nil"; - break; - - case LUA_TBOOLEAN: - { - auto oldflags { out.flags() }; - out << std::boolalpha << lua_toboolean(self.L, self.index); - out.flags(oldflags); - break; - } - - case LUA_TNUMBER: - out << lua_tonumber(self.L, self.index); - break; - - case LUA_TSTRING: - out << std::quoted(lua_tostdstring(self.L, self.index)); - break; - - case LUA_TUSERDATA: - { - const S32 maxlen = 20; - S32 binlen{ lua_rawlen(self.L, self.index) }; - LLSD::Binary binary(std::min(maxlen, binlen)); - std::memcpy(binary.data(), lua_touserdata(self.L, self.index), binary.size()); - out << LL::hexdump(binary); - if (binlen > maxlen) - { - out << "...(" << (binlen - maxlen) << " more)"; - } - break; - } - - case LUA_TLIGHTUSERDATA: - out << lua_touserdata(self.L, self.index); - break; - - default: - // anything else, don't bother trying to report value, just type - out << lua_typename(self.L, lua_type(self.L, self.index)); - break; - } - return out; - } - - operator std::string() const { return stringize(*this); } - -private: - lua_State* L; - int index; -}; - -// Usage: std::cout << lua_stack(L) << ...; -// Reports on the contents of the Lua stack. -// If cast to std::string, returns the corresponding string value. -class lua_stack -{ -public: - lua_stack(lua_State* state): - L(state) - {} - - friend std::ostream& operator<<(std::ostream& out, const lua_stack& self) - { - const char* sep = "stack: ["; - for (int index = 1; index <= lua_gettop(self.L); ++index) - { - out << sep << lua_what(self.L, index); - sep = ", "; - } - out << ']'; - return out; - } - - operator std::string() const { return stringize(*this); } - -private: - lua_State* L; -}; - -// log exit from any block declaring an instance of DebugExit, regardless of -// how control leaves that block -struct DebugExit -{ - DebugExit(const std::string& name): mName(name) {} - DebugExit(const DebugExit&) = delete; - DebugExit& operator=(const DebugExit&) = delete; - ~DebugExit() - { - LL_DEBUGS("Lua") << "exit " << mName << LL_ENDL; - } - - std::string mName; -}; - -// By analogy with existing lua_tomumble() functions, return an LLSD object -// corresponding to the Lua object at stack index 'index' in state L. -// This function assumes that a Lua caller is fully aware that they're trying -// to call a viewer function. In other words, the caller must specifically -// construct Lua data convertible to LLSD. -// -// For proper error handling, we REQUIRE that the Lua runtime be compiled as -// C++ so errors are raised as C++ exceptions rather than as longjmp() calls: -// http://www.lua.org/manual/5.4/manual.html#4.4 -// "Internally, Lua uses the C longjmp facility to handle errors. (Lua will -// use exceptions if you compile it as C++; search for LUAI_THROW in the -// source code for details.)" -// Some blocks within this function construct temporary C++ objects in the -// expectation that these objects will be properly destroyed even if code -// reached by that block raises a Lua error. -LLSD lua_tollsd(lua_State* L, int index) -{ - LL_DEBUGS("Lua") << "lua_tollsd(" << index << ") of " << lua_gettop(L) << " stack entries: " - << lua_what(L, index) << LL_ENDL; - DebugExit log_exit("lua_tollsd()"); - switch (lua_type(L, index)) - { - case LUA_TNONE: - // Should LUA_TNONE be an error instead of returning isUndefined()? - case LUA_TNIL: - return {}; - - case LUA_TBOOLEAN: - return bool(lua_toboolean(L, index)); - - case LUA_TNUMBER: - { - // check if integer truncation leaves the number intact - int isint; - lua_Integer intval{ lua_tointegerx(L, index, &isint) }; - if (isint) - { - return LLSD::Integer(intval); - } - else - { - return lua_tonumber(L, index); - } - } - - case LUA_TSTRING: - return lua_tostdstring(L, index); - - case LUA_TUSERDATA: - { - LLSD::Binary binary(lua_rawlen(L, index)); - std::memcpy(binary.data(), lua_touserdata(L, index), binary.size()); - return binary; - } - - case LUA_TTABLE: - { - // A Lua table correctly constructed to convert to LLSD will have - // either consecutive integer keys starting at 1, which we represent - // as an LLSD array (with Lua key 1 at C++ index 0), or will have - // all string keys. - // - // In the belief that Lua table traversal skips "holes," that is, it - // doesn't report any key/value pair whose value is nil, we allow a - // table with integer keys >= 1 but with "holes." This produces an - // LLSD array with isUndefined() entries at unspecified keys. There - // would be no other way for a Lua caller to construct an - // isUndefined() LLSD array entry. However, to guard against crazy int - // keys, we forbid gaps larger than a certain size: crazy int keys - // could result in a crazy large contiguous LLSD array. - // - // Possible looseness could include: - // - A mix of integer and string keys could produce an LLSD map in - // which the integer keys are converted to string. (Key conversion - // must be performed in C++, not Lua, to avoid confusing - // lua_next().) - // - However, since in Lua t[0] and t["0"] are distinct table entries, - // do not consider converting numeric string keys to int to return - // an LLSD array. - // But until we get more experience with actual Lua scripts in - // practice, let's say that any deviation is a Lua coding error. - // An important property of the strict definition above is that most - // conforming data blobs can make a round trip across the language - // boundary and still compare equal. A non-conforming data blob would - // lose that property. - // Known exceptions to round trip identity: - // - Empty LLSD map and empty LLSD array convert to empty Lua table. - // But empty Lua table converts to isUndefined() LLSD object. - // - LLSD::Real with integer value returns as LLSD::Integer. - // - LLSD::UUID, LLSD::Date and LLSD::URI all convert to Lua string, - // and so return as LLSD::String. - // - Lua does not store any table key whose value is nil. An LLSD - // array with isUndefined() entries produces a Lua table with - // "holes" in the int key sequence; this converts back to an LLSD - // array containing corresponding isUndefined() entries -- except - // when one or more of the final entries isUndefined(). These are - // simply dropped, producing a shorter LLSD array than the original. - // - For the same reason, any keys in an LLSD map whose value - // isUndefined() are simply discarded in the converted Lua table. - // This converts back to an LLSD map lacking those keys. - // - If it's important to preserve the original length of an LLSD - // array whose final entries are undefined, or the full set of keys - // for an LLSD map some of whose values are undefined, store an - // LLSD::emptyArray() or emptyMap() instead. These will be - // represented in Lua as empty table, which should convert back to - // undefined LLSD. Naturally, though, those won't survive a second - // round trip. - - // This is the most important of the luaL_checkstack() calls because a - // deeply nested Lua structure will enter this case at each level, and - // we'll need another 2 stack slots to traverse each nested table. - luaL_checkstack(L, 2, nullptr); - // BEFORE we push nil to initialize the lua_next() traversal, convert - // 'index' to absolute! Our caller might have passed a relative index; - // we do, below: lua_tollsd(L, -1). If 'index' is -1, then when we - // push nil, what we find at index -1 is nil, not the table! - index = lua_absindex(L, index); - LL_DEBUGS("Lua") << "checking for empty table" << LL_ENDL; - lua_pushnil(L); // first key - LL_DEBUGS("Lua") << lua_stack(L) << LL_ENDL; - if (! lua_next(L, index)) - { - // it's a table, but the table is empty -- no idea if it should be - // modeled as empty array or empty map -- return isUndefined(), - // which can be consumed as either - LL_DEBUGS("Lua") << "empty table" << LL_ENDL; - return {}; - } - // key is at stack index -2, value at index -1 - // from here until lua_next() returns 0, have to lua_pop(2) if we - // return early - LuaPopper popper(L, 2); - // Remember the type of the first key - auto firstkeytype{ lua_type(L, -2) }; - LL_DEBUGS("Lua") << "table not empty, first key type " << lua_typename(L, firstkeytype) - << LL_ENDL; - switch (firstkeytype) - { - case LUA_TNUMBER: - { - // First Lua key is a number: try to convert table to LLSD array. - // This is tricky because we don't know in advance the size of the - // array. The Lua reference manual says that lua_rawlen() is the - // same as the length operator '#'; but the length operator states - // that it might stop at any "hole" in the subject table. - // Moreover, the Lua next() function (and presumably lua_next()) - // traverses a table in unspecified order, even for numeric keys - // (emphasized in the doc). - // Make a preliminary pass over the whole table to validate and to - // collect keys. - std::vector<LLSD::Integer> keys; - // Try to determine the length of the table. If the length - // operator is truthful, avoid allocations while we grow the keys - // vector. Even if it's not, we can still grow the vector, albeit - // a little less efficiently. - keys.reserve(lua_objlen(L, index)); - do - { - auto arraykeytype{ lua_type(L, -2) }; - switch (arraykeytype) - { - case LUA_TNUMBER: - { - int isint; - lua_Integer intkey{ lua_tointegerx(L, -2, &isint) }; - if (! isint) - { - // key isn't an integer - this doesn't fit our LLSD - // array constraints - luaL_error(L, "Expected integer array key, got %f instead", lua_tonumber(L, -2)); - return 0; - } - if (intkey < 1) - { - luaL_error(L, "array key %d out of bounds", int(intkey)); - return 0; - } - - keys.push_back(LLSD::Integer(intkey)); - break; - } - - case LUA_TSTRING: - // break out strings specially to report the value - luaL_error(L, "Cannot convert string array key '%s' to LLSD", lua_tostring(L, -2)); - return 0; - - default: - luaL_error(L, "Cannot convert %s array key to LLSD", lua_typename(L, arraykeytype)); - return 0; - } - - // remove value, keep key for next iteration - lua_pop(L, 1); - } while (lua_next(L, index) != 0); - popper.disarm(); - // Table keys are all integers: are they reasonable integers? - // Arbitrary max: may bite us, but more likely to protect us - size_t array_max{ 10000 }; - if (keys.size() > array_max) - { - luaL_error(L, "Conversion from Lua to LLSD array limited to %d entries", int(array_max)); - return 0; - } - // We know the smallest key is >= 1. Check the largest. We also - // know the vector is NOT empty, else we wouldn't have gotten here. - std::sort(keys.begin(), keys.end()); - LLSD::Integer highkey = *keys.rbegin(); - if ((highkey - LLSD::Integer(keys.size())) > 100) - { - // Looks like we've gone beyond intentional array gaps into - // crazy key territory. - luaL_error(L, "Gaps in Lua table too large for conversion to LLSD array"); - return 0; - } - LL_DEBUGS("Lua") << "collected " << keys.size() << " keys, max " << highkey << LL_ENDL; - // right away expand the result array to the size we'll need - LLSD result{ LLSD::emptyArray() }; - result[highkey - 1] = LLSD(); - // Traverse the table again, and this time populate result array. - lua_pushnil(L); // first key - while (lua_next(L, index)) - { - // key at stack index -2, value at index -1 - // We've already validated lua_tointegerx() for each key. - auto key{ lua_tointeger(L, -2) }; - LL_DEBUGS("Lua") << "key " << key << ':' << LL_ENDL; - // Don't forget to subtract 1 from Lua key for LLSD subscript! - result[LLSD::Integer(key) - 1] = lua_tollsd(L, -1); - // remove value, keep key for next iteration - lua_pop(L, 1); - } - return result; - } - - case LUA_TSTRING: - { - // First Lua key is a string: try to convert table to LLSD map - LLSD result{ LLSD::emptyMap() }; - do - { - auto mapkeytype{ lua_type(L, -2) }; - if (mapkeytype != LUA_TSTRING) - { - luaL_error(L, "Cannot convert %s map key to LLSD", lua_typename(L, mapkeytype)); - return 0; - } - - auto key{ lua_tostdstring(L, -2) }; - LL_DEBUGS("Lua") << "map key " << std::quoted(key) << ':' << LL_ENDL; - result[key] = lua_tollsd(L, -1); - // remove value, keep key for next iteration - lua_pop(L, 1); - } while (lua_next(L, index) != 0); - popper.disarm(); - return result; - } - - default: - // First Lua key isn't number or string: sorry - luaL_error(L, "Cannot convert %s table key to LLSD", lua_typename(L, firstkeytype)); - return 0; - } - } - - default: - // Other Lua entities (e.g. function, C function, light userdata, - // thread, userdata) are not convertible to LLSD, indicating a coding - // error in the caller. - luaL_error(L, "Cannot convert type %s to LLSD", luaL_typename(L, index)); - return 0; - } -} - -// By analogy with existing lua_pushmumble() functions, push onto state L's -// stack a Lua object corresponding to the passed LLSD object. -void lua_pushllsd(lua_State* L, const LLSD& data) -{ - // might need 2 slots for array or map - luaL_checkstack(L, 2, nullptr); - switch (data.type()) - { - case LLSD::TypeUndefined: - lua_pushnil(L); - break; - - case LLSD::TypeBoolean: - lua_pushboolean(L, data.asBoolean()); - break; - - case LLSD::TypeInteger: - lua_pushinteger(L, data.asInteger()); - break; - - case LLSD::TypeReal: - lua_pushnumber(L, data.asReal()); - break; - - case LLSD::TypeBinary: - { - auto binary{ data.asBinary() }; - std::memcpy(lua_newuserdata(L, binary.size()), - binary.data(), binary.size()); - break; - } - - case LLSD::TypeMap: - { - // push a new table with space for our non-array keys - lua_createtable(L, 0, data.size()); - for (const auto& pair: llsd::inMap(data)) - { - // push value -- so now table is at -2, value at -1 - lua_pushllsd(L, pair.second); - // pop value, assign to table[key] - lua_setfield(L, -2, pair.first.c_str()); - } - break; - } - - case LLSD::TypeArray: - { - // push a new table with space for array entries - lua_createtable(L, data.size(), 0); - lua_Integer key{ 0 }; - for (const auto& item: llsd::inArray(data)) - { - // push new array value: table at -2, value at -1 - lua_pushllsd(L, item); - // pop value, assign table[key] = value - lua_rawseti(L, -2, ++key); - } - break; - } - - case LLSD::TypeString: - case LLSD::TypeUUID: - case LLSD::TypeDate: - case LLSD::TypeURI: - default: - { - lua_pushstdstring(L, data.asString()); - break; - } - } -} -- cgit v1.2.3 From 5b0404961e35ecca46148b90f2c27aed1bad607f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Feb 2024 12:50:26 -0500 Subject: Add machinery to capture result of running a Lua script or snippet. Add LuaState::expr() that evaluates a Lua snippet and reports back any result (or error) left on the stack. Add LLLUAmanager::runScriptFile() and runScriptLine() overloads that accept a callback with an (int count, LLSD result) signature. The count disambiguates (error, no result, one result, array of results). Also add overloads that accept an existing LuaState instance. Also add waitScriptFile() and waitScriptLine() methods that pause the calling coroutine until the Lua script completes, and return its results. Instead of giving LuaState a description to use for all subsequent checkLua() calls, remove description from its constructor and data members. Move to expr() and checkLua() parameters: we want a description specific to each operation, rather than for the LuaState as a whole. This prepares for persistent LuaState instances. For now, the existing script_finished_fn semantics remain: the callback will be called only when the LuaState is destroyed. This may need to change as we migrate towards longer-lasting LuaState instances. Make lua_function(name) macro append suffixes to the name for both the LuaFunction subclass declaration and the instance declaration. This allows publishing a lua_function() name such as sleep(), which already has a different C++ declaration. Move the Lua sleep() entry point to a standalone lua_function(sleep), instead of a lambda in the body of runScriptFile(). --- indra/newview/llluamanager.cpp | 93 ++++++++++++++++++++++++++++++++++-------- indra/newview/llluamanager.h | 30 ++++++++++++-- 2 files changed, 103 insertions(+), 20 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 596d8cab56..44c7a6ba3b 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -28,6 +28,7 @@ #include "llviewerprecompiledheaders.h" #include "llluamanager.h" +#include "llcoros.h" #include "llerror.h" #include "lleventcoro.h" #include "lua_function.h" @@ -55,6 +56,14 @@ extern LLUIListener sUIListener; #include <string_view> #include <vector> +lua_function(sleep) +{ + F32 seconds = lua_tonumber(L, -1); + lua_pop(L, 1); + llcoro::suspendUntilTimeout(seconds); + return 0; +}; + /* // This function consumes ALL Lua stack arguments and returns concatenated // message string @@ -262,21 +271,34 @@ lua_function(await_event) void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb) { - std::string desc{ stringize("runScriptFile('", filename, "')") }; - LLCoros::instance().launch(desc, [desc, filename, cb]() - { - LuaState L(desc, cb); + // A script_finished_fn is used to initialize the LuaState. + // It will be called when the LuaState is destroyed. + LuaState L(cb); + runScriptFile(L, filename); +} - auto LUA_sleep_func = [](lua_State *L) - { - F32 seconds = lua_tonumber(L, -1); - lua_pop(L, 1); - llcoro::suspendUntilTimeout(seconds); - return 0; - }; +void LLLUAmanager::runScriptFile(const std::string& filename, script_result_fn cb) +{ + LuaState L; + // A script_result_fn will be called when LuaState::expr() completes. + runScriptFile(L, filename, cb); +} - lua_register(L, "sleep", LUA_sleep_func); +std::pair<int, LLSD> LLLUAmanager::waitScriptFile(LuaState& L, const std::string& filename) +{ + LLCoros::Promise<std::pair<int, LLSD>> promise; + auto future{ LLCoros::getFuture(promise) }; + runScriptFile(L, filename, + [&promise](int count, LLSD result) + { promise.set_value({ count, result }); }); + return future.get(); +} +void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, script_result_fn cb) +{ + std::string desc{ stringize("runScriptFile('", filename, "')") }; + LLCoros::instance().launch(desc, [&L, desc, filename, cb]() + { llifstream in_file; in_file.open(filename.c_str()); @@ -284,16 +306,50 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn { std::string text{std::istreambuf_iterator<char>(in_file), std::istreambuf_iterator<char>()}; - L.checkLua(lluau::dostring(L, desc, text)); + auto [count, result] = L.expr(desc, text); + if (cb) + { + cb(count, result); + } } else { - LL_WARNS("Lua") << "unable to open script file '" << filename << "'" << LL_ENDL; + auto msg{ stringize("unable to open script file '", filename, "'") }; + LL_WARNS("Lua") << msg << LL_ENDL; + if (cb) + { + cb(-1, msg); + } } }); } void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) +{ + // A script_finished_fn is used to initialize the LuaState. + // It will be called when the LuaState is destroyed. + LuaState L(cb); + runScriptLine(L, cmd); +} + +void LLLUAmanager::runScriptLine(const std::string& cmd, script_result_fn cb) +{ + LuaState L; + // A script_result_fn will be called when LuaState::expr() completes. + runScriptLine(L, cmd, cb); +} + +std::pair<int, LLSD> LLLUAmanager::waitScriptLine(LuaState& L, const std::string& cmd) +{ + LLCoros::Promise<std::pair<int, LLSD>> promise; + auto future{ LLCoros::getFuture(promise) }; + runScriptLine(L, cmd, + [&promise](int count, LLSD result) + { promise.set_value({ count, result }); }); + return future.get(); +} + +void LLLUAmanager::runScriptLine(LuaState& L, const std::string& cmd, script_result_fn cb) { // find a suitable abbreviation for the cmd string std::string_view shortcmd{ cmd }; @@ -305,10 +361,13 @@ void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) shortcmd = stringize(shortcmd.substr(0, shortlen), "..."); std::string desc{ stringize("runScriptLine('", shortcmd, "')") }; - LLCoros::instance().launch(desc, [desc, cmd, cb]() + LLCoros::instance().launch(desc, [&L, desc, cmd, cb]() { - LuaState L(desc, cb); - L.checkLua(lluau::dostring(L, desc, cmd)); + auto [count, result] = L.expr(desc, cmd); + if (cb) + { + cb(count, result); + } }); } diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 08d9876ce2..bed12e358a 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -27,19 +27,43 @@ #ifndef LL_LLLUAMANAGER_H #define LL_LLLUAMANAGER_H +#include "llsd.h" #include <functional> #include <string> +#include <utility> // std::pair + +class LuaState; class LLLUAmanager { public: + // Pass a callback with this signature to obtain the error message, if + // any, from running a script or source string. Empty msg means success. typedef std::function<void(std::string msg)> script_finished_fn; + // Pass a callback with this signature to obtain the result, if any, of + // running a script or source string. + // count < 0 means error, and result.asString() is the error message. + // count == 0 with result.isUndefined() means the script returned no results. + // count == 1 means the script returned one result. + // count > 1 with result.isArray() means the script returned multiple + // results, represented as the entries of the result array. + typedef std::function<void(int count, const LLSD& result)> script_result_fn; + + static void runScriptFile(const std::string &filename, script_finished_fn cb = {}); + static void runScriptFile(const std::string &filename, script_result_fn cb); + static void runScriptFile(LuaState& L, const std::string &filename, script_result_fn cb = {}); + // Run a Lua script file, and pause the calling coroutine until it completes. + // The return value is the (count, result) pair described above. + static std::pair<int, LLSD> waitScriptFile(LuaState& L, const std::string& filename); - static void runScriptFile(const std::string &filename, script_finished_fn cb = script_finished_fn()); - static void runScriptLine(const std::string &cmd, script_finished_fn cb = script_finished_fn()); + static void runScriptLine(const std::string &cmd, script_finished_fn cb = {}); + static void runScriptLine(const std::string &cmd, script_result_fn cb); + static void runScriptLine(LuaState& L, const std::string &cmd, script_result_fn cb = {}); + // Run a Lua expression string, and pause the calling coroutine until it completes. + // The return value is the (count, result) pair described above. + static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& cmd); static void runScriptOnLogin(); }; - #endif -- cgit v1.2.3 From 4ecfd706bce5c45556eaf2833f89fd9f2f5b07a9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Feb 2024 22:24:52 -0500 Subject: Add LLLUAmanager::startScriptFile(), startScriptLine() functions. Break out for LLLUAmanager consumers the promise/future semantics of waitScriptFile() and waitScriptLine(). startScriptMumble() uses runScriptMumble() to launch a coroutine to run the specified Lua script or chunk, providing an internal adapter callback to set a promise on completion. It then returns to its caller the future obtained from that promise. This allows a caller to call startScriptMumble(), run in parallel with the Lua coroutine for a while and then call get() on the returned future to wait for results. waitScriptMumble() is then trivially implemented using startScriptMumble(). Fix runScriptLine()'s logic to abbreviate the passed Lua chunk for use as the description. We were erroneously assigning back through a string_view of the parameter, which overwrote a temporary string in the argument list. With Lua 5.4, listen_events() tried to discover the main "thread" (Lua coroutine) associated with the current lua_State so we could call async callbacks on that thread. Luau doesn't seem to provide that feature, so run callbacks on whichever thread calls listen_events(). Reinstate original multi-argument lua_print_msg(), tweaked to avoid the Lua 5.4 lua_rotate() function, which is missing from Luau. --- indra/newview/llluamanager.cpp | 107 +++++++++++++++++++++-------------------- indra/newview/llluamanager.h | 25 ++++++++-- 2 files changed, 76 insertions(+), 56 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 44c7a6ba3b..fac66003a1 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -64,13 +64,13 @@ lua_function(sleep) return 0; }; -/* // This function consumes ALL Lua stack arguments and returns concatenated // message string -std::string lua_print_msg_args(lua_State* L, const std::string_view& level) +std::string lua_print_msg(lua_State* L, const std::string_view& level) { - // On top of existing Lua arguments, push 'where' info - luaL_checkstack(L, 1, nullptr); + // On top of existing Lua arguments, we're going to push tostring() and + // duplicate each existing stack entry so we can stringize each one. + luaL_checkstack(L, 2, nullptr); luaL_where(L, 1); // start with the 'where' info at the top of the stack std::ostringstream out; @@ -79,7 +79,7 @@ std::string lua_print_msg_args(lua_State* L, const std::string_view& level) const char* sep = ""; // 'where' info ends with ": " // now iterate over arbitrary args, calling Lua tostring() on each and // concatenating with separators - for (int p = 1; p <= lua_gettop(L); ++p) + for (int p = 1, top = lua_gettop(L); p <= top; ++p) { out << sep; sep = " "; @@ -87,15 +87,15 @@ std::string lua_print_msg_args(lua_State* L, const std::string_view& level) // lua_tostring()! lua_getglobal(L, "tostring"); // Now the stack is arguments 1 .. N, plus tostring(). - // Rotate downwards, producing stack args 2 .. N, tostring(), arg1. - lua_rotate(L, 1, -1); - // pop tostring() and arg1, pushing tostring(arg1) + // Push a copy of the argument at index p. + lua_pushvalue(L, p); + // pop tostring() and arg-p, pushing tostring(arg-p) // (ignore potential error code from lua_pcall() because, if there was // an error, we expect the stack top to be an error message -- which // we'll print) lua_pcall(L, 1, 1, 0); - // stack now holds args 2 .. N, tostring(arg1) out << lua_tostring(L, -1); + lua_pop(L, 1); } // pop everything lua_settop(L, 0); @@ -105,20 +105,6 @@ std::string lua_print_msg_args(lua_State* L, const std::string_view& level) LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); return msg; } -*/ - -std::string lua_print_msg(lua_State *L, const std::string_view &level) -{ - lua_getglobal(L, "tostring"); - - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, 1); /* value to print */ - lua_call(L, 1, 1); - std::string msg = lua_tostring(L, -1); - - LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); - return msg; -} lua_function(print_debug) { @@ -187,19 +173,24 @@ lua_function(listen_events) } luaL_checkstack(L, 2, nullptr); +/*==========================================================================*| // Get the lua_State* for the main thread of this state, in case we were // called from a coroutine thread. We're going to make callbacks into Lua // code, and we want to do it on the main thread rather than a (possibly // suspended) coroutine thread. // Registry table is at pseudo-index LUA_REGISTRYINDEX // Main thread is at registry key LUA_RIDX_MAINTHREAD - auto regtype {lua_rawgeti(L, LUA_REGISTRYINDEX, 1 /*LUA_RIDX_MAINTHREAD*/)}; + auto regtype {lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD)}; // Not finding the main thread at the documented place isn't a user error, // it's a Problem llassert_always(regtype == LUA_TTHREAD); lua_State* mainthread{ lua_tothread(L, -1) }; // pop the main thread lua_pop(L, 1); +|*==========================================================================*/ + // Luau is based on Lua 5.1, and Lua 5.1 apparently provides no way to get + // back to the main thread from a coroutine thread? + lua_State* mainthread{ L }; luaL_checkstack(mainthread, 1, nullptr); LuaListener::ptr_t listener; @@ -284,14 +275,21 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_result_fn c runScriptFile(L, filename, cb); } -std::pair<int, LLSD> LLLUAmanager::waitScriptFile(LuaState& L, const std::string& filename) +LLCoros::Future<std::pair<int, LLSD>> +LLLUAmanager::startScriptFile(LuaState& L, const std::string& filename) { - LLCoros::Promise<std::pair<int, LLSD>> promise; - auto future{ LLCoros::getFuture(promise) }; + // Despite returning from startScriptFile(), we need this Promise to + // remain alive until the callback has fired. + auto promise{ std::make_shared<LLCoros::Promise<std::pair<int, LLSD>>>() }; runScriptFile(L, filename, - [&promise](int count, LLSD result) - { promise.set_value({ count, result }); }); - return future.get(); + [promise](int count, LLSD result) + { promise->set_value({ count, result }); }); + return LLCoros::getFuture(*promise); +} + +std::pair<int, LLSD> LLLUAmanager::waitScriptFile(LuaState& L, const std::string& filename) +{ + return startScriptFile(L, filename).get(); } void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, script_result_fn cb) @@ -324,46 +322,53 @@ void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, scrip }); } -void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb) +void LLLUAmanager::runScriptLine(const std::string& chunk, script_finished_fn cb) { // A script_finished_fn is used to initialize the LuaState. // It will be called when the LuaState is destroyed. LuaState L(cb); - runScriptLine(L, cmd); + runScriptLine(L, chunk); } -void LLLUAmanager::runScriptLine(const std::string& cmd, script_result_fn cb) +void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn cb) { LuaState L; // A script_result_fn will be called when LuaState::expr() completes. - runScriptLine(L, cmd, cb); + runScriptLine(L, chunk, cb); +} + +LLCoros::Future<std::pair<int, LLSD>> +LLLUAmanager::startScriptLine(LuaState& L, const std::string& chunk) +{ + // Despite returning from startScriptLine(), we need this Promise to + // remain alive until the callback has fired. + auto promise{ std::make_shared<LLCoros::Promise<std::pair<int, LLSD>>>() }; + runScriptLine(L, chunk, + [promise](int count, LLSD result) + { promise->set_value({ count, result }); }); + return LLCoros::getFuture(*promise); } -std::pair<int, LLSD> LLLUAmanager::waitScriptLine(LuaState& L, const std::string& cmd) +std::pair<int, LLSD> LLLUAmanager::waitScriptLine(LuaState& L, const std::string& chunk) { - LLCoros::Promise<std::pair<int, LLSD>> promise; - auto future{ LLCoros::getFuture(promise) }; - runScriptLine(L, cmd, - [&promise](int count, LLSD result) - { promise.set_value({ count, result }); }); - return future.get(); + return startScriptLine(L, chunk).get(); } -void LLLUAmanager::runScriptLine(LuaState& L, const std::string& cmd, script_result_fn cb) +void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_result_fn cb) { - // find a suitable abbreviation for the cmd string - std::string_view shortcmd{ cmd }; + // find a suitable abbreviation for the chunk string + std::string shortchunk{ chunk }; const size_t shortlen = 40; - std::string::size_type eol = shortcmd.find_first_of("\r\n"); + std::string::size_type eol = shortchunk.find_first_of("\r\n"); if (eol != std::string::npos) - shortcmd = shortcmd.substr(0, eol); - if (shortcmd.length() > shortlen) - shortcmd = stringize(shortcmd.substr(0, shortlen), "..."); + shortchunk = shortchunk.substr(0, eol); + if (shortchunk.length() > shortlen) + shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); - std::string desc{ stringize("runScriptLine('", shortcmd, "')") }; - LLCoros::instance().launch(desc, [&L, desc, cmd, cb]() + std::string desc{ stringize("runScriptLine('", shortchunk, "')") }; + LLCoros::instance().launch(desc, [&L, desc, chunk, cb]() { - auto [count, result] = L.expr(desc, cmd); + auto [count, result] = L.expr(desc, chunk); if (cb) { cb(count, result); diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index bed12e358a..12284cd0e4 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -27,6 +27,7 @@ #ifndef LL_LLLUAMANAGER_H #define LL_LLLUAMANAGER_H +#include "llcoros.h" #include "llsd.h" #include <functional> #include <string> @@ -52,16 +53,30 @@ public: static void runScriptFile(const std::string &filename, script_finished_fn cb = {}); static void runScriptFile(const std::string &filename, script_result_fn cb); static void runScriptFile(LuaState& L, const std::string &filename, script_result_fn cb = {}); + // Start running a Lua script file, returning an LLCoros::Future whose + // get() method will pause the calling coroutine until it can deliver the + // (count, result) pair described above. Between startScriptFile() and + // Future::get(), the caller and the Lua script coroutine will run + // concurrently. + static LLCoros::Future<std::pair<int, LLSD>> + startScriptFile(LuaState& L, const std::string& filename); // Run a Lua script file, and pause the calling coroutine until it completes. // The return value is the (count, result) pair described above. static std::pair<int, LLSD> waitScriptFile(LuaState& L, const std::string& filename); - static void runScriptLine(const std::string &cmd, script_finished_fn cb = {}); - static void runScriptLine(const std::string &cmd, script_result_fn cb); - static void runScriptLine(LuaState& L, const std::string &cmd, script_result_fn cb = {}); - // Run a Lua expression string, and pause the calling coroutine until it completes. + static void runScriptLine(const std::string &chunk, script_finished_fn cb = {}); + static void runScriptLine(const std::string &chunk, script_result_fn cb); + static void runScriptLine(LuaState& L, const std::string &chunk, script_result_fn cb = {}); + // Start running a Lua chunk, returning an LLCoros::Future whose + // get() method will pause the calling coroutine until it can deliver the + // (count, result) pair described above. Between startScriptLine() and + // Future::get(), the caller and the Lua script coroutine will run + // concurrently. + static LLCoros::Future<std::pair<int, LLSD>> + startScriptLine(LuaState& L, const std::string& chunk); + // Run a Lua chunk, and pause the calling coroutine until it completes. // The return value is the (count, result) pair described above. - static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& cmd); + static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& chunk); static void runScriptOnLogin(); }; -- cgit v1.2.3 From 0c14c8a372a5d4639de3365f69e566962493fe78 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Feb 2024 22:50:03 -0500 Subject: Fix tests broken by switching from Lua 5.4 to Luau. Add a new test<1>() that tests returning values from a Lua chunk using LLLUAmanager::waitScriptLine(). This exercises lua_tollsd() without yet involving LLEventPump machinery. For that purpose, extract from test<2>() the sequence of (description, expression, LLSD expected) triples into a static C array. The new test<1>() returns each such expression as a result; test<2>() posts each such expression to a test LLEventPump. test<2>() now uses waitScriptLine() instead of pumping the coroutine scheduler a few times and hoping. The pump-and-hope tactic worked before, but no longer does. waitScriptLine() is more robust anyway. Move the former test<1>() to test<3>() because it exercises still more machinery, specifically listen_events() and await_event(). Because this test involves a handshake with C++ code, use startScriptLine() to launch the Lua coroutine while providing a definite way to wait for completion later. Again, startScriptLine() followed by get() on the returned future is more robust than the previous pump-and-hope code. Similarly, the former test<3>(), now renamed test<4>(), uses startScriptLine() and Future::get() instead of pump-and-hope. --- indra/newview/tests/llluamanager_test.cpp | 143 ++++++++++++++++-------------- 1 file changed, 78 insertions(+), 65 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 98a2726af7..1f25fd5f3b 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -27,6 +27,7 @@ #include "llsdutil.h" #include "lluri.h" #include "lluuid.h" +#include "lua_function.h" #include "stringize.h" class LLTestApp : public LLApp @@ -64,14 +65,80 @@ namespace tut typedef llluamanager_group::object object; llluamanager_group llluamanagergrp("llluamanager"); + static struct LuaExpr + { + std::string desc, expr; + LLSD expect; + } lua_expressions[] = { + { "nil", "nil", LLSD() }, + { "true", "true", true }, + { "false", "false", false }, + { "int", "17", 17 }, + { "real", "3.14", 3.14 }, + { "string", "'string'", "string" }, + // can't synthesize Lua userdata in Lua code: that can only be + // constructed by a C function + { "empty table", "{}", LLSD() }, + { "nested empty table", "{ 1, 2, 3, {}, 5 }", + llsd::array(1, 2, 3, LLSD(), 5) }, + { "nested non-empty table", "{ 1, 2, 3, {a=0, b=1}, 5 }", + llsd::array(1, 2, 3, llsd::map("a", 0, "b", 1), 5) }, + }; + template<> template<> void object::test<1>() + { + set_test_name("test Lua results"); + LuaState L; + for (auto& luax : lua_expressions) + { + auto [count, result] = + LLLUAmanager::waitScriptLine(L, "return " + luax.expr); + auto desc{ stringize("waitScriptLine(", luax.desc, ")") }; + ensure_equals(desc + ".count", count, 1); + ensure_equals(desc + ".result", result, luax.expect); + } + } + + void from_lua(const std::string& desc, const std::string_view& construct, const LLSD& expect) + { + LLSD fromlua; + LLEventStream replypump("testpump"); + LLTempBoundListener conn( + replypump.listen("llluamanager_test", + listener([&fromlua](const LLSD& data){ fromlua = data; }))); + const std::string lua(stringize( + "-- test LLSD synthesized by Lua\n", + "data = ", construct, "\n" + "post_on('testpump', data)\n" + )); + LuaState L; + auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + // We woke up again ourselves because the coroutine running Lua has + // finished. But our Lua chunk didn't actually return anything, so we + // expect count to be 0 and result to be undefined. + ensure_equals(desc + " count", count, 0); + ensure_equals(desc, fromlua, expect); + } + + template<> template<> + void object::test<2>() + { + set_test_name("LLSD from post_on()"); + for (auto& luax : lua_expressions) + { + from_lua(luax.desc, luax.expr, luax.expect); + } + } + + template<> template<> + void object::test<3>() { set_test_name("test post_on(), listen_events(), await_event()"); StringVec posts; LLEventStream replypump("testpump"); LLTempBoundListener conn( - replypump.listen("test<1>", + replypump.listen("test<3>", listener([&posts](const LLSD& data) { posts.push_back(data.asString()); }))); const std::string lua( @@ -88,7 +155,11 @@ namespace tut "await_event(replypump)\n" "post_on('testpump', 'exit')\n" ); - LLLUAmanager::runScriptLine(lua); + LuaState L; + // It's important to let the startScriptLine() coroutine run + // concurrently with ours until we've had a chance to post() our + // reply. + auto future = LLLUAmanager::startScriptLine(L, lua); StringVec expected{ "entry", "listen_events()", @@ -97,10 +168,6 @@ namespace tut "message", "exit" }; - for (int i = 0; i < 10 && posts.size() <= 2 && posts[2].empty(); ++i) - { - llcoro::suspend(); - } expected[2] = posts.at(2); LL_DEBUGS() << "Found pumpname '" << expected[2] << "'" << LL_ENDL; LLEventPump& luapump{ LLEventPumps::instance().obtain(expected[2]) }; @@ -108,57 +175,10 @@ namespace tut << LLError::Log::classname(luapump) << "': post('" << expected[4] << "')" << LL_ENDL; luapump.post(expected[4]); - llcoro::suspend(); + auto [count, result] = future.get(); ensure_equals("post_on() sequence", posts, expected); } - void from_lua(const std::string& desc, const std::string_view& construct, const LLSD& expect) - { - LLSD fromlua; - LLEventStream replypump("testpump"); - LLTempBoundListener conn( - replypump.listen("llluamanager_test", - listener([&fromlua](const LLSD& data){ fromlua = data; }))); - const std::string lua(stringize( - "-- test LLSD synthesized by Lua\n", - // we expect the caller's Lua snippet to construct a Lua object - // called 'data' - construct, "\n" - "post_on('testpump', data)\n" - )); - LLLUAmanager::runScriptLine(lua); - // At this point LLLUAmanager::runScriptLine() has launched a new C++ - // coroutine to run the passed Lua snippet, but that coroutine hasn't - // yet had a chance to run. Poke the coroutine scheduler until the Lua - // script has sent its data. - for (int i = 0; i < 10 && fromlua.isUndefined(); ++i) - { - llcoro::suspend(); - } - // We woke up again ourselves because the coroutine running Lua has - // finished. - ensure_equals(desc, fromlua, expect); - } - - template<> template<> - void object::test<2>() - { - set_test_name("LLSD from Lua"); - from_lua("nil", "data = nil", LLSD()); - from_lua("true", "data = true", true); - from_lua("false", "data = false", false); - from_lua("int", "data = 17", 17); - from_lua("real", "data = 3.14", 3.14); - from_lua("string", "data = 'string'", "string"); - // can't synthesize Lua userdata in Lua code: that can only be - // constructed by a C function - from_lua("empty table", "data = {}", LLSD()); - from_lua("nested empty table", "data = { 1, 2, 3, {}, 5 }", - llsd::array(1, 2, 3, LLSD(), 5)); - from_lua("nested non-empty table", "data = { 1, 2, 3, {a=0, b=1}, 5 }", - llsd::array(1, 2, 3, llsd::map("a", 0, "b", 1), 5)); - } - void round_trip(const std::string& desc, const LLSD& send, const LLSD& expect) { LLSD reply; @@ -176,15 +196,8 @@ namespace tut "post_on('testpump', replypump)\n" "await_event(replypump)\n" ); - LLLUAmanager::runScriptLine(lua); - // At this point LLLUAmanager::runScriptLine() has launched a new C++ - // coroutine to run the passed Lua snippet, but that coroutine hasn't - // yet had a chance to run. Poke the coroutine scheduler until the Lua - // script has sent its reply pump name. - for (int i = 0; i < 10 && reply.isUndefined(); ++i) - { - llcoro::suspend(); - } + LuaState L; + auto future = LLLUAmanager::startScriptLine(L, lua); // We woke up again ourselves because the coroutine running Lua has // reached the await_event() call, which suspends the calling C++ // coroutine (including the Lua code running on it) until we post @@ -194,7 +207,7 @@ namespace tut LLEventPumps::instance().post(luapump, send); // The C++ coroutine running the Lua script is now ready to run. Run // it so it will echo the LLSD back to us. - llcoro::suspend(); + auto [count, result] = future.get(); ensure_equals(desc, reply, expect); } @@ -219,7 +232,7 @@ namespace tut }; template<> template<> - void object::test<3>() + void object::test<4>() { set_test_name("LLSD round trip"); LLSD::Binary binary{ 3, 1, 4, 1, 5, 9, 2, 6, 5 }; -- cgit v1.2.3 From 4e9794bd06660baea6d16779f6e354ca99e11b8a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 8 Feb 2024 13:59:19 -0500 Subject: Add required helptext parameter to lua_function() macro. Extend the LuaFunction::Registry map to store helptext as well as the function pointer. Add help text to every existing lua_function() invocation. --- indra/newview/llluamanager.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index fac66003a1..c55c44e671 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -56,7 +56,7 @@ extern LLUIListener sUIListener; #include <string_view> #include <vector> -lua_function(sleep) +lua_function(sleep, "sleep(seconds): pause the running coroutine") { F32 seconds = lua_tonumber(L, -1); lua_pop(L, 1); @@ -106,20 +106,20 @@ std::string lua_print_msg(lua_State* L, const std::string_view& level) return msg; } -lua_function(print_debug) +lua_function(print_debug, "print_debug(args...): DEBUG level logging") { LL_DEBUGS("Lua") << lua_print_msg(L, "DEBUG") << LL_ENDL; return 0; } // also used for print(); see LuaState constructor -lua_function(print_info) +lua_function(print_info, "print_info(args...): INFO level logging") { LL_INFOS("Lua") << lua_print_msg(L, "INFO") << LL_ENDL; return 0; } -lua_function(print_warning) +lua_function(print_warning, "print_warning(args...): WARNING level logging") { LL_WARNS("Lua") << lua_print_msg(L, "WARN") << LL_ENDL; return 0; @@ -127,7 +127,9 @@ lua_function(print_warning) #ifndef LL_TEST -lua_function(run_ui_command) +lua_function(run_ui_command, + "run_ui_command(name [, parameter]): " + "call specified UI command with specified parameter") { int top = lua_gettop(L); std::string func_name; @@ -154,7 +156,7 @@ lua_function(run_ui_command) } #endif // ! LL_TEST -lua_function(post_on) +lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLEventPump") { std::string pumpname{ lua_tostdstring(L, 1) }; LLSD data{ lua_tollsd(L, 2) }; @@ -164,7 +166,10 @@ lua_function(post_on) return 0; } -lua_function(listen_events) +lua_function(listen_events, + "listen_events(callback): call callback(pumpname, data) with events received\n" + "on this Lua chunk's replypump.\n" + "Returns replypump, commandpump: names of LLEventPumps specific to this chunk.") { if (! lua_isfunction(L, 1)) { @@ -237,9 +242,10 @@ lua_function(listen_events) return 2; } -lua_function(await_event) +lua_function(await_event, + "await_event(pumpname [, timeout [, value to return if timeout (default nil)]]):\n" + "pause the running Lua chunk until the next event on the named LLEventPump") { - // await_event(pumpname [, timeout [, value to return if timeout (default nil)]]) auto pumpname{ lua_tostdstring(L, 1) }; LLSD result; if (lua_gettop(L) > 1) -- cgit v1.2.3 From 8e3375534607a1a6648ace18f7293a2c0a096862 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 9 Feb 2024 09:19:27 -0500 Subject: When LLFloaterLUADebug script returns a value, display the value. The chunk: return 1, 2, {} differs in two ways from: print(1, 2, {}) First, print() engages the Lua tostring() builtin, so it displays values as Lua sees them. (For a table, tostring() displays "table: hex", which isn't so wonderful.) But LLFloaterLUADebug serializes the LLSD converted from the Lua return values. Second, we've overridden print() to engage a function that writes to the viewer log as well as displaying to LLFloaterLUADebug. (As we go forward, most Lua scripts won't be run manually by LLFloaterLUADebug.) The values returned by a Lua chunk aren't implicitly logged. Each C++ caller wanting to evaluate a Lua expression can choose whether to log the results. --- indra/newview/llfloaterluadebug.cpp | 41 ++++++++++++++++++++++++++++++------- indra/newview/llfloaterluadebug.h | 2 ++ 2 files changed, 36 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 58639490db..b2c001817f 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -37,6 +37,9 @@ #include "llfloaterimnearbychat.h" #include "llluamanager.h" +#include "llsdutil.h" +#include "lua_function.h" +#include "stringize.h" LLFloaterLUADebug::LLFloaterLUADebug(const LLSD &key) @@ -74,9 +77,9 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); - LLLUAmanager::runScriptLine(cmd, [this](std::string msg) - { - mResultOutput->insertText(msg); + LLLUAmanager::runScriptLine(cmd, [this](int count, const LLSD& result) + { + completion(count, result); }); } @@ -104,10 +107,34 @@ void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filena if (!filepath.empty()) { mScriptPath->setText(filepath); - LLLUAmanager::runScriptFile(filepath, [this](std::string msg) - { - mResultOutput->insertText(msg); - }); + LLLUAmanager::runScriptFile(filepath, [this](int count, const LLSD& result) + { + completion(count, result); + }); } } +void LLFloaterLUADebug::completion(int count, const LLSD& result) +{ + if (count < 0) + { + // error: show error message + mResultOutput->insertText("*** "); + mResultOutput->insertText(result.asString()); + return; + } + if (count == 1) + { + // single result + mResultOutput->insertText(stringize(result)); + return; + } + // 0 or multiple results + const char* sep = ""; + for (const auto& item : llsd::inArray(result)) + { + mResultOutput->insertText(sep); + mResultOutput->insertText(stringize(item)); + sep = ", "; + } +} diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 1e26828c83..2dc59c5894 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -56,6 +56,8 @@ class LLFloaterLUADebug : void runSelectedScript(const std::vector<std::string> &filenames); private: + void completion(int count, const LLSD& result); + LLTempBoundListener mOutConnection; LLTextEditor* mResultOutput; -- cgit v1.2.3 From 8f9acfd71f7cc2b6295404c8fb270bb4b83f5626 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 9 Feb 2024 11:32:02 -0500 Subject: Make LLFloaterLUADebug store a persistent LuaState. That means that as you use the floater, variables that you assign and functions that you define are available to subsequent Lua chunks. --- indra/newview/llfloaterluadebug.cpp | 4 ++-- indra/newview/llfloaterluadebug.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index b2c001817f..d7b46eaa71 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -77,7 +77,7 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); - LLLUAmanager::runScriptLine(cmd, [this](int count, const LLSD& result) + LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) { completion(count, result); }); @@ -107,7 +107,7 @@ void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filena if (!filepath.empty()) { mScriptPath->setText(filepath); - LLLUAmanager::runScriptFile(filepath, [this](int count, const LLSD& result) + LLLUAmanager::runScriptFile(mState, filepath, [this](int count, const LLSD& result) { completion(count, result); }); diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 2dc59c5894..69b334ae2d 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -28,6 +28,7 @@ #include "llevents.h" #include "llfloater.h" +#include "lua_function.h" extern "C" { @@ -63,6 +64,7 @@ private: LLTextEditor* mResultOutput; LLLineEditor* mLineInput; LLLineEditor* mScriptPath; + LuaState mState; }; #endif // LL_LLFLOATERLUADEBUG_H -- cgit v1.2.3 From 36f535a8ec1dc2d2553a322259a28e42aff5940b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 9 Feb 2024 17:19:39 -0500 Subject: Make LLLUAmanager::runScriptFile() use filename as description. Since the description shows up in the log output, it's better to see just the script filename than to see "runScriptFile('filename')". --- indra/newview/llluamanager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c55c44e671..d58ee5ca5f 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -300,8 +300,7 @@ std::pair<int, LLSD> LLLUAmanager::waitScriptFile(LuaState& L, const std::string void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, script_result_fn cb) { - std::string desc{ stringize("runScriptFile('", filename, "')") }; - LLCoros::instance().launch(desc, [&L, desc, filename, cb]() + LLCoros::instance().launch(filename, [&L, filename, cb]() { llifstream in_file; in_file.open(filename.c_str()); @@ -310,7 +309,7 @@ void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, scrip { std::string text{std::istreambuf_iterator<char>(in_file), std::istreambuf_iterator<char>()}; - auto [count, result] = L.expr(desc, text); + auto [count, result] = L.expr(filename, text); if (cb) { cb(count, result); -- cgit v1.2.3 From 177000d2c9b3dba889119d63109f9b6d8748b0b7 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 9 Feb 2024 17:19:48 -0500 Subject: Add command-line switches --lua "chunk" and --luafile pathname. --lua "chunk" runs the specified Lua chunk at startup time. --luafile pathname runs the specified Lua script file at startup time. You may specify more than one --lua or --luafile switch on the command line. --- indra/newview/app_settings/cmd_line.xml | 28 ++++++++++++++- indra/newview/app_settings/settings.xml | 24 ++++++++++++- indra/newview/llappviewer.cpp | 60 +++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 19 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index 340334aee8..534d1d594d 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -195,7 +195,33 @@ <string>LogPerformance</string> </map> - <key>multiple</key> + <key>lua</key> + <map> + <key>desc</key> + <string>Run specified Lua chunk</string> + <key>count</key> + <integer>1</integer> + <!-- you can specify multiple such chunks --> + <key>compose</key> + <boolean>true</boolean> + <key>map-to</key> + <string>LuaChunk</string> + </map> + + <key>luafile</key> + <map> + <key>desc</key> + <string>Run specified Lua script</string> + <key>count</key> + <integer>1</integer> + <!-- you can specify multiple such scripts --> + <key>compose</key> + <boolean>true</boolean> + <key>map-to</key> + <string>LuaScript</string> + </map> + + <key>multiple</key> <map> <key>desc</key> <string>Allow multiple viewers.</string> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 5e4cd4e57b..bda07f8821 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -68,7 +68,7 @@ <key>Value</key> <integer>1</integer> </map> - <key>CrashHostUrl</key> + <key>CrashHostUrl</key> <map> <key>Comment</key> <string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string> @@ -5431,6 +5431,28 @@ <key>Value</key> <string>http://wiki.secondlife.com/wiki/[LSL_STRING]</string> </map> + <key>LuaChunk</key> + <map> + <key>Comment</key> + <string>Zero or more Lua chunks to run</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array /> + </map> + <key>LuaScript</key> + <map> + <key>Comment</key> + <string>Zero or more Lua script files to run</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array /> + </map> <key>GridStatusRSS</key> <map> <key>Comment</key> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4a43133ff6..5ad6f1dc1e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -60,6 +60,7 @@ #include "llslurl.h" #include "llstartup.h" #include "llfocusmgr.h" +#include "llluamanager.h" #include "llurlfloaterdispatchhandler.h" #include "llviewerjoystick.h" #include "llallocator.h" @@ -386,6 +387,9 @@ static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) const char* const VIEWER_WINDOW_CLASSNAME = "Second Life"; +void processComposeSwitch(const std::string&, const std::string&, + const std::function<void(const LLSD&)>&); + //---------------------------------------------------------------------------- // List of entries from strings.xml to always replace @@ -1194,22 +1198,10 @@ bool LLAppViewer::init() } #endif //LL_RELEASE_FOR_DOWNLOAD - { - // Iterate over --leap command-line options. But this is a bit tricky: if - // there's only one, it won't be an array at all. - LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand")); - LL_DEBUGS("InitInfo") << "LeapCommand: " << LeapCommand << LL_ENDL; - if (LeapCommand.isDefined() && !LeapCommand.isArray()) - { - // If LeapCommand is actually a scalar value, make an array of it. - // Have to do it in two steps because LeapCommand.append(LeapCommand) - // trashes content! :-P - LLSD item(LeapCommand); - LeapCommand.append(item); - } - BOOST_FOREACH(const std::string& leap, llsd::inArray(LeapCommand)) + processComposeSwitch( + "--leap", "LeapCommand", + [](const LLSD& leap) { - LL_INFOS("InitInfo") << "processing --leap \"" << leap << '"' << LL_ENDL; // We don't have any better description of this plugin than the // user-specified command line. Passing "" causes LLLeap to derive a // description from the command line itself. @@ -1217,8 +1209,21 @@ bool LLAppViewer::init() // don't consider any one --leap command mission-critical, so if one // fails, log it, shrug and carry on. LLLeap::create("", leap, false); // exception=false - } - } + }); + processComposeSwitch( + "--lua", "LuaChunk", + [](const LLSD& chunk) + { + // no completion callback: we don't need to know + LLLUAmanager::runScriptLine(chunk); + }); + processComposeSwitch( + "--luafile", "LuaScript", + [](const LLSD& script) + { + // no completion callback: we don't need to know + LLLUAmanager::runScriptFile(script); + }); if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0) { @@ -1291,6 +1296,27 @@ bool LLAppViewer::init() return true; } +void processComposeSwitch(const std::string& option, + const std::string& setting, + const std::function<void(const LLSD&)>& action) +{ + // Iterate over 'option' command-line options. But this is a bit tricky: + // if there's only one, it won't be an array at all. + LLSD args(gSavedSettings.getLLSD(setting)); + LL_DEBUGS("InitInfo") << option << ": " << args << LL_ENDL; + if (args.isDefined() && ! args.isArray()) + { + // If args is actually a scalar value, make an array of it. Have to do + // it in two steps because args.append(args) trashes content! :-P + args.append(LLSD(args)); + } + for (const auto& arg : llsd::inArray(args)) + { + LL_INFOS("InitInfo") << "processing " << option << ' ' << arg << LL_ENDL; + action(arg); + } +} + void LLAppViewer::initMaxHeapSize() { //set the max heap size. -- cgit v1.2.3 From 9b1796df73f2d4fa19517f390258f798c10bff1e Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Mon, 12 Feb 2024 18:49:36 +0200 Subject: Make LLFloaterLUADebug assume 'Execute' button on LUA String Enter --- indra/newview/llfloaterluadebug.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index d7b46eaa71..7d56d8e618 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -65,6 +65,8 @@ BOOL LLFloaterLUADebug::postBuild() getChild<LLButton>("execute_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); getChild<LLButton>("browse_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnBrowse, this)); getChild<LLButton>("run_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnRun, this)); + mLineInput->setCommitCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); + mLineInput->setSelectAllonCommit(false); return TRUE; } -- cgit v1.2.3 From b4583fac09657cb64ed02e82e12ce69c4ace225d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 12 Feb 2024 17:10:42 -0500 Subject: WIP: Changes towards supporting Lua console help text. --- indra/newview/llfloaterluadebug.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index d7b46eaa71..245cc88f79 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -57,7 +57,7 @@ BOOL LLFloaterLUADebug::postBuild() .listen("LLFloaterLUADebug", [mResultOutput=mResultOutput](const LLSD& data) { - mResultOutput->insertText(data.asString()); + mResultOutput->pasteTextWithLinebreaks(data.asString()); mResultOutput->addLineBreakChar(true); return false; }); @@ -120,13 +120,13 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) { // error: show error message mResultOutput->insertText("*** "); - mResultOutput->insertText(result.asString()); + mResultOutput->pasteTextWithLinebreaks(result.asString()); return; } if (count == 1) { // single result - mResultOutput->insertText(stringize(result)); + mResultOutput->pasteTextWithLinebreaks(stringize(result)); return; } // 0 or multiple results @@ -134,7 +134,7 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) for (const auto& item : llsd::inArray(result)) { mResultOutput->insertText(sep); - mResultOutput->insertText(stringize(item)); + mResultOutput->pasteTextWithLinebreaks(stringize(item)); sep = ", "; } } -- cgit v1.2.3 From d583fb8badd8060c0f74bcb6e99bb6e7d08a67d0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 13 Feb 2024 17:34:00 -0500 Subject: Add leaphelp() Lua builtin function for help on LEAP operations. leaphelp() (no argument) shows a list of all LEAP APIs. leaphelp(API) shows further help for a specific API. Both forms query LuaListener's LeapListener and report its responses. In future we might reimplement leaphelp() as a Lua function. Add LuaState::getListener() method, which checks whether there's a LuaListener associated with this LuaState and returns a pointer if so. Add LuaState::obtainListener() method, which finds or creates a LuaListener for this LuaState and returns its pointer. Both the above use logic migrated from the Lua listen_events() entry point, which now calls obtainListener() instead. --- indra/newview/llluamanager.cpp | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index d58ee5ca5f..c6a900aa81 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -197,34 +197,7 @@ lua_function(listen_events, // back to the main thread from a coroutine thread? lua_State* mainthread{ L }; - luaL_checkstack(mainthread, 1, nullptr); - LuaListener::ptr_t listener; - // Does the main thread already have a LuaListener stored in the registry? - // That is, has this Lua chunk already called listen_events()? - auto keytype{ lua_getfield(mainthread, LUA_REGISTRYINDEX, "event.listener") }; - llassert(keytype == LUA_TNIL || keytype == LUA_TNUMBER); - if (keytype == LUA_TNUMBER) - { - // We do already have a LuaListener. Retrieve it. - int isint; - listener = LuaListener::getInstance(lua_tointegerx(mainthread, -1, &isint)); - // pop the int "event.listener" key - lua_pop(mainthread, 1); - // Nobody should have destroyed this LuaListener instance! - llassert(isint && listener); - } - else - { - // pop the nil "event.listener" key - lua_pop(mainthread, 1); - // instantiate a new LuaListener, binding the mainthread state -- but - // use a no-op deleter: we do NOT want to delete this new LuaListener - // on return from listen_events()! - listener.reset(new LuaListener(mainthread), [](LuaListener*){}); - // set its key in the field where we'll look for it later - lua_pushinteger(mainthread, listener->getKey()); - lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.listener"); - } + auto listener{ LuaState::obtainListener(mainthread) }; // Now that we've found or created our LuaListener, store the passed Lua // function as the callback. Beware: our caller passed the function on L's -- cgit v1.2.3 From b305fb6411939bf6afbe2ecf2c1bdf765c9247a9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 20 Feb 2024 14:25:56 +0200 Subject: Initial require implementation --- indra/newview/llluamanager.cpp | 207 +++++++++++++++++++++++++++++++++++++++++ indra/newview/llluamanager.h | 39 ++++++++ 2 files changed, 246 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index d58ee5ca5f..9b74060139 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -401,3 +401,210 @@ void LLLUAmanager::runScriptOnLogin() runScriptFile(filename); #endif // ! LL_TEST } + + +bool is_absolute_path(std::string_view path) +{ +#ifdef LL_WINDOWS + // Must either begin with "X:/", "X:\", "/", or "\", where X is a drive letter + return (path.size() >= 3 && isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) || + (path.size() >= 1 && (path[0] == '/' || path[0] == '\\')); +#else + // Must begin with '/' + return path.size() >= 1 && path[0] == '/'; +#endif +} + +std::string join_paths(const std::string &lhs, const std::string &rhs) +{ + std::string result = lhs; + if (!result.empty() && result.back() != '/' && result.back() != '\\') + result += '/'; + result += rhs; + return result; +} + +std::string read_file(const std::string &name) +{ + llifstream in_file; + in_file.open(name.c_str()); + + if (in_file.is_open()) + { + std::string text {std::istreambuf_iterator<char>(in_file), std::istreambuf_iterator<char>()}; + return text; + } + + return std::string(); +} + +LLRequireResolver::LLRequireResolver(lua_State *L, std::string path) : mPathToResolve(std::move(path)), L(L) +{ + lua_Debug ar; + lua_getinfo(L, 1, "s", &ar); + mSourceChunkname = ar.source; + + std::replace(mPathToResolve.begin(), mPathToResolve.end(), '\\', '/'); +} + +[[nodiscard]] LLRequireResolver::ResolvedRequire LLRequireResolver::resolveRequire(lua_State *L, std::string path) +{ + LLRequireResolver resolver(L, std::move(path)); + ModuleStatus status = resolver.findModule(); + if (status != ModuleStatus::FileRead) + return ResolvedRequire {status}; + else + return ResolvedRequire {status, std::move(resolver.mChunkname), std::move(resolver.mAbsolutePath), std::move(resolver.mSourceCode)}; +} + +LLRequireResolver::ModuleStatus LLRequireResolver::findModule() +{ + resolveAndStoreDefaultPaths(); + + // Put _MODULES table on stack for checking and saving to the cache + luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1); + + LLRequireResolver::ModuleStatus moduleStatus = findModuleImpl(); + + if (moduleStatus != LLRequireResolver::ModuleStatus::NotFound) + return moduleStatus; + + if (is_absolute_path(mPathToResolve)) + return moduleStatus; + + std::vector<std::string> lib_paths; + + lib_paths.push_back(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + + for (size_t i = 0; i < lib_paths.size(); ++i) + { + std::string absolutePathOpt = join_paths(lib_paths[i], mPathToResolve); + + if (absolutePathOpt.empty()) + luaL_errorL(L, "error requiring module"); + + mChunkname = absolutePathOpt; + mAbsolutePath = absolutePathOpt; + + moduleStatus = findModuleImpl(); + + if (moduleStatus != LLRequireResolver::ModuleStatus::NotFound) + return moduleStatus; + } + + return LLRequireResolver::ModuleStatus::NotFound; +} + +LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() +{ + std::string possibleSuffixes[] = {".luau", ".lua"}; + + size_t unsuffixedAbsolutePathSize = mAbsolutePath.size(); + + for (auto possibleSuffix : possibleSuffixes) + { + mAbsolutePath += possibleSuffix; + + // Check cache for module + lua_getfield(L, -1, mAbsolutePath.c_str()); + if (!lua_isnil(L, -1)) + { + return ModuleStatus::Cached; + } + lua_pop(L, 1); + + // Try to read the matching file + std::string source = read_file(mAbsolutePath); + if (!source.empty()) + { + mChunkname = "=" + mChunkname + possibleSuffix; + mSourceCode = source; + return ModuleStatus::FileRead; + } + + mAbsolutePath.resize(unsuffixedAbsolutePathSize); // truncate to remove suffix + } + + return ModuleStatus::NotFound; +} + +void LLRequireResolver::resolveAndStoreDefaultPaths() +{ + if (!is_absolute_path(mPathToResolve)) + { + std::string path = gDirUtilp->getDirName(mSourceChunkname); + std::replace(path.begin(), path.end(), '\\', '/'); + path = join_paths(path, mPathToResolve); + mAbsolutePath = path; + mChunkname = path; + } + else + { + mChunkname = mPathToResolve; + mAbsolutePath = mPathToResolve; + } +} + +static int finishrequire(lua_State *L) +{ + if (lua_isstring(L, -1)) + lua_error(L); + + return 1; +} + +lua_function(require, "require(module_name) : module_name can be fullpath or just the name, in both cases without .lua") +{ + std::string name = luaL_checkstring(L, 1); + + LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, std::move(name)); + + if (resolvedRequire.status == LLRequireResolver::ModuleStatus::Cached) + return finishrequire(L); + else if (resolvedRequire.status == LLRequireResolver::ModuleStatus::NotFound) + luaL_errorL(L, "error requiring module"); + + // module needs to run in a new thread, isolated from the rest + // note: we create ML on main thread so that it doesn't inherit environment of L + lua_State *GL = lua_mainthread(L); + lua_State *ML = lua_newthread(GL); + lua_xmove(GL, L, 1); + + // new thread needs to have the globals sandboxed + luaL_sandboxthread(ML); + + { + // now we can compile & run module on the new thread + size_t bytecodeSize = 0; + std::unique_ptr<char[], freer> bytecode { + luau_compile(resolvedRequire.sourceCode.c_str(), resolvedRequire.sourceCode.length(), nullptr, &bytecodeSize)}; + + if (luau_load(ML, resolvedRequire.chunkName.c_str(), bytecode.get(), bytecodeSize, 0) == 0) + { + int status = lua_resume(ML, L, 0); + + if (status == 0) + { + if (lua_gettop(ML) == 0) + lua_pushstring(ML, "module must return a value"); + else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1)) + lua_pushstring(ML, "module must return a table or function"); + } + else if (status == LUA_YIELD) + { + lua_pushstring(ML, "module can not yield"); + } + else if (!lua_isstring(ML, -1)) + { + lua_pushstring(ML, "unknown error while running module"); + } + } + } + // there's now a return value on top of ML; L stack: _MODULES ML + lua_xmove(ML, L, 1); + lua_pushvalue(L, -1); + lua_setfield(L, -4, resolvedRequire.absolutePath.c_str()); + + // L stack: _MODULES ML result + return finishrequire(L); +} diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 12284cd0e4..c382de3c62 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -33,6 +33,9 @@ #include <string> #include <utility> // std::pair +#include "luau/lua.h" +#include "luau/lualib.h" + class LuaState; class LLLUAmanager @@ -81,4 +84,40 @@ public: static void runScriptOnLogin(); }; +class LLRequireResolver +{ + public: + enum class ModuleStatus + { + Cached, + FileRead, + NotFound + }; + + struct ResolvedRequire + { + ModuleStatus status; + std::string chunkName; + std::string absolutePath; + std::string sourceCode; + }; + + [[nodiscard]] ResolvedRequire static resolveRequire(lua_State *L, std::string path); + + std::string mChunkname; + std::string mAbsolutePath; + std::string mSourceCode; + + private: + std::string mPathToResolve; + std::string mSourceChunkname; + + LLRequireResolver(lua_State *L, std::string path); + + ModuleStatus findModule(); + lua_State *L; + + void resolveAndStoreDefaultPaths(); + ModuleStatus findModuleImpl(); +}; #endif -- cgit v1.2.3 From 3a9d0e7fa9214b5f802dd558d1e4c7154bbadb3e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 20 Feb 2024 18:18:04 +0200 Subject: Don't accept a full path as arg for require() --- indra/newview/llluamanager.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 9b74060139..164738bc3b 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -444,6 +444,9 @@ LLRequireResolver::LLRequireResolver(lua_State *L, std::string path) : mPathToRe lua_getinfo(L, 1, "s", &ar); mSourceChunkname = ar.source; + if (is_absolute_path(mPathToResolve)) + luaL_argerrorL(L, 1, "cannot require a full path"); + std::replace(mPathToResolve.begin(), mPathToResolve.end(), '\\', '/'); } -- cgit v1.2.3 From 32bf9c7b7a9d2b2428b052d74389ec48ccc427cf Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 21 Feb 2024 17:11:33 +0200 Subject: Add the option to use clean lua_State in "Lua debug" floater --- indra/newview/llfloaterluadebug.cpp | 12 ++++++++++++ indra/newview/llfloaterluadebug.h | 1 + indra/newview/skins/default/xui/en/floater_lua_debug.xml | 9 +++++++++ 3 files changed, 22 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 7d56d8e618..2d9dc89340 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -27,6 +27,7 @@ #include "llfloaterluadebug.h" +#include "llcheckboxctrl.h" #include "lllineeditor.h" #include "lltexteditor.h" #include "llviewermenufile.h" // LLFilePickerReplyThread @@ -79,6 +80,7 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); + cleanLuaState(); LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) { completion(count, result); @@ -109,6 +111,7 @@ void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filena if (!filepath.empty()) { mScriptPath->setText(filepath); + cleanLuaState(); LLLUAmanager::runScriptFile(mState, filepath, [this](int count, const LLSD& result) { completion(count, result); @@ -140,3 +143,12 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) sep = ", "; } } + +void LLFloaterLUADebug::cleanLuaState() +{ + if(getChild<LLCheckBoxCtrl>("clean_lua_state")->get()) + { + //Reinit to clean lua_State + mState.initLuaState(); + } +} diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 69b334ae2d..7418174570 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -58,6 +58,7 @@ class LLFloaterLUADebug : private: void completion(int count, const LLSD& result); + void cleanLuaState(); LLTempBoundListener mOutConnection; diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml index f03739f7c2..a028a1802c 100644 --- a/indra/newview/skins/default/xui/en/floater_lua_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -25,6 +25,15 @@ width="100"> LUA string: </text> + <check_box + follows="left|bottom" + height="15" + label="Use clean lua_State" + layout="topleft" + top="10" + right ="-70" + name="clean_lua_state" + width="70"/> <line_editor border_style="line" border_thickness="1" -- cgit v1.2.3 From 85ef003ed7836cb351ee62ed44a4837a305e9dbd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 22 Feb 2024 20:42:08 -0500 Subject: Lua listen_events(), await_event() => get_event_{pumps,next}(). Don't set up a Lua callback to receive incoming events, a la listen_events(). Don't listen on an arbitrary event pump, a la await_event(). Instead, the new get_event_pumps() entry point simply delivers the reply pump and command pump names (as listen_events() did) without storing a Lua callback. Make LuaListener capture incoming events on the reply pump in a queue. This avoids the problem of multiple events arriving too quickly for the Lua script to retrieve. If the queue gets too big, discard the excess instead of blocking the caller of post(). Then the new get_event_next() entry point retrieves the next (pump, data) pair from the queue, blocking the Lua script until a suitable event arrives. This is closer to the use of stdin for a LEAP plugin. It also addresses the question: what should the Lua script's C++ coroutine do while waiting for an incoming reply pump event? Recast llluamanager_test.cpp for this new, more straightforward API. Move LLLeap's and LuaListener's reply LLEventPump into LLLeapListener, which they both use. This simplifies LLLeapListener's API, which was a little convoluted: the caller supplied a connect callback to allow LLLeapListener to connect some listener to the caller's reply pump. Now, instead, the caller simply passes a bool(pumpname, data) callback to receive events incoming on LLLeapListener's own reply pump. Fix a latent bug in LLLeapListener: if a plugin called listen() more than once with the same listener name, the new connection would not have been saved. While at it, replace some older Boost features in LLLeapListener and LLLeap. --- indra/newview/llluamanager.cpp | 63 +++++++++++-------------------- indra/newview/tests/llluamanager_test.cpp | 35 +++++++---------- 2 files changed, 35 insertions(+), 63 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c6a900aa81..33b996ab50 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -166,55 +166,34 @@ lua_function(post_on, "post_on(pumpname, data): post specified data to specified return 0; } -lua_function(listen_events, - "listen_events(callback): call callback(pumpname, data) with events received\n" - "on this Lua chunk's replypump.\n" - "Returns replypump, commandpump: names of LLEventPumps specific to this chunk.") +lua_function(get_event_pumps, + "get_event_pumps():\n" + "Returns replypump, commandpump: names of LLEventPumps specific to this chunk.\n" + "Events posted to replypump are queued for get_event_next().\n" + "post_on(commandpump, ...) to engage LLEventAPI operations (see helpleap()).") { - if (! lua_isfunction(L, 1)) - { - luaL_typeerror(L, 1, "function"); - return 0; - } luaL_checkstack(L, 2, nullptr); - -/*==========================================================================*| - // Get the lua_State* for the main thread of this state, in case we were - // called from a coroutine thread. We're going to make callbacks into Lua - // code, and we want to do it on the main thread rather than a (possibly - // suspended) coroutine thread. - // Registry table is at pseudo-index LUA_REGISTRYINDEX - // Main thread is at registry key LUA_RIDX_MAINTHREAD - auto regtype {lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD)}; - // Not finding the main thread at the documented place isn't a user error, - // it's a Problem - llassert_always(regtype == LUA_TTHREAD); - lua_State* mainthread{ lua_tothread(L, -1) }; - // pop the main thread - lua_pop(L, 1); -|*==========================================================================*/ - // Luau is based on Lua 5.1, and Lua 5.1 apparently provides no way to get - // back to the main thread from a coroutine thread? - lua_State* mainthread{ L }; - - auto listener{ LuaState::obtainListener(mainthread) }; - - // Now that we've found or created our LuaListener, store the passed Lua - // function as the callback. Beware: our caller passed the function on L's - // stack, but we want to store it on the mainthread registry. - if (L != mainthread) - { - // push 1 value (the Lua function) from L's stack to mainthread's - lua_xmove(L, mainthread, 1); - } - lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.function"); - + auto listener{ LuaState::obtainListener(L) }; // return the reply pump name and the command pump name on caller's lua_State lua_pushstdstring(L, listener->getReplyName()); lua_pushstdstring(L, listener->getCommandName()); return 2; } +lua_function(get_event_next, + "get_event_next():\n" + "Returns the next (pumpname, data) pair from the replypump whose name\n" + "is returned by get_event_pumps(). Blocks the calling chunk until an\n" + "event becomes available.") +{ + luaL_checkstack(L, 2, nullptr); + auto listener{ LuaState::obtainListener(L) }; + const auto& [pump, data]{ listener->getNext() }; + lua_pushstdstring(L, pump); + lua_pushllsd(L, data); + return 2; +} + lua_function(await_event, "await_event(pumpname [, timeout [, value to return if timeout (default nil)]]):\n" "pause the running Lua chunk until the next event on the named LLEventPump") @@ -343,7 +322,7 @@ void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_r if (shortchunk.length() > shortlen) shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); - std::string desc{ stringize("runScriptLine('", shortchunk, "')") }; + std::string desc{ stringize("lua: ", shortchunk) }; LLCoros::instance().launch(desc, [&L, desc, chunk, cb]() { auto [count, result] = L.expr(desc, chunk); diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 1f25fd5f3b..81ec186cf4 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -108,7 +108,6 @@ namespace tut replypump.listen("llluamanager_test", listener([&fromlua](const LLSD& data){ fromlua = data; }))); const std::string lua(stringize( - "-- test LLSD synthesized by Lua\n", "data = ", construct, "\n" "post_on('testpump', data)\n" )); @@ -134,7 +133,7 @@ namespace tut template<> template<> void object::test<3>() { - set_test_name("test post_on(), listen_events(), await_event()"); + set_test_name("test post_on(), get_event_pumps(), get_event_next()"); StringVec posts; LLEventStream replypump("testpump"); LLTempBoundListener conn( @@ -142,17 +141,14 @@ namespace tut listener([&posts](const LLSD& data) { posts.push_back(data.asString()); }))); const std::string lua( - "-- test post_on,listen_events,await_event\n" + "-- test post_on,get_event_pumps,get_event_next\n" "post_on('testpump', 'entry')\n" - "callback = function(pump, data)\n" - " -- just echo the data we received\n" - " post_on('testpump', data)\n" - "end\n" - "post_on('testpump', 'listen_events()')\n" - "replypump, cmdpump = listen_events(callback)\n" + "post_on('testpump', 'get_event_pumps()')\n" + "replypump, cmdpump = get_event_pumps()\n" "post_on('testpump', replypump)\n" - "post_on('testpump', 'await_event()')\n" - "await_event(replypump)\n" + "post_on('testpump', 'get_event_next()')\n" + "pump, data = get_event_next()\n" + "post_on('testpump', data)\n" "post_on('testpump', 'exit')\n" ); LuaState L; @@ -162,9 +158,9 @@ namespace tut auto future = LLLUAmanager::startScriptLine(L, lua); StringVec expected{ "entry", - "listen_events()", + "get_event_pumps()", "", - "await_event()", + "get_event_next()", "message", "exit" }; @@ -188,18 +184,15 @@ namespace tut listener([&reply](const LLSD& post){ reply = post; }))); const std::string lua( "-- test LLSD round trip\n" - "callback = function(pump, data)\n" - " -- just echo the data we received\n" - " post_on('testpump', data)\n" - "end\n" - "replypump, cmdpump = listen_events(callback)\n" + "replypump, cmdpump = get_event_pumps()\n" "post_on('testpump', replypump)\n" - "await_event(replypump)\n" + "pump, data = get_event_next()\n" + "return data\n" ); LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); // We woke up again ourselves because the coroutine running Lua has - // reached the await_event() call, which suspends the calling C++ + // reached the get_event_next() call, which suspends the calling C++ // coroutine (including the Lua code running on it) until we post // something to that reply pump. auto luapump{ reply.asString() }; @@ -208,7 +201,7 @@ namespace tut // The C++ coroutine running the Lua script is now ready to run. Run // it so it will echo the LLSD back to us. auto [count, result] = future.get(); - ensure_equals(desc, reply, expect); + ensure_equals(desc, result, expect); } // Define an RTItem to be used for round-trip LLSD testing: what it is, -- cgit v1.2.3 From 49785357e07f6309e2504b56829d9916f75168b2 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 23 Feb 2024 16:57:00 +0200 Subject: require() code clean-up --- indra/newview/llluamanager.cpp | 89 ++++++++++++------------------------------ indra/newview/llluamanager.h | 4 +- 2 files changed, 26 insertions(+), 67 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 164738bc3b..671410d420 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -46,6 +46,7 @@ extern LLUIListener sUIListener; #endif // ! LL_TEST #include <boost/algorithm/string/replace.hpp> +#include <filesystem> #include "luau/luacode.h" #include "luau/lua.h" @@ -307,8 +308,7 @@ void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, scrip if (in_file.is_open()) { - std::string text{std::istreambuf_iterator<char>(in_file), - std::istreambuf_iterator<char>()}; + std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); if (cb) { @@ -402,28 +402,6 @@ void LLLUAmanager::runScriptOnLogin() #endif // ! LL_TEST } - -bool is_absolute_path(std::string_view path) -{ -#ifdef LL_WINDOWS - // Must either begin with "X:/", "X:\", "/", or "\", where X is a drive letter - return (path.size() >= 3 && isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) || - (path.size() >= 1 && (path[0] == '/' || path[0] == '\\')); -#else - // Must begin with '/' - return path.size() >= 1 && path[0] == '/'; -#endif -} - -std::string join_paths(const std::string &lhs, const std::string &rhs) -{ - std::string result = lhs; - if (!result.empty() && result.back() != '/' && result.back() != '\\') - result += '/'; - result += rhs; - return result; -} - std::string read_file(const std::string &name) { llifstream in_file; @@ -431,20 +409,22 @@ std::string read_file(const std::string &name) if (in_file.is_open()) { - std::string text {std::istreambuf_iterator<char>(in_file), std::istreambuf_iterator<char>()}; + std::string text {std::istreambuf_iterator<char>(in_file), {}}; return text; } return std::string(); } -LLRequireResolver::LLRequireResolver(lua_State *L, std::string path) : mPathToResolve(std::move(path)), L(L) +LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : mPathToResolve(path), L(L) { lua_Debug ar; lua_getinfo(L, 1, "s", &ar); mSourceChunkname = ar.source; - if (is_absolute_path(mPathToResolve)) + mPathToResolve = std::filesystem::path(mPathToResolve).lexically_normal().string(); + + if (std::filesystem::path(mPathToResolve).is_absolute()) luaL_argerrorL(L, 1, "cannot require a full path"); std::replace(mPathToResolve.begin(), mPathToResolve.end(), '\\', '/'); @@ -457,7 +437,7 @@ LLRequireResolver::LLRequireResolver(lua_State *L, std::string path) : mPathToRe if (status != ModuleStatus::FileRead) return ResolvedRequire {status}; else - return ResolvedRequire {status, std::move(resolver.mChunkname), std::move(resolver.mAbsolutePath), std::move(resolver.mSourceCode)}; + return ResolvedRequire {status, resolver.mAbsolutePath, resolver.mSourceCode}; } LLRequireResolver::ModuleStatus LLRequireResolver::findModule() @@ -467,26 +447,24 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModule() // Put _MODULES table on stack for checking and saving to the cache luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1); + // Check if the module is already in _MODULES table, read from file otherwise LLRequireResolver::ModuleStatus moduleStatus = findModuleImpl(); if (moduleStatus != LLRequireResolver::ModuleStatus::NotFound) return moduleStatus; - if (is_absolute_path(mPathToResolve)) + if (std::filesystem::path(mPathToResolve).is_absolute()) return moduleStatus; - std::vector<std::string> lib_paths; - - lib_paths.push_back(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + std::vector<std::string> lib_paths {gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua")}; - for (size_t i = 0; i < lib_paths.size(); ++i) + for (const auto& path : lib_paths) { - std::string absolutePathOpt = join_paths(lib_paths[i], mPathToResolve); + std::string absolutePathOpt = (std::filesystem::path(path) / mPathToResolve).u8string(); if (absolutePathOpt.empty()) luaL_errorL(L, "error requiring module"); - mChunkname = absolutePathOpt; mAbsolutePath = absolutePathOpt; moduleStatus = findModuleImpl(); @@ -500,16 +478,12 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModule() LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() { - std::string possibleSuffixes[] = {".luau", ".lua"}; - - size_t unsuffixedAbsolutePathSize = mAbsolutePath.size(); + std::string possibleSuffixedPaths[] = {mAbsolutePath + ".luau", mAbsolutePath + ".lua"}; - for (auto possibleSuffix : possibleSuffixes) + for (auto suffixedPath : possibleSuffixedPaths) { - mAbsolutePath += possibleSuffix; - - // Check cache for module - lua_getfield(L, -1, mAbsolutePath.c_str()); + // Check _MODULES cache for module + lua_getfield(L, -1, suffixedPath.c_str()); if (!lua_isnil(L, -1)) { return ModuleStatus::Cached; @@ -517,15 +491,12 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() lua_pop(L, 1); // Try to read the matching file - std::string source = read_file(mAbsolutePath); + std::string source = read_file(suffixedPath); if (!source.empty()) { - mChunkname = "=" + mChunkname + possibleSuffix; mSourceCode = source; return ModuleStatus::FileRead; } - - mAbsolutePath.resize(unsuffixedAbsolutePathSize); // truncate to remove suffix } return ModuleStatus::NotFound; @@ -533,17 +504,12 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() void LLRequireResolver::resolveAndStoreDefaultPaths() { - if (!is_absolute_path(mPathToResolve)) + if (!std::filesystem::path(mPathToResolve).is_absolute()) { - std::string path = gDirUtilp->getDirName(mSourceChunkname); - std::replace(path.begin(), path.end(), '\\', '/'); - path = join_paths(path, mPathToResolve); - mAbsolutePath = path; - mChunkname = path; + mAbsolutePath = (std::filesystem::path((mSourceChunkname)).parent_path() / mPathToResolve).u8string();; } else { - mChunkname = mPathToResolve; mAbsolutePath = mPathToResolve; } } @@ -558,9 +524,9 @@ static int finishrequire(lua_State *L) lua_function(require, "require(module_name) : module_name can be fullpath or just the name, in both cases without .lua") { - std::string name = luaL_checkstring(L, 1); + std::string name = lua_tostdstring(L, 1); - LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, std::move(name)); + LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, name); if (resolvedRequire.status == LLRequireResolver::ModuleStatus::Cached) return finishrequire(L); @@ -577,18 +543,13 @@ lua_function(require, "require(module_name) : module_name can be fullpath or jus luaL_sandboxthread(ML); { - // now we can compile & run module on the new thread - size_t bytecodeSize = 0; - std::unique_ptr<char[], freer> bytecode { - luau_compile(resolvedRequire.sourceCode.c_str(), resolvedRequire.sourceCode.length(), nullptr, &bytecodeSize)}; - - if (luau_load(ML, resolvedRequire.chunkName.c_str(), bytecode.get(), bytecodeSize, 0) == 0) + if (lluau::loadstring(ML, resolvedRequire.absolutePath.c_str(), resolvedRequire.sourceCode.c_str()) == LUA_OK) { int status = lua_resume(ML, L, 0); - if (status == 0) + if (status == LUA_OK) { - if (lua_gettop(ML) == 0) + if (lua_gettop(ML) == LUA_OK) lua_pushstring(ML, "module must return a value"); else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1)) lua_pushstring(ML, "module must return a table or function"); diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index c382de3c62..43950ccee4 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -97,14 +97,12 @@ class LLRequireResolver struct ResolvedRequire { ModuleStatus status; - std::string chunkName; std::string absolutePath; std::string sourceCode; }; [[nodiscard]] ResolvedRequire static resolveRequire(lua_State *L, std::string path); - std::string mChunkname; std::string mAbsolutePath; std::string mSourceCode; @@ -112,7 +110,7 @@ class LLRequireResolver std::string mPathToResolve; std::string mSourceChunkname; - LLRequireResolver(lua_State *L, std::string path); + LLRequireResolver(lua_State *L, const std::string& path); ModuleStatus findModule(); lua_State *L; -- cgit v1.2.3 From 758378859ce2f5bac2e472f5f6f24061bce7c153 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 26 Feb 2024 20:08:13 +0200 Subject: Clean-up and restoring correct path --- indra/newview/llluamanager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 671410d420..54acb49b00 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -418,16 +418,17 @@ std::string read_file(const std::string &name) LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : mPathToResolve(path), L(L) { + //Luau lua_Debug and lua_getinfo() are different compared to default Lua: + //see https://github.com/luau-lang/luau/blob/80928acb92d1e4b6db16bada6d21b1fb6fa66265/VM/include/lua.h lua_Debug ar; lua_getinfo(L, 1, "s", &ar); mSourceChunkname = ar.source; - mPathToResolve = std::filesystem::path(mPathToResolve).lexically_normal().string(); + std::filesystem::path fs_path(mPathToResolve); + mPathToResolve = fs_path.lexically_normal().string(); - if (std::filesystem::path(mPathToResolve).is_absolute()) + if (fs_path.is_absolute()) luaL_argerrorL(L, 1, "cannot require a full path"); - - std::replace(mPathToResolve.begin(), mPathToResolve.end(), '\\', '/'); } [[nodiscard]] LLRequireResolver::ResolvedRequire LLRequireResolver::resolveRequire(lua_State *L, std::string path) @@ -494,6 +495,7 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() std::string source = read_file(suffixedPath); if (!source.empty()) { + mAbsolutePath = suffixedPath; mSourceCode = source; return ModuleStatus::FileRead; } -- cgit v1.2.3 From 01a94f9d8378bb1094f4272b37ed9b966703f0b6 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 26 Feb 2024 23:55:30 +0200 Subject: Clear the stack after requiring a module --- indra/newview/llluamanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 54acb49b00..4463fe65f5 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -530,8 +530,12 @@ lua_function(require, "require(module_name) : module_name can be fullpath or jus LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, name); - if (resolvedRequire.status == LLRequireResolver::ModuleStatus::Cached) + if (resolvedRequire.status == LLRequireResolver::ModuleStatus::Cached) + { + // remove _MODULES from stack + lua_remove(L, -2); return finishrequire(L); + } else if (resolvedRequire.status == LLRequireResolver::ModuleStatus::NotFound) luaL_errorL(L, "error requiring module"); @@ -571,6 +575,11 @@ lua_function(require, "require(module_name) : module_name can be fullpath or jus lua_pushvalue(L, -1); lua_setfield(L, -4, resolvedRequire.absolutePath.c_str()); - // L stack: _MODULES ML result + //remove _MODULES from stack + lua_remove(L, -3); + // remove ML from stack + lua_remove(L, -2); + + // L stack: [module name] [result] return finishrequire(L); } -- cgit v1.2.3 From 9dae3e96ee6b0cb4139f368488da85f9961d1d4f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Feb 2024 12:09:59 -0500 Subject: Refactor require() to make it easier to reason about Lua stack usage. Push throwing Lua errors down into LLRequireResolver::findModule() and findModuleImpl() so their callers don't have to handle the error case. That eliminates finishrequire(). require() itself now only retrieves (and pops) the passed module name and calls LLRequireResolver::resolveRequire() to do the actual work. resolveRequire() is now void. It only instantiates LLRequireResolver and calls its findModule(). findModule() is now also void. It's guaranteed to either push the loaded Lua module or throw a Lua error. In particular, when findPathImpl() cannot find the specified module, findModule() throws an error. That replaces ModuleStatus::NotFound. Since std::filesystem::path::append() aka operator/() detects when its right operand is absolute and, in that case, discards the left operand, we no longer need resolveAndStoreDefaultPaths(): we can just invoke that operation inline. When findModule() pushes _MODULES on the Lua stack, it uses LuaRemover (below) to ensure that _MODULES is removed again no matter how findModules() exits. findModuleImpl() now accepts the candidate pathname as its argument. That eliminates mAbsolutePath. findModuleImpl() now returns only bool: true means the module was found and loaded and pushed on the Lua stack, false means not found and nothing was pushed; no return means an error was reported. Push running a newly found module's source file down into findModuleImpl(). That eliminates the distinction between Cached and FileRead, which obviates ModuleStatus: a bool return means either "previously cached" or "we read it, compiled it, loaded it and ran it." That also eliminates the need to store the module's textual content in mSourceCode. Similarly, once loading the module succeeds, findModuleImpl() caches it in _MODULES right away. That eliminates ResolvedRequire since we need not pass the full pathname of the found module (or its contents) back up through the call chain. Move require() code that runs the new module into private runModule() method, called by findModuleImpl() in the not-cached case. runModule() is the only remaining method that can push either a string error message or the desired module, because of its funny stack manipulations. That means the check for a string error message on the stack top can move down to findModuleImpl(). Add LuaRemover class to ensure that on exit from some particular C++ block, the specified Lua stack entry will definitely be removed. This is different from LuaPopper in that it engages lua_remove() rather than lua_pop(). Also ditch obsolete await_event() Lua entry point. --- indra/newview/llluamanager.cpp | 233 +++++++++++++++++++++-------------------- indra/newview/llluamanager.h | 25 +---- 2 files changed, 125 insertions(+), 133 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 0c39f6c8df..80d7eb4210 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -195,30 +195,6 @@ lua_function(get_event_next, return 2; } -lua_function(await_event, - "await_event(pumpname [, timeout [, value to return if timeout (default nil)]]):\n" - "pause the running Lua chunk until the next event on the named LLEventPump") -{ - auto pumpname{ lua_tostdstring(L, 1) }; - LLSD result; - if (lua_gettop(L) > 1) - { - auto timeout{ lua_tonumber(L, 2) }; - // with no 3rd argument, should be LLSD() - auto dftval{ lua_tollsd(L, 3) }; - lua_settop(L, 0); - result = llcoro::suspendUntilEventOnWithTimeout(pumpname, timeout, dftval); - } - else - { - // no timeout - lua_pop(L, 1); - result = llcoro::suspendUntilEventOn(pumpname); - } - lua_pushllsd(L, result); - return 1; -} - void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb) { // A script_finished_fn is used to initialize the LuaState. @@ -361,14 +337,36 @@ std::string read_file(const std::string &name) if (in_file.is_open()) { - std::string text {std::istreambuf_iterator<char>(in_file), {}}; - return text; + return std::string{std::istreambuf_iterator<char>(in_file), {}}; } - return std::string(); + return {}; } -LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : mPathToResolve(path), L(L) +lua_function(require, "require(module_name) : load module_name.lua from known places") +{ + std::string name = lua_tostdstring(L, 1); + lua_pop(L, 1); + + // resolveRequire() does not return in case of error. + LLRequireResolver::resolveRequire(L, name); + + // resolveRequire() returned the newly-loaded module on the stack top. + // Return it. + return 1; +} + +// push loaded module or throw Lua error +void LLRequireResolver::resolveRequire(lua_State *L, std::string path) +{ + LLRequireResolver resolver(L, std::move(path)); + // findModule() pushes the loaded module or throws a Lua error. + resolver.findModule(); +} + +LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : + mPathToResolve(path), + L(L) { //Luau lua_Debug and lua_getinfo() are different compared to default Lua: //see https://github.com/luau-lang/luau/blob/80928acb92d1e4b6db16bada6d21b1fb6fa66265/VM/include/lua.h @@ -383,31 +381,59 @@ LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : mP luaL_argerrorL(L, 1, "cannot require a full path"); } -[[nodiscard]] LLRequireResolver::ResolvedRequire LLRequireResolver::resolveRequire(lua_State *L, std::string path) +/** + * Remove a particular stack index on exit from enclosing scope. + * If you pass a negative index (meaning relative to the current stack top), + * converts to an absolute index. The point of LuaRemover is to remove the + * entry at the specified index regardless of subsequent pushes to the stack. + */ +class LuaRemover { - LLRequireResolver resolver(L, std::move(path)); - ModuleStatus status = resolver.findModule(); - if (status != ModuleStatus::FileRead) - return ResolvedRequire {status}; - else - return ResolvedRequire {status, resolver.mAbsolutePath, resolver.mSourceCode}; -} +public: + LuaRemover(lua_State* L, int index): + mState(L), + mIndex(lua_absindex(L, index)) + {} + LuaRemover(const LuaRemover&) = delete; + LuaRemover& operator=(const LuaRemover&) = delete; + ~LuaRemover() + { + lua_remove(mState, mIndex); + } + +private: + lua_State* mState; + int mIndex; +}; -LLRequireResolver::ModuleStatus LLRequireResolver::findModule() +// push the loaded module or throw a Lua error +void LLRequireResolver::findModule() { - resolveAndStoreDefaultPaths(); + // If mPathToResolve is absolute, this replaces mSourceChunkname.parent_path. + auto absolutePath = (std::filesystem::path((mSourceChunkname)).parent_path() / mPathToResolve).u8string(); - // Put _MODULES table on stack for checking and saving to the cache + // Push _MODULES table on stack for checking and saving to the cache luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1); + // Remove that stack entry no matter how we exit + LuaRemover rm_MODULES(L, -1); + + // Check if the module is already in _MODULES table, read from file + // otherwise. + // findModuleImpl() pushes module if found, nothing if not, may throw Lua + // error. + if (findModuleImpl(absolutePath)) + return; - // Check if the module is already in _MODULES table, read from file otherwise - LLRequireResolver::ModuleStatus moduleStatus = findModuleImpl(); - - if (moduleStatus != LLRequireResolver::ModuleStatus::NotFound) - return moduleStatus; + // not already cached - prep error message just in case + auto fail{ + [L=L, path=mPathToResolve]() + { luaL_error(L, "could not find require('%s')", path.data()); }}; if (std::filesystem::path(mPathToResolve).is_absolute()) - return moduleStatus; + { + // no point searching known directories for an absolute path + fail(); + } std::vector<std::string> lib_paths {gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua")}; @@ -416,30 +442,31 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModule() std::string absolutePathOpt = (std::filesystem::path(path) / mPathToResolve).u8string(); if (absolutePathOpt.empty()) - luaL_errorL(L, "error requiring module"); - - mAbsolutePath = absolutePathOpt; - - moduleStatus = findModuleImpl(); + luaL_error(L, "error requiring module '%s'", mPathToResolve.data()); - if (moduleStatus != LLRequireResolver::ModuleStatus::NotFound) - return moduleStatus; + if (findModuleImpl(absolutePathOpt)) + return; } - return LLRequireResolver::ModuleStatus::NotFound; + // not found + fail(); } -LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() +// expects _MODULES table on stack top (and leaves it there) +// - if found, pushes loaded module and returns true +// - not found, pushes nothing and returns false +// - may throw Lua error +bool LLRequireResolver::findModuleImpl(const std::string& absolutePath) { - std::string possibleSuffixedPaths[] = {mAbsolutePath + ".luau", mAbsolutePath + ".lua"}; + std::string possibleSuffixedPaths[] = {absolutePath + ".luau", absolutePath + ".lua"}; - for (auto suffixedPath : possibleSuffixedPaths) + for (const auto& suffixedPath : possibleSuffixedPaths) { // Check _MODULES cache for module lua_getfield(L, -1, suffixedPath.c_str()); if (!lua_isnil(L, -1)) { - return ModuleStatus::Cached; + return true; } lua_pop(L, 1); @@ -447,91 +474,73 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() std::string source = read_file(suffixedPath); if (!source.empty()) { - mAbsolutePath = suffixedPath; - mSourceCode = source; - return ModuleStatus::FileRead; - } - } + // Try to run the loaded source. This will leave either a string + // error message or the module contents on the stack top. + runModule(suffixedPath, source); - return ModuleStatus::NotFound; -} + // If the stack top is an error message string, raise it. + if (lua_isstring(L, -1)) + lua_error(L); -void LLRequireResolver::resolveAndStoreDefaultPaths() -{ - if (!std::filesystem::path(mPathToResolve).is_absolute()) - { - mAbsolutePath = (std::filesystem::path((mSourceChunkname)).parent_path() / mPathToResolve).u8string();; - } - else - { - mAbsolutePath = mPathToResolve; - } -} + // duplicate the new module: _MODULES newmodule newmodule + lua_pushvalue(L, -1); + // store _MODULES[found path] = newmodule + lua_setfield(L, -3, source.data()); -static int finishrequire(lua_State *L) -{ - if (lua_isstring(L, -1)) - lua_error(L); + return true; + } + } - return 1; + return false; } -lua_function(require, "require(module_name) : module_name can be fullpath or just the name, in both cases without .lua") +// push string error message or new module +void LLRequireResolver::runModule(const std::string& desc, const std::string& code) { - std::string name = lua_tostdstring(L, 1); - - LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, name); - - if (resolvedRequire.status == LLRequireResolver::ModuleStatus::Cached) - { - // remove _MODULES from stack - lua_remove(L, -2); - return finishrequire(L); - } - else if (resolvedRequire.status == LLRequireResolver::ModuleStatus::NotFound) - luaL_errorL(L, "error requiring module"); - - // module needs to run in a new thread, isolated from the rest - // note: we create ML on main thread so that it doesn't inherit environment of L + // Here we just loaded a new module 'code', need to run it and get its result. + // Module needs to run in a new thread, isolated from the rest. + // Note: we create ML on main thread so that it doesn't inherit environment of L. lua_State *GL = lua_mainthread(L); lua_State *ML = lua_newthread(GL); + // lua_newthread() pushed the new thread object on GL's stack. Move to L's. lua_xmove(GL, L, 1); // new thread needs to have the globals sandboxed luaL_sandboxthread(ML); { - if (lluau::loadstring(ML, resolvedRequire.absolutePath.c_str(), resolvedRequire.sourceCode.c_str()) == LUA_OK) + // If loadstring() returns (! LUA_OK) then there's an error message on + // the stack. If it returns LUA_OK then the newly-loaded module code + // is on the stack. + if (lluau::loadstring(ML, desc, code) == LUA_OK) { + // luau uses Lua 5.3's version of lua_resume(): + // run the coroutine on ML, "from" L, passing no arguments. int status = lua_resume(ML, L, 0); if (status == LUA_OK) { - if (lua_gettop(ML) == LUA_OK) - lua_pushstring(ML, "module must return a value"); + if (lua_gettop(ML) == 0) + lua_pushfstring(ML, "module %s must return a value", desc.data()); else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1)) - lua_pushstring(ML, "module must return a table or function"); + lua_pushfstring(ML, "module %s must return a table or function, not %s", + desc.data(), lua_typename(ML, lua_type(ML, -1))); } else if (status == LUA_YIELD) { - lua_pushstring(ML, "module can not yield"); + lua_pushfstring(ML, "module %s can not yield", desc.data()); } else if (!lua_isstring(ML, -1)) { - lua_pushstring(ML, "unknown error while running module"); + lua_pushfstring(ML, "unknown error while running module %s", desc.data()); } } } - // there's now a return value on top of ML; L stack: _MODULES ML + // There's now a return value (string error message or module) on top of ML. + // Move return value to L's stack. lua_xmove(ML, L, 1); - lua_pushvalue(L, -1); - lua_setfield(L, -4, resolvedRequire.absolutePath.c_str()); - - //remove _MODULES from stack - lua_remove(L, -3); - // remove ML from stack + // remove ML from L's stack lua_remove(L, -2); - - // L stack: [module name] [result] - return finishrequire(L); +// // DON'T call lua_close(ML)! Since ML is only a thread of L, corrupts L too! +// lua_close(ML); } diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 43950ccee4..fb9f1b8141 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -87,24 +87,7 @@ public: class LLRequireResolver { public: - enum class ModuleStatus - { - Cached, - FileRead, - NotFound - }; - - struct ResolvedRequire - { - ModuleStatus status; - std::string absolutePath; - std::string sourceCode; - }; - - [[nodiscard]] ResolvedRequire static resolveRequire(lua_State *L, std::string path); - - std::string mAbsolutePath; - std::string mSourceCode; + static void resolveRequire(lua_State *L, std::string path); private: std::string mPathToResolve; @@ -112,10 +95,10 @@ class LLRequireResolver LLRequireResolver(lua_State *L, const std::string& path); - ModuleStatus findModule(); + void findModule(); lua_State *L; - void resolveAndStoreDefaultPaths(); - ModuleStatus findModuleImpl(); + bool findModuleImpl(const std::string& absolutePath); + void runModule(const std::string& desc, const std::string& code); }; #endif -- cgit v1.2.3 From 9bf2837505b7384ac18f1ae23de256729f561dfc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Feb 2024 14:01:02 -0500 Subject: Add indra/newview/scripts/lua directory, copied into viewer image. --- indra/newview/scripts/lua/testmod.lua | 2 ++ indra/newview/viewer_manifest.py | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 indra/newview/scripts/lua/testmod.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/testmod.lua b/indra/newview/scripts/lua/testmod.lua new file mode 100644 index 0000000000..22626e4038 --- /dev/null +++ b/indra/newview/scripts/lua/testmod.lua @@ -0,0 +1,2 @@ +print('scripts/lua/testmod.lua') +return function () return 'hello from scripts/lua/testmod.lua' end diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 1fa4df1682..562c7166a2 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -166,6 +166,9 @@ class ViewerManifest(LLManifest): self.path("*/*/*/*.js") self.path("*/*/*.html") + with self.prefix(src_dst="scripts/lua"): + self.path("*.lua") + #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing build_data_dict = {"Type":"viewer","Version":'.'.join(self.args['version']), -- cgit v1.2.3 From c369d436bece8b3ff60768897e88a7f40fdb877d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Feb 2024 15:07:25 -0500 Subject: Fix caching for loaded Lua require() modules. The code to save the loaded module was using the wrong key. --- indra/newview/llluamanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 80d7eb4210..cd663021a1 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -463,7 +463,7 @@ bool LLRequireResolver::findModuleImpl(const std::string& absolutePath) for (const auto& suffixedPath : possibleSuffixedPaths) { // Check _MODULES cache for module - lua_getfield(L, -1, suffixedPath.c_str()); + lua_getfield(L, -1, suffixedPath.data()); if (!lua_isnil(L, -1)) { return true; @@ -485,7 +485,7 @@ bool LLRequireResolver::findModuleImpl(const std::string& absolutePath) // duplicate the new module: _MODULES newmodule newmodule lua_pushvalue(L, -1); // store _MODULES[found path] = newmodule - lua_setfield(L, -3, source.data()); + lua_setfield(L, -3, suffixedPath.data()); return true; } -- cgit v1.2.3 From ba1f0060b42390bd4f63de7fe32b0d0e9360f633 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Feb 2024 15:08:20 -0500 Subject: Clarify that the print output from testmod.lua is load-time. --- indra/newview/scripts/lua/testmod.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/testmod.lua b/indra/newview/scripts/lua/testmod.lua index 22626e4038..60f7f80db1 100644 --- a/indra/newview/scripts/lua/testmod.lua +++ b/indra/newview/scripts/lua/testmod.lua @@ -1,2 +1,2 @@ -print('scripts/lua/testmod.lua') +print('loaded scripts/lua/testmod.lua') return function () return 'hello from scripts/lua/testmod.lua' end -- cgit v1.2.3 From d50d7c50651d5bcaf6f35349e2461351cf91224f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Feb 2024 15:09:49 -0500 Subject: Add Queue.lua from roblox.com documentation. --- indra/newview/scripts/lua/Queue.lua | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 indra/newview/scripts/lua/Queue.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/Queue.lua b/indra/newview/scripts/lua/Queue.lua new file mode 100644 index 0000000000..fa8737334c --- /dev/null +++ b/indra/newview/scripts/lua/Queue.lua @@ -0,0 +1,40 @@ +-- from https://create.roblox.com/docs/luau/queues#implementing-queues + +local Queue = {} +Queue.__index = Queue + +function Queue.new() + local self = setmetatable({}, Queue) + + self._first = 0 + self._last = -1 + self._queue = {} + + return self +end + +-- Check if the queue is empty +function Queue:IsEmpty() + return self._first > self._last +end + +-- Add a value to the queue +function Queue:Enqueue(value) + local last = self._last + 1 + self._last = last + self._queue[last] = value +end + +-- Remove a value from the queue +function Queue:Dequeue() + local first = self._first + if self:IsEmpty() then + return nil + end + local value = self._queue[first] + self._queue[first] = nil + self._first = first + 1 + return value +end + +return Queue -- cgit v1.2.3 From 6aee62f2bbdd06cf34c4042317cb52ec3c09570c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Feb 2024 16:47:42 -0500 Subject: Fix wonky Unicode chars from web paste --- indra/newview/scripts/lua/Queue.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/Queue.lua b/indra/newview/scripts/lua/Queue.lua index fa8737334c..e178ad9969 100644 --- a/indra/newview/scripts/lua/Queue.lua +++ b/indra/newview/scripts/lua/Queue.lua @@ -2,29 +2,29 @@ local Queue = {} Queue.__index = Queue - + function Queue.new() local self = setmetatable({}, Queue) - + self._first = 0 self._last = -1 self._queue = {} - + return self end - + -- Check if the queue is empty function Queue:IsEmpty() return self._first > self._last end - + -- Add a value to the queue function Queue:Enqueue(value) local last = self._last + 1 self._last = last self._queue[last] = value end - + -- Remove a value from the queue function Queue:Dequeue() local first = self._first @@ -36,5 +36,5 @@ function Queue:Dequeue() self._first = first + 1 return value end - + return Queue -- cgit v1.2.3 From c621fc39fc4ac25482fbc1090b8067c4187de176 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 6 Mar 2024 09:56:45 -0500 Subject: WIP: Unfinished Queue.lua, WaitQueue.lua, ErrorQueue.lua, leap.lua. Also qtest.lua to exercise the queue classes and inspect.lua (from https://github.com/kikito/inspect.lua) for debugging. --- indra/newview/scripts/lua/ErrorQueue.lua | 32 +++ indra/newview/scripts/lua/Queue.lua | 41 ++-- indra/newview/scripts/lua/WaitQueue.lua | 68 ++++++ indra/newview/scripts/lua/inspect.lua | 371 +++++++++++++++++++++++++++++++ indra/newview/scripts/lua/leap.lua | 284 +++++++++++++++++++++++ indra/newview/scripts/lua/qtest.lua | 47 ++++ 6 files changed, 823 insertions(+), 20 deletions(-) create mode 100644 indra/newview/scripts/lua/ErrorQueue.lua create mode 100644 indra/newview/scripts/lua/WaitQueue.lua create mode 100644 indra/newview/scripts/lua/inspect.lua create mode 100644 indra/newview/scripts/lua/leap.lua create mode 100644 indra/newview/scripts/lua/qtest.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua new file mode 100644 index 0000000000..e6279f8411 --- /dev/null +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -0,0 +1,32 @@ +-- ErrorQueue isa WaitQueue with the added feature that a producer can push an +-- error through the queue. When that error is dequeued, the consumer will +-- throw that error. + +local WaitQueue = require('WaitQueue') + +ErrorQueue = WaitQueue:new() + +function ErrorQueue:Enqueue(value) + -- normal value, not error + WaitQueue:Enqueue({ false, value }) +end + +function ErrorQueue:Error(message) + -- flag this entry as an error message + WaitQueue:Enqueue({ true, message }) +end + +function ErrorQueue:Dequeue() + local errflag, value = table.unpack(WaitQueue:Dequeue()) + if errflag == nil then + -- queue has been closed, tell caller + return nil + end + if errflag then + -- 'value' is a message pushed by Error() + error(value) + end + return value +end + +return ErrorQueue diff --git a/indra/newview/scripts/lua/Queue.lua b/indra/newview/scripts/lua/Queue.lua index e178ad9969..b0a5a87f87 100644 --- a/indra/newview/scripts/lua/Queue.lua +++ b/indra/newview/scripts/lua/Queue.lua @@ -1,40 +1,41 @@ --- from https://create.roblox.com/docs/luau/queues#implementing-queues +-- from https://create.roblox.com/docs/luau/queues#implementing-queues, +-- amended per https://www.lua.org/pil/16.1.html local Queue = {} -Queue.__index = Queue -function Queue.new() - local self = setmetatable({}, Queue) +function Queue:new() + local obj = setmetatable({}, self) + self.__index = self - self._first = 0 - self._last = -1 - self._queue = {} + obj._first = 0 + obj._last = -1 + obj._queue = {} - return self + return obj end -- Check if the queue is empty function Queue:IsEmpty() - return self._first > self._last + return self._first > self._last end -- Add a value to the queue function Queue:Enqueue(value) - local last = self._last + 1 - self._last = last - self._queue[last] = value + local last = self._last + 1 + self._last = last + self._queue[last] = value end -- Remove a value from the queue function Queue:Dequeue() - local first = self._first - if self:IsEmpty() then - return nil - end - local value = self._queue[first] - self._queue[first] = nil - self._first = first + 1 - return value + if self:IsEmpty() then + return nil + end + local first = self._first + local value = self._queue[first] + self._queue[first] = nil + self._first = first + 1 + return value end return Queue diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua new file mode 100644 index 0000000000..05d2056085 --- /dev/null +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -0,0 +1,68 @@ +-- WaitQueue isa Queue with the added feature that when the queue is empty, +-- the Dequeue() operation blocks the calling coroutine until some other +-- coroutine Enqueue()s a new value. + +local Queue = require('Queue') + +WaitQueue = Queue:new() + +function WaitQueue:new() + local obj = setmetatable(Queue:new(), self) + self.__index = self + obj._waiters = {} + obj._closed = false + return obj +end + +function WaitQueue:Enqueue(value) + if self._closed then + error("can't Enqueue() on closed Queue") + end + Queue:Enqueue(value) + -- WaitQueue is designed to support multi-producer, multi-consumer use + -- cases. With multiple consumers, if more than one is trying to + -- Dequeue() from an empty WaitQueue, we'll have multiple waiters. + -- Unlike OS threads, with cooperative concurrency it doesn't make sense + -- to "notify all": we need resume only one of the waiting Dequeue() + -- callers. But since resuming that caller might entail either Enqueue() + -- or Dequeue() calls, recheck every time around to see if we must resume + -- another waiting coroutine. + while not self:IsEmpty() and #self._waiters do + -- pop the oldest waiting coroutine instead of the most recent, for + -- more-or-less round robin fairness + local waiter = table.remove(self._waiters, 1) + -- don't pass the head item: let the resumed coroutine retrieve it + local ok, message = coroutine.resume(waiter) + -- if resuming that waiter encountered an error, don't swallow it + if not ok then + error(message) + end + end +end + +function WaitQueue:Dequeue() + while self:IsEmpty() do + -- Don't check for closed until the queue is empty: producer can close + -- the queue while there are still items left, and we want the + -- consumer(s) to retrieve those last few items. + if self._closed then + return nil + end + local coro = coroutine.running() + if coro == nil then + error("WaitQueue:Dequeue() trying to suspend main coroutine") + end + -- add the running coroutine to the list of waiters + table.insert(self._waiters, coro) + -- then let somebody else run + coroutine.yield() + end + -- here we're sure this queue isn't empty + return Queue:Dequeue() +end + +function WaitQueue:close() + self._closed = true +end + +return WaitQueue diff --git a/indra/newview/scripts/lua/inspect.lua b/indra/newview/scripts/lua/inspect.lua new file mode 100644 index 0000000000..9900a0b81b --- /dev/null +++ b/indra/newview/scripts/lua/inspect.lua @@ -0,0 +1,371 @@ +local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table +local inspect = {Options = {}, } + + + + + + + + + + + + + + + + + +inspect._VERSION = 'inspect.lua 3.1.0' +inspect._URL = 'http://github.com/kikito/inspect.lua' +inspect._DESCRIPTION = 'human-readable representations of tables' +inspect._LICENSE = [[ + MIT LICENSE + + Copyright (c) 2022 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] +inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end }) +inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end }) + +local tostring = tostring +local rep = string.rep +local match = string.match +local char = string.char +local gsub = string.gsub +local fmt = string.format + +local _rawget +if rawget then + _rawget = rawget +else + _rawget = function(t, k) return t[k] end +end + +local function rawpairs(t) + return next, t, nil +end + + + +local function smartQuote(str) + if match(str, '"') and not match(str, "'") then + return "'" .. str .. "'" + end + return '"' .. gsub(str, '"', '\\"') .. '"' +end + + +local shortControlCharEscapes = { + ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", + ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127", +} +local longControlCharEscapes = { ["\127"] = "\127" } +for i = 0, 31 do + local ch = char(i) + if not shortControlCharEscapes[ch] then + shortControlCharEscapes[ch] = "\\" .. i + longControlCharEscapes[ch] = fmt("\\%03d", i) + end +end + +local function escape(str) + return (gsub(gsub(gsub(str, "\\", "\\\\"), + "(%c)%f[0-9]", longControlCharEscapes), + "%c", shortControlCharEscapes)) +end + +local luaKeywords = { + ['and'] = true, + ['break'] = true, + ['do'] = true, + ['else'] = true, + ['elseif'] = true, + ['end'] = true, + ['false'] = true, + ['for'] = true, + ['function'] = true, + ['goto'] = true, + ['if'] = true, + ['in'] = true, + ['local'] = true, + ['nil'] = true, + ['not'] = true, + ['or'] = true, + ['repeat'] = true, + ['return'] = true, + ['then'] = true, + ['true'] = true, + ['until'] = true, + ['while'] = true, +} + +local function isIdentifier(str) + return type(str) == "string" and + not not str:match("^[_%a][_%a%d]*$") and + not luaKeywords[str] +end + +local flr = math.floor +local function isSequenceKey(k, sequenceLength) + return type(k) == "number" and + flr(k) == k and + 1 <= (k) and + k <= sequenceLength +end + +local defaultTypeOrders = { + ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, + ['function'] = 5, ['userdata'] = 6, ['thread'] = 7, +} + +local function sortKeys(a, b) + local ta, tb = type(a), type(b) + + + if ta == tb and (ta == 'string' or ta == 'number') then + return (a) < (b) + end + + local dta = defaultTypeOrders[ta] or 100 + local dtb = defaultTypeOrders[tb] or 100 + + + return dta == dtb and ta < tb or dta < dtb +end + +local function getKeys(t) + + local seqLen = 1 + while _rawget(t, seqLen) ~= nil do + seqLen = seqLen + 1 + end + seqLen = seqLen - 1 + + local keys, keysLen = {}, 0 + for k in rawpairs(t) do + if not isSequenceKey(k, seqLen) then + keysLen = keysLen + 1 + keys[keysLen] = k + end + end + table.sort(keys, sortKeys) + return keys, keysLen, seqLen +end + +local function countCycles(x, cycles) + if type(x) == "table" then + if cycles[x] then + cycles[x] = cycles[x] + 1 + else + cycles[x] = 1 + for k, v in rawpairs(x) do + countCycles(k, cycles) + countCycles(v, cycles) + end + countCycles(getmetatable(x), cycles) + end + end +end + +local function makePath(path, a, b) + local newPath = {} + local len = #path + for i = 1, len do newPath[i] = path[i] end + + newPath[len + 1] = a + newPath[len + 2] = b + + return newPath +end + + +local function processRecursive(process, + item, + path, + visited) + if item == nil then return nil end + if visited[item] then return visited[item] end + + local processed = process(item, path) + if type(processed) == "table" then + local processedCopy = {} + visited[item] = processedCopy + local processedKey + + for k, v in rawpairs(processed) do + processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) + if processedKey ~= nil then + processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) + end + end + + local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) + if type(mt) ~= 'table' then mt = nil end + setmetatable(processedCopy, mt) + processed = processedCopy + end + return processed +end + +local function puts(buf, str) + buf.n = buf.n + 1 + buf[buf.n] = str +end + + + +local Inspector = {} + + + + + + + + + + +local Inspector_mt = { __index = Inspector } + +local function tabify(inspector) + puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level)) +end + +function Inspector:getId(v) + local id = self.ids[v] + local ids = self.ids + if not id then + local tv = type(v) + id = (ids[tv] or 0) + 1 + ids[v], ids[tv] = id, id + end + return tostring(id) +end + +function Inspector:putValue(v) + local buf = self.buf + local tv = type(v) + if tv == 'string' then + puts(buf, smartQuote(escape(v))) + elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or + tv == 'cdata' or tv == 'ctype' then + puts(buf, tostring(v)) + elseif tv == 'table' and not self.ids[v] then + local t = v + + if t == inspect.KEY or t == inspect.METATABLE then + puts(buf, tostring(t)) + elseif self.level >= self.depth then + puts(buf, '{...}') + else + if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end + + local keys, keysLen, seqLen = getKeys(t) + + puts(buf, '{') + self.level = self.level + 1 + + for i = 1, seqLen + keysLen do + if i > 1 then puts(buf, ',') end + if i <= seqLen then + puts(buf, ' ') + self:putValue(t[i]) + else + local k = keys[i - seqLen] + tabify(self) + if isIdentifier(k) then + puts(buf, k) + else + puts(buf, "[") + self:putValue(k) + puts(buf, "]") + end + puts(buf, ' = ') + self:putValue(t[k]) + end + end + + local mt = getmetatable(t) + if type(mt) == 'table' then + if seqLen + keysLen > 0 then puts(buf, ',') end + tabify(self) + puts(buf, '<metatable> = ') + self:putValue(mt) + end + + self.level = self.level - 1 + + if keysLen > 0 or type(mt) == 'table' then + tabify(self) + elseif seqLen > 0 then + puts(buf, ' ') + end + + puts(buf, '}') + end + + else + puts(buf, fmt('<%s %d>', tv, self:getId(v))) + end +end + + + + +function inspect.inspect(root, options) + options = options or {} + + local depth = options.depth or (math.huge) + local newline = options.newline or '\n' + local indent = options.indent or ' ' + local process = options.process + + if process then + root = processRecursive(process, root, {}, {}) + end + + local cycles = {} + countCycles(root, cycles) + + local inspector = setmetatable({ + buf = { n = 0 }, + ids = {}, + cycles = cycles, + depth = depth, + level = 0, + newline = newline, + indent = indent, + }, Inspector_mt) + + inspector:putValue(root) + + return table.concat(inspector.buf) +end + +setmetatable(inspect, { + __call = function(_, root, options) + return inspect.inspect(root, options) + end, +}) + +return inspect diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua new file mode 100644 index 0000000000..351e1bf007 --- /dev/null +++ b/indra/newview/scripts/lua/leap.lua @@ -0,0 +1,284 @@ +-- Lua implementation of LEAP (LLSD Event API Plugin) protocol +-- +-- This module supports Lua scripts run by the Second Life viewer. +-- +-- LEAP protocol passes LLSD objects, converted to/from Lua tables, in both +-- directions. A typical LLSD object is a map containing keys 'pump' and +-- 'data'. +-- +-- The viewer's Lua post_to(pump, data) function posts 'data' to the +-- LLEventPump 'pump'. This is typically used to engage an LLEventAPI method. +-- +-- Similarly, the viewer gives each Lua script its own LLEventPump with a +-- unique name. That name is returned by get_event_pumps(). Every event +-- received on that LLEventPump is queued for retrieval by get_event_next(), +-- which returns (pump, data): the name of the LLEventPump on which the event +-- was received and the received event data. When the queue is empty, +-- get_event_next() blocks the calling Lua script until the next event is +-- received. + +local leap = {} + +-- _reply: string name of reply LLEventPump. Any events the viewer posts to +-- this pump will be queued for get_event_next(). We usually specify it as the +-- reply pump for requests to internal viewer services. +-- _command: string name of command LLEventPump. post_to(_command, ...) +-- engages LLLeapListener operations such as listening on a specified other +-- LLEventPump, etc. +leap._reply, leap._command = get_event_pumps() +-- Dict of features added to the LEAP protocol since baseline implementation. +-- Before engaging a new feature that might break an older viewer, we can +-- check for the presence of that feature key. This table is solely about the +-- LEAP protocol itself, the way we communicate with the viewer. To discover +-- whether a given listener exists, or supports a particular operation, use +-- _command's "getAPI" operation. +-- For Lua, _command's "getFeatures" operation suffices? +-- leap._features = {} + +-- Each outstanding request() or generate() call has a corresponding +-- WaitForReqid object (later in this module) to handle the +-- response(s). If an incoming event contains an echoed ["reqid"] key, +-- we can look up the appropriate WaitForReqid object more efficiently +-- in a dict than by tossing such objects into the usual waitfors list. +-- Note: the ["reqid"] must be unique, otherwise we could end up +-- replacing an earlier WaitForReqid object in self.pending with a +-- later one. That means that no incoming event will ever be given to +-- the old WaitForReqid object. Any coroutine waiting on the discarded +-- WaitForReqid object would therefore wait forever. +leap._pending = {} +-- Our consumer will instantiate some number of WaitFor subclass objects. +-- As these are traversed in descending priority order, we must keep +-- them in a list. +leap._waitfors = {} +-- It has been suggested that we should use UUIDs as ["reqid"] values, +-- since UUIDs are guaranteed unique. However, as the "namespace" for +-- ["reqid"] values is our very own _reply pump, we can get away with +-- an integer. +leap._reqid = 0 + +-- get the name of the reply pump +function leap.replypump() + return leap._reply +end + +-- get the name of the command pump +function leap.cmdpump() + return leap._command +end + +-- Fire and forget. Send the specified request LLSD, expecting no reply. +-- In fact, should the request produce an eventual reply, it will be +-- treated as an unsolicited event. +-- +-- See also request(), generate(). +function leap.send(pump, data, reqid) + local data = data + if type(data) == 'table' then + data = table.clone(data) + data['reply'] = leap._reply + if reqid ~= nil then + data['reqid'] = reqid + end + end + post_to(pump, data) +end + +-- Send the specified request LLSD, expecting exactly one reply. Block +-- the calling coroutine until we receive that reply. +-- +-- Every request() (or generate()) LLSD block we send will get stamped +-- with a distinct ["reqid"] value. The requested event API must echo the +-- same ["reqid"] field in each reply associated with that request. This way +-- we can correctly dispatch interleaved replies from different requests. +-- +-- If the desired event API doesn't support the ["reqid"] echo convention, +-- you should use send() instead -- since request() or generate() would +-- wait forever for a reply stamped with that ["reqid"] -- and intercept +-- any replies using WaitFor. +-- +-- Unless the request data already contains a ["reply"] key, we insert +-- reply=self.replypump to try to ensure that the expected reply will be +-- returned over the socket. +function leap.request(pump, data) + local reqid = leap._requestSetup(pump, data) + local ok, response = pcall(leap._pending[reqid].wait) + -- kill off temporary WaitForReqid object, even if error + leap._pending[reqid] = nil + if ok then + return response + else + error(response) + end +end + +-- common setup code shared by request() and generate() +function leap._requestSetup(pump, data) + -- invent a new, unique reqid + local reqid = leap._reqid + leap._reqid += 1 + -- Instantiate a new WaitForReqid object. The priority is irrelevant + -- because, unlike the WaitFor base class, WaitForReqid does not + -- self-register on our leap._waitfors list. Instead, capture the new + -- WaitForReqid object in leap._pending so _dispatch() can find it. + leap._pending[reqid] = WaitForReqid.new(reqid) + -- Pass reqid to send() to stamp it into (a copy of) the request data. + leap.send(pump, data, reqid) + return reqid +end + +-- Send the specified request LLSD, expecting an arbitrary number of replies. +-- Each one is yielded on receipt. If you omit checklast, this is an infinite +-- generator; it's up to the caller to recognize when the last reply has been +-- received, and stop resuming for more. +-- +-- If you pass checklast=<callable accepting(event)>, each response event is +-- passed to that callable (after the yield). When the callable returns +-- True, the generator terminates in the usual way. +-- +-- See request() remarks about ["reqid"]. +function leap.generate(pump, data, checklast) + -- Invent a new, unique reqid. Arrange to handle incoming events + -- bearing that reqid. Stamp the outbound request with that reqid, and + -- send it. + local reqid = leap._requestSetup(pump, data) + local ok, response + repeat + ok, response = pcall(leap._pending[reqid].wait) + if not ok then + break + end + coroutine.yield(response) + until checklast and checklast(response) + -- If we break the above loop, whether or not due to error, clean up. + leap._pending[reqid] = nil + if not ok then + error(response) + end +end + +-- Kick off response processing. The calling script must create and resume one +-- or more coroutines to perform viewer requests using send(), request() or +-- generate() before calling this function to handle responses. +-- +-- While waiting for responses from the viewer, the C++ coroutine running the +-- calling Lua script is blocked: no other Lua coroutine is running. +function leap.process() + local ok, pump, data + while true do + ok, pump, data = pcall(get_event_next) + if not ok then + break + end + leap._dispatch(pump, data) + end + -- we're done: clean up all pending coroutines + for i, waitfor in pairs(leap._pending) do + waitfor._exception(pump) + end + for i, waitfor in pairs(leap._waitfors) do + waitfor._exception(pump) + end +end + +-- Route incoming (pump, data) event to the appropriate waiting coroutine. +function leap._dispatch(pump, data) + local reqid = data['reqid'] + -- if the response has no 'reqid', it's not from request() or generate() + if reqid == nil then + return leap._unsolicited(pump, data) + end + -- have reqid; do we have a WaitForReqid? + local waitfor = leap._pending[reqid] + if waitfor == nil then + return leap._unsolicited(pump, data) + end + -- found the right WaitForReqid object, let it handle the event + data['reqid'] = nil + waitfor._handle(pump, data) +end + +-- Handle an incoming (pump, data) event with no recognizable ['reqid'] +function leap._unsolicited(pump, data) + -- we maintain waitfors in descending priority order, so the first waitfor + -- to claim this event is the one with the highest priority + for i, waitfor in pairs(leap._waitfors) do + if waitfor._handle(pump, data) then + return + end + end + print_debug('_unsolicited(', pump, ', ', data, ') discarding unclaimed event') +end + +-- called by WaitFor.enable() +function leap._registerWaitFor(waitfor) + table.insert(leap._waitfors, waitfor) + -- keep waitfors sorted in descending order of specified priority + table.sort(leap._waitfors, + function (lhs, rhs) return lhs.priority > rhs.priority end) +end + +-- called by WaitFor.disable() +function leap._unregisterWaitFor(waitfor) + for i, w in pairs(leap._waitfors) do + if w == waitfor then + leap._waitfors[i] = nil + break + end + end +end + +-- ****************************************************************************** +-- WaitFor and friends +-- ****************************************************************************** + +-- An unsolicited event is handled by the highest-priority WaitFor subclass +-- object willing to accept it. If no such object is found, the unsolicited +-- event is discarded. +-- +-- - First, instantiate a WaitFor subclass object to register its interest in +-- some incoming event(s). WaitFor instances are self-registering; merely +-- instantiating the object suffices. +-- - Any coroutine may call a given WaitFor object's wait() method. This blocks +-- the calling coroutine until a suitable event arrives. +-- - WaitFor's constructor accepts a float priority. Every incoming event +-- (other than those claimed by request() or generate()) is passed to each +-- extant WaitFor.filter() method in descending priority order. The first +-- such filter() to return nontrivial data claims that event. +-- - At that point, the blocked wait() call on that WaitFor object returns the +-- item returned by filter(). +-- - WaitFor contains a queue. Multiple arriving events claimed by that WaitFor +-- object's filter() method are added to the queue. Naturally, until the +-- queue is empty, calling wait() immediately returns the front entry. +-- +-- It's reasonable to instantiate a WaitFor subclass whose filter() method +-- unconditionally returns the incoming event, and whose priority places it +-- last in the list. This object will enqueue every unsolicited event left +-- unclaimed by other WaitFor subclass objects. +-- +-- It's not strictly necessary to associate a WaitFor object with exactly one +-- coroutine. You might have multiple "worker" coroutines drawing from the same +-- WaitFor object, useful if the work being done per event might itself involve +-- "blocking" operations. Or a given coroutine might sample a number of WaitFor +-- objects in round-robin fashion... etc. etc. Nonetheless, it's +-- straightforward to designate one coroutine for each WaitFor object. +leap.WaitFor = {} + +function leap.WaitFor:new() + obj = setmetatable({}, self) + self.__index = self + + + + self._first = 0 + self._last = -1 + self._queue = {} + + return obj +end + +-- Check if the queue is empty +function Queue:IsEmpty() + return self._first > self._last +end + +return leap diff --git a/indra/newview/scripts/lua/qtest.lua b/indra/newview/scripts/lua/qtest.lua new file mode 100644 index 0000000000..16a54be0d1 --- /dev/null +++ b/indra/newview/scripts/lua/qtest.lua @@ -0,0 +1,47 @@ +-- Exercise the Queue, WaitQueue, ErrorQueue family + +Queue = require('Queue') +WaitQueue = require('WaitQueue') +ErrorQueue = require('ErrorQueue') + +q1 = Queue:new() +q2 = Queue:new() + +q1:Enqueue(17) + +assert(not q1:IsEmpty()) +assert(q2:IsEmpty()) +assert(q1:Dequeue() == 17) +assert(q1:Dequeue() == nil) +assert(q2:Dequeue() == nil) + +q1 = WaitQueue:new() + +inspect = require('inspect') +print(inspect(q1)) + +q2 = WaitQueue:new() +result = {} + +values = { 1, 1, 2, 3, 5, 8, 13, 21 } +for i, value in pairs(values) do + q1:Enqueue(value) +end + +function consumer(desc, q) + print('consumer(', desc, ') start') + local value = q:Dequeue() + while value ~= nil do + table.insert(result, value) + value = q:Dequeue() + end + print('consumer(', desc, ') done') +end + +coa = coroutine.create(consumer) +cob = coroutine.create(consumer) +coroutine.resume(coa, 'a', q1) +coroutine.resume(cob, 'b', q1) + +assert(result == values) + -- cgit v1.2.3 From 6abe0f3a734f4a567db157c7627aa82f1c84c1f0 Mon Sep 17 00:00:00 2001 From: Cosmic Linden <cosmic@lindenlab.com> Date: Wed, 6 Mar 2024 15:59:08 -0800 Subject: secondlife/viewer-issues#75: Remove "HTTP Textures" setting in Developer menu --- indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 38763cd9a8..58397afeb5 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3969,16 +3969,6 @@ function="World.EnvPreset" <menu_item_separator/> - <menu_item_check - label="HTTP Textures" - name="HTTP Textures"> - <menu_item_check.on_check - function="CheckControl" - parameter="ImagePipelineUseHTTP" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="ImagePipelineUseHTTP" /> - </menu_item_check> <menu_item_call label="Compress Images" name="Compress Images"> -- cgit v1.2.3 From 63dcb3802c8139ff3b87b614cb275236cecea858 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 7 Mar 2024 13:46:24 -0500 Subject: Finish WaitQueue, ErrorQueue; add util.count(), join(); extend qtest. For WaitQueue, nail down the mechanism for declaring a subclass and for calling a base-class method from a subclass override. Break out new _wake_waiters() method from Enqueue(): we need to do the same from close(), in case there are waiting consumers. Also, in Lua, 0 is not false. Instead of bundling a normal/error flag with every queued value, make ErrorQueue overload its _closed attribute. Once you call ErrorQueue:Error(), every subsequent Dequeue() call by any consumer will re-raise the same error. util.count() literally counts entries in a table, since #t is documented to be unreliable. (If you create a list with 5 entries and delete the middle one, #t might return 2 or it might return 5, but it won't return 4.) util.join() fixes a curious omission from Luau's string library: like Python's str.join(), it concatenates all the strings from a list with an optional separator. We assume that incrementally building a list of strings and then doing a single allocation for the desired result string is cheaper than reallocating each of a sequence of partial concatenated results. Add qtest test that posts individual items to a WaitQueue, waking waiting consumers to retrieve the next available result. Add test proving that calling ErrorQueue:Error() propagates the error to all consumers. --- indra/newview/scripts/lua/ErrorQueue.lua | 32 +++++----- indra/newview/scripts/lua/WaitQueue.lua | 20 +++++-- indra/newview/scripts/lua/qtest.lua | 100 ++++++++++++++++++++++++++++--- indra/newview/scripts/lua/util.lua | 72 ++++++++++++++++++++++ 4 files changed, 195 insertions(+), 29 deletions(-) create mode 100644 indra/newview/scripts/lua/util.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index e6279f8411..db7022661e 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -1,32 +1,30 @@ -- ErrorQueue isa WaitQueue with the added feature that a producer can push an --- error through the queue. When that error is dequeued, the consumer will --- throw that error. +-- error through the queue. Once that error is dequeued, every consumer will +-- raise that error. local WaitQueue = require('WaitQueue') ErrorQueue = WaitQueue:new() -function ErrorQueue:Enqueue(value) - -- normal value, not error - WaitQueue:Enqueue({ false, value }) -end - function ErrorQueue:Error(message) - -- flag this entry as an error message - WaitQueue:Enqueue({ true, message }) + -- Setting Error() is a marker, like closing the queue. Once we reach the + -- error, every subsequent Dequeue() call will raise the same error. + self._closed = message + self:_wake_waiters() end function ErrorQueue:Dequeue() - local errflag, value = table.unpack(WaitQueue:Dequeue()) - if errflag == nil then - -- queue has been closed, tell caller - return nil + local value = WaitQueue.Dequeue(self) + if value ~= nil then + -- queue not yet closed, show caller + return value end - if errflag then - -- 'value' is a message pushed by Error() - error(value) + if self._closed == true then + -- WaitQueue:close() sets true: queue has only been closed, tell caller + return nil end - return value + -- self._closed is a message set by Error() + error(self._closed) end return ErrorQueue diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index 05d2056085..6a64c3dd67 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -7,8 +7,10 @@ local Queue = require('Queue') WaitQueue = Queue:new() function WaitQueue:new() - local obj = setmetatable(Queue:new(), self) + local obj = Queue:new() + setmetatable(obj, self) self.__index = self + obj._waiters = {} obj._closed = false return obj @@ -18,7 +20,14 @@ function WaitQueue:Enqueue(value) if self._closed then error("can't Enqueue() on closed Queue") end - Queue:Enqueue(value) + -- can't simply call Queue:Enqueue(value)! That calls the method on the + -- Queue class definition, instead of calling Queue:Enqueue() on self. + -- Hand-expand the Queue:Enqueue() syntactic sugar. + Queue.Enqueue(self, value) + self:_wake_waiters() +end + +function WaitQueue:_wake_waiters() -- WaitQueue is designed to support multi-producer, multi-consumer use -- cases. With multiple consumers, if more than one is trying to -- Dequeue() from an empty WaitQueue, we'll have multiple waiters. @@ -27,7 +36,7 @@ function WaitQueue:Enqueue(value) -- callers. But since resuming that caller might entail either Enqueue() -- or Dequeue() calls, recheck every time around to see if we must resume -- another waiting coroutine. - while not self:IsEmpty() and #self._waiters do + while not self:IsEmpty() and #self._waiters > 0 do -- pop the oldest waiting coroutine instead of the most recent, for -- more-or-less round robin fairness local waiter = table.remove(self._waiters, 1) @@ -58,11 +67,14 @@ function WaitQueue:Dequeue() coroutine.yield() end -- here we're sure this queue isn't empty - return Queue:Dequeue() + return Queue.Dequeue(self) end function WaitQueue:close() self._closed = true + -- close() is like Enqueueing an end marker. If there are waiting + -- consumers, give them a chance to see we're closed. + self:_wake_waiters() end return WaitQueue diff --git a/indra/newview/scripts/lua/qtest.lua b/indra/newview/scripts/lua/qtest.lua index 16a54be0d1..12e425b7b2 100644 --- a/indra/newview/scripts/lua/qtest.lua +++ b/indra/newview/scripts/lua/qtest.lua @@ -3,7 +3,11 @@ Queue = require('Queue') WaitQueue = require('WaitQueue') ErrorQueue = require('ErrorQueue') +util = require('util') +inspect = require('inspect') + +-- ------------------ Queue variables are instance-specific ------------------ q1 = Queue:new() q2 = Queue:new() @@ -15,33 +19,113 @@ assert(q1:Dequeue() == 17) assert(q1:Dequeue() == nil) assert(q2:Dequeue() == nil) +-- ----------------------------- test WaitQueue ------------------------------ q1 = WaitQueue:new() - -inspect = require('inspect') -print(inspect(q1)) - q2 = WaitQueue:new() result = {} - values = { 1, 1, 2, 3, 5, 8, 13, 21 } + for i, value in pairs(values) do q1:Enqueue(value) end +-- close() while not empty tests that queue drains before reporting done +q1:close() +-- ensure that WaitQueue instance variables are in fact independent +assert(q2:IsEmpty()) + +-- consumer() coroutine to pull from the passed q until closed function consumer(desc, q) - print('consumer(', desc, ') start') + print(string.format('consumer(%s) start', desc)) local value = q:Dequeue() while value ~= nil do + print(string.format('consumer(%s) got %q', desc, value)) table.insert(result, value) value = q:Dequeue() end - print('consumer(', desc, ') done') + print(string.format('consumer(%s) done', desc)) end +-- run two consumers coa = coroutine.create(consumer) cob = coroutine.create(consumer) +-- Since consumer() doesn't yield while it can still retrieve values, +-- consumer(a) will dequeue all values from q1 and return when done. coroutine.resume(coa, 'a', q1) +-- consumer(b) will wake up to find the queue empty and closed. coroutine.resume(cob, 'b', q1) +coroutine.close(coa) +coroutine.close(cob) + +print('values:', inspect(values)) +print('result:', inspect(result)) + +assert(util.equal(values, result)) + +-- try incrementally enqueueing values +q3 = WaitQueue:new() +result = {} +values = { 'This', 'is', 'a', 'test', 'script' } + +coros = {} +for _, name in {'a', 'b'} do + local coro = coroutine.create(consumer) + table.insert(coros, coro) + -- Resuming both coroutines should leave them both waiting for a queue item. + coroutine.resume(coro, name, q3) +end + +for _, s in pairs(values) do + print(string.format('Enqueue(%q)', s)) + q3:Enqueue(s) +end +q3:close() + +function joinall(coros) + local running + local errors = 0 + repeat + running = false + for i, coro in pairs(coros) do + if coroutine.status(coro) == 'suspended' then + running = true + local ok, message = coroutine.resume(coro) + if not ok then + print('*** ' .. message) + errors += 1 + end + if coroutine.status(coro) == 'dead' then + coros[i] = nil + end + end + end + until not running + return errors +end + +joinall(coros) + +print(string.format('%q', util.join(result, ' '))) +assert(util.equal(values, result)) + +-- ----------------------------- test ErrorQueue ----------------------------- +q4 = ErrorQueue:new() +result = {} +values = { 'This', 'is', 'a', 'test', 'script' } + +coros = {} +for _, name in {'a', 'b'} do + local coro = coroutine.create(consumer) + table.insert(coros, coro) + -- Resuming both coroutines should leave them both waiting for a queue item. + coroutine.resume(coro, name, q4) +end + +for i = 1, 4 do + print(string.format('Enqueue(%q)', values[i])) + q4:Enqueue(values[i]) +end +q4:Error('something went wrong') -assert(result == values) +assert(joinall(coros) == 2) diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua new file mode 100644 index 0000000000..bb8d492d12 --- /dev/null +++ b/indra/newview/scripts/lua/util.lua @@ -0,0 +1,72 @@ +-- utility functions, in alpha order + +local util = {} + +-- cheap test whether table t is empty +function util.empty(t) + for _ in pairs(t) do + return false + end + return true +end + +-- reliable count of the number of entries in table t +-- (since #t is unreliable) +function util.count(t) + local count = 0 + for _ in pairs(t) do + count += 1 + end + return count +end + +-- recursive table equality +function util.equal(t1, t2) + if not (type(t1) == 'table' and type(t2) == 'table') then + return t1 == t2 + end + -- both t1 and t2 are tables: get modifiable copy of t2 + local temp = table.clone(t2) + for k, v in pairs(t1) do + -- if any key in t1 doesn't have same value in t2, not equal + if not util.equal(v, temp[k]) then + return false + end + -- temp[k] == t1[k], delete temp[k] + temp[k] = nil + end + -- All keys in t1 have equal values in t2; t2 == t1 if there are no extra keys in t2 + return util.empty(temp) +end + +-- Concatentate the strings in the passed list, return the composite string. +-- For iterative string building, the theory is that building a list with +-- table.insert() and then using join() to allocate the full-size result +-- string once should be more efficient than reallocating an intermediate +-- string for every partial concatenation. +function util.join(list, sep) + -- This succinct implementation assumes that string.format() precomputes + -- the required size of its output buffer before populating it. We don't + -- know that. Moreover, this implementation predates our sep argument. +-- return string.format(string.rep('%s', #list), table.unpack(list)) + + -- this implementation makes it explicit + local sep = sep or '' + local size = if util.empty(list) then 0 else -#sep + for _, s in pairs(list) do + size += #sep + #s + end + local result = buffer.create(size) + size = 0 + for i, s in pairs(list) do + if i > 1 then + buffer.writestring(result, size, sep) + size += #sep + end + buffer.writestring(result, size, s) + size += #s + end + return buffer.tostring(result) +end + +return util -- cgit v1.2.3 From 7f46c285263acd65587884a6704f07fb7f391e92 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 7 Mar 2024 16:41:39 -0500 Subject: Finish adding leap.WaitFor and WaitForReqid. Untested. --- indra/newview/scripts/lua/ErrorQueue.lua | 2 +- indra/newview/scripts/lua/WaitQueue.lua | 2 +- indra/newview/scripts/lua/leap.lua | 141 +++++++++++++++++++++++++++---- 3 files changed, 127 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index db7022661e..a6d4470044 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -4,7 +4,7 @@ local WaitQueue = require('WaitQueue') -ErrorQueue = WaitQueue:new() +local ErrorQueue = WaitQueue:new() function ErrorQueue:Error(message) -- Setting Error() is a marker, like closing the queue. Once we reach the diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index 6a64c3dd67..e6adde0573 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -4,7 +4,7 @@ local Queue = require('Queue') -WaitQueue = Queue:new() +local WaitQueue = Queue:new() function WaitQueue:new() local obj = Queue:new() diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 351e1bf007..708df821e8 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -17,6 +17,8 @@ -- get_event_next() blocks the calling Lua script until the next event is -- received. +local ErrorQueue = require('ErrorQueue') + local leap = {} -- _reply: string name of reply LLEventPump. Any events the viewer posts to @@ -120,7 +122,7 @@ function leap._requestSetup(pump, data) -- because, unlike the WaitFor base class, WaitForReqid does not -- self-register on our leap._waitfors list. Instead, capture the new -- WaitForReqid object in leap._pending so _dispatch() can find it. - leap._pending[reqid] = WaitForReqid.new(reqid) + leap._pending[reqid] = leap.WaitForReqid:new(reqid) -- Pass reqid to send() to stamp it into (a copy of) the request data. leap.send(pump, data, reqid) return reqid @@ -178,6 +180,10 @@ function leap.process() for i, waitfor in pairs(leap._waitfors) do waitfor._exception(pump) end + -- now that we're done with cleanup, propagate the error we caught above + if not ok then + error(pump) + end end -- Route incoming (pump, data) event to the appropriate waiting coroutine. @@ -235,18 +241,18 @@ end -- object willing to accept it. If no such object is found, the unsolicited -- event is discarded. -- --- - First, instantiate a WaitFor subclass object to register its interest in +-- * First, instantiate a WaitFor subclass object to register its interest in -- some incoming event(s). WaitFor instances are self-registering; merely -- instantiating the object suffices. --- - Any coroutine may call a given WaitFor object's wait() method. This blocks +-- * Any coroutine may call a given WaitFor object's wait() method. This blocks -- the calling coroutine until a suitable event arrives. --- - WaitFor's constructor accepts a float priority. Every incoming event +-- * WaitFor's constructor accepts a float priority. Every incoming event -- (other than those claimed by request() or generate()) is passed to each -- extant WaitFor.filter() method in descending priority order. The first -- such filter() to return nontrivial data claims that event. --- - At that point, the blocked wait() call on that WaitFor object returns the +-- * At that point, the blocked wait() call on that WaitFor object returns the -- item returned by filter(). --- - WaitFor contains a queue. Multiple arriving events claimed by that WaitFor +-- * WaitFor contains a queue. Multiple arriving events claimed by that WaitFor -- object's filter() method are added to the queue. Naturally, until the -- queue is empty, calling wait() immediately returns the front entry. -- @@ -261,24 +267,127 @@ end -- "blocking" operations. Or a given coroutine might sample a number of WaitFor -- objects in round-robin fashion... etc. etc. Nonetheless, it's -- straightforward to designate one coroutine for each WaitFor object. -leap.WaitFor = {} -function leap.WaitFor:new() - obj = setmetatable({}, self) +-- --------------------------------- WaitFor --------------------------------- +leap.WaitFor = { _id=0 } + +function leap.WaitFor:new(priority, name) + local obj = setmetatable({}, self) self.__index = self - + obj.priority = priority + if name then + obj.name = name + else + self._id += 1 + obj.name = 'WaitFor' .. self._id + end + obj._queue = ErrorQueue:new() + obj._registered = false + obj:enable() + + return obj +end + +function leap.WaitFor.tostring(self) + -- Lua (sub)classes have no name; can't prefix with that + return self.name +end + +-- Re-enable a disable()d WaitFor object. New WaitFor objects are +-- enable()d by default. +function leap.WaitFor:enable() + if not self._registered then + leap._registerWaitFor(self) + self._registered = true + end +end + +-- Disable an enable()d WaitFor object. +function leap.WaitFor:disable() + if self._registered then + leap._unregisterWaitFor(self) + self._registered = false + end +end + +-- Block the calling coroutine until a suitable unsolicited event (one +-- for which filter() returns the event) arrives. +function leap.WaitFor:wait() + return self._queue:Dequeue() +end + +-- Loop over wait() calls. +function leap.WaitFor:iterate() + -- on each iteration, call self.wait(self) + return self.wait, self, nil +end + +-- Override filter() to examine the incoming event in whatever way +-- makes sense. +-- +-- Return nil to ignore this event. +-- +-- To claim the event, return the item you want placed in the queue. +-- Typically you'd write: +-- return data +-- or perhaps +-- return {pump=pump, data=data} +-- or some variation. +function leap.WaitFor:filter(pump, data) + error('You must subclass WaitFor and override its filter() method') +end + +-- called by leap._unsolicited() for each WaitFor in leap._waitfors +function leap.WaitFor:_handle(pump, data) + item = self:filter(pump, data) + -- if this item doesn't pass the filter, we're not interested + if not item then + return false + end + -- okay, filter() claims this event + self:process(item) + return true +end - self._first = 0 - self._last = -1 - self._queue = {} +-- called by WaitFor:_handle() for an accepted event +function leap.WaitFor:process(item) + self._queue:Enqueue(item) +end + +-- called by leap.process() when get_event_next() raises an error +function leap.WaitFor:_exception(message) + self._queue:Error(message) +end + +-- ------------------------------ WaitForReqid ------------------------------- +leap.WaitForReqid = leap.WaitFor:new() + +function leap.WaitForReqid:new(reqid) + -- priority is meaningless, since this object won't be added to the + -- priority-sorted ViewerClient.waitfors list. Use the reqid as the + -- debugging name string. + local obj = leap.WaitFor:new(0, 'WaitForReqid(' .. reqid .. ')') + setmetatable(obj, self) + self.__index = self return obj end --- Check if the queue is empty -function Queue:IsEmpty() - return self._first > self._last +function leap.WaitForReqid:enable() + -- Do NOT self-register in the normal way. request() and generate() + -- have an entirely different registry that points directly to the + -- WaitForReqid object of interest. +end + +function leap.WaitForReqid:disable() +end + +function leap.WaitForReqid:filter(pump, data) + -- Because we expect to directly look up the WaitForReqid object of + -- interest based on the incoming ["reqid"] value, it's not necessary + -- to test the event again. Accept every such event. + return data end return leap -- cgit v1.2.3 From 27d6bbd3d98bde278cc828d6673a93c4702b3e80 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 8 Mar 2024 10:47:41 -0500 Subject: Allow build-time Lua tests to require() bundled Lua modules. --- indra/newview/llluamanager.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index cd663021a1..c65f062fd7 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -435,7 +435,14 @@ void LLRequireResolver::findModule() fail(); } - std::vector<std::string> lib_paths {gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua")}; + std::vector<std::string> lib_paths + { + gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"), +#ifdef LL_TEST + // Build-time tests don't have the app bundle - use source tree. + std::filesystem::path(__FILE__).parent_path() / "scripts" / "lua", +#endif + }; for (const auto& path : lib_paths) { -- cgit v1.2.3 From efdda0b93d2dbf28e7722150028476286f0ec623 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 8 Mar 2024 10:53:50 -0500 Subject: Enhance llluamanager_test.cpp. Sketch in an initial test that requires one of our bundled Lua modules. Each time we run Lua, report any error returned by the Lua engine. Use llcoro::suspendUntilEventOn(LLEventMailDrop) as shorthand for initializing an explicit LLTempBoundListener with a listen() call with a lambda. --- indra/newview/tests/llluamanager_test.cpp | 34 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 81ec186cf4..1c2be900d3 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -94,9 +94,10 @@ namespace tut { auto [count, result] = LLLUAmanager::waitScriptLine(L, "return " + luax.expr); - auto desc{ stringize("waitScriptLine(", luax.desc, ")") }; - ensure_equals(desc + ".count", count, 1); - ensure_equals(desc + ".result", result, luax.expect); + auto desc{ stringize("waitScriptLine(", luax.desc, "): ") }; + // if count < 0, report Lua error message + ensure_equals(desc + result.asString(), count, 1); + ensure_equals(desc + "result", result, luax.expect); } } @@ -116,7 +117,7 @@ namespace tut // We woke up again ourselves because the coroutine running Lua has // finished. But our Lua chunk didn't actually return anything, so we // expect count to be 0 and result to be undefined. - ensure_equals(desc + " count", count, 0); + ensure_equals(desc + ": " + result.asString(), count, 0); ensure_equals(desc, fromlua, expect); } @@ -172,16 +173,13 @@ namespace tut << "': post('" << expected[4] << "')" << LL_ENDL; luapump.post(expected[4]); auto [count, result] = future.get(); + ensure_equals("post_on(): " + result.asString(), count, 0); ensure_equals("post_on() sequence", posts, expected); } void round_trip(const std::string& desc, const LLSD& send, const LLSD& expect) { - LLSD reply; - LLEventStream replypump("testpump"); - LLTempBoundListener conn( - replypump.listen("llluamanager_test", - listener([&reply](const LLSD& post){ reply = post; }))); + LLEventMailDrop replypump("testpump"); const std::string lua( "-- test LLSD round trip\n" "replypump, cmdpump = get_event_pumps()\n" @@ -195,12 +193,12 @@ namespace tut // reached the get_event_next() call, which suspends the calling C++ // coroutine (including the Lua code running on it) until we post // something to that reply pump. - auto luapump{ reply.asString() }; - reply.clear(); + auto luapump{ llcoro::suspendUntilEventOn(replypump).asString() }; LLEventPumps::instance().post(luapump, send); // The C++ coroutine running the Lua script is now ready to run. Run // it so it will echo the LLSD back to us. auto [count, result] = future.get(); + ensure_equals(stringize("round_trip(", desc, "): ", result.asString()), count, 1); ensure_equals(desc, result, expect); } @@ -304,4 +302,18 @@ namespace tut } round_trip("nested map", send_map, expect_map); } + + template<> template<> + void object::test<5>() + { + set_test_name("test leap.lua"); + const std::string lua( + "-- test leap.lua\n" + "leap = require('leap')\n" + ); + LuaState L; + auto future = LLLUAmanager::startScriptLine(L, lua); + auto [count, result] = future.get(); + ensure_equals("leap.lua: " + result.asString(), count, 0); + } } // namespace tut -- cgit v1.2.3 From 1ebd23ffed912a5c8c94d109f37a2c25cf169523 Mon Sep 17 00:00:00 2001 From: JamesFoxpaws <162667174+JamesFoxpaws@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:10:55 +1000 Subject: Remove gender-based restrictions on shape and physics sliders --- indra/newview/character/avatar_lad.xml | 59 +++------------------- indra/newview/skins/default/xui/da/strings.xml | 3 ++ indra/newview/skins/default/xui/de/strings.xml | 1 + .../skins/default/xui/en/panel_edit_wearable.xml | 51 ------------------- indra/newview/skins/default/xui/en/strings.xml | 1 + indra/newview/skins/default/xui/es/strings.xml | 1 + indra/newview/skins/default/xui/fr/strings.xml | 1 + indra/newview/skins/default/xui/it/strings.xml | 1 + indra/newview/skins/default/xui/ja/strings.xml | 3 ++ indra/newview/skins/default/xui/pl/strings.xml | 3 ++ indra/newview/skins/default/xui/pt/strings.xml | 1 + indra/newview/skins/default/xui/ru/strings.xml | 3 ++ indra/newview/skins/default/xui/tr/strings.xml | 3 ++ indra/newview/skins/default/xui/zh/strings.xml | 3 ++ 14 files changed, 30 insertions(+), 104 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 2cdd86267e..9be6275929 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -3822,7 +3822,6 @@ <param id="30879" group="1" - sex="male" name="Male_Package" value_min="-.5" value_max="2"> @@ -5813,7 +5812,6 @@ <param id="400" - sex="male" group="1" name="Displace_Hair_Facial" label="Hair Thickess" @@ -6838,7 +6836,6 @@ <param id="626" - sex="female" group="1" name="Big_Chest" label="Chest Size" @@ -6865,7 +6862,6 @@ <param id="627" - sex="female" group="1" name="Small_Chest" label="Chest Size" @@ -6891,7 +6887,6 @@ <param id="843" - sex="female" group="1" name="No_Chest" label="Chest Size" @@ -6920,7 +6915,6 @@ group="1" name="Muscular_Torso" label="Torso Muscles" - sex="male" show_simple="true" wearable="shape" edit_group="shape_torso" @@ -6963,7 +6957,6 @@ group="1" name="Muscular_Torso" label="Torso Muscles" - sex="female" show_simple="true" wearable="shape" edit_group="shape_torso" @@ -7004,7 +6997,6 @@ <param id="648" group="1" - sex="female" name="Scrawny_Torso" label="Torso Muscles" show_simple="true" @@ -7059,7 +7051,6 @@ <param id="677" group="1" - sex="male" name="Scrawny_Torso_Male" label="Torso Scrawny" wearable="shape" @@ -7192,7 +7183,6 @@ <param id="507" group="0" - sex="female" name="Breast_Gravity" label="Breast Buoyancy" wearable="shape" @@ -7279,7 +7269,6 @@ <param id="684" group="0" - sex="female" name="Breast_Female_Cleavage" label="Breast Cleavage" wearable="shape" @@ -7307,7 +7296,6 @@ <param id="685" group="0" - sex="male" name="Chest_Male_No_Pecs" label="Pectorals" wearable="shape" @@ -7525,7 +7513,6 @@ <param id="1200" group="1" - sex="female" name="Breast_Physics_UpDown_Driven" wearable="physics" edit_group="driven" @@ -7547,7 +7534,6 @@ <param id="1201" group="1" - sex="female" name="Breast_Physics_InOut_Driven" wearable="physics" edit_group="driven" @@ -8079,7 +8065,6 @@ <param id="20879" group="1" - sex="male" name="Male_Package" value_min="-.5" value_max="2"> @@ -9837,7 +9822,6 @@ render_pass="bump"> <param id="1004" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9852,7 +9836,6 @@ render_pass="bump"> <param id="1006" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9867,7 +9850,6 @@ render_pass="bump"> <param id="1008" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9882,7 +9864,6 @@ render_pass="bump"> <param id="1010" - sex="male" group="1" edit_group="driven" wearable="hair" @@ -9898,7 +9879,6 @@ render_pass="bump"> <param id="1012" group="1" - sex="male" wearable="hair" edit_group="driven" name="5 O'Clock Shadow bump" @@ -9924,7 +9904,6 @@ render_pass="bump"> <param id="1005" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9939,7 +9918,6 @@ render_pass="bump"> <param id="1007" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9954,7 +9932,6 @@ render_pass="bump"> <param id="1009" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9969,7 +9946,6 @@ render_pass="bump"> <param id="1011" - sex="male" group="1" wearable="hair" edit_group="driven" @@ -9986,7 +9962,6 @@ render_pass="bump"> id="751" group="1" wearable="hair" - sex="male" edit_group="hair_facial" name="5 O'Clock Shadow" label_min="Dense hair" @@ -15097,7 +15072,6 @@ render_pass="bump"> <param id="105" group="0" - sex="female" wearable="shape" edit_group="shape_torso" edit_group_order="6" @@ -15262,7 +15236,6 @@ render_pass="bump"> <param id="649" group="0" - sex="female" wearable="shape" edit_group="shape_torso" edit_group_order="1.1" @@ -15297,7 +15270,6 @@ render_pass="bump"> <param id="678" group="0" - sex="male" wearable="shape" edit_group="shape_torso" edit_group_order="1" @@ -15365,10 +15337,14 @@ render_pass="bump"> id="80" name="male" group="0" - edit_group="dummy" + edit_group="shape_body" + label="Gender" + label_min="Female" + label_max="Male" wearable="shape" value_min="0" - value_max="1"> + value_max="1" + camera_distance="2.2"> <param_driver> <driven id="32" /> @@ -15583,7 +15559,6 @@ render_pass="bump"> <param id="752" group="0" - sex="male" wearable="hair" edit_group="hair_facial" edit_group_order="1" @@ -15865,7 +15840,6 @@ render_pass="bump"> <param id="879" group="0" - sex="male" name="Male_Package" label="Package" wearable="shape" @@ -16053,7 +16027,6 @@ render_pass="bump"> <param id="166" - sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16079,7 +16052,6 @@ render_pass="bump"> <param id="167" - sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16105,7 +16077,6 @@ render_pass="bump"> <param id="168" - sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16131,7 +16102,6 @@ render_pass="bump"> <param id="169" - sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16944,7 +16914,6 @@ render_pass="bump"> <param id="1100" group="1" - sex="female" wearable="physics" name="Breast_Physics_UpDown_Controller" label="Breast Physics UpDown Controller" @@ -16960,7 +16929,6 @@ render_pass="bump"> <param id="1101" group="1" - sex="female" wearable="physics" name="Breast_Physics_InOut_Controller" label="Breast Physics InOut Controller" @@ -17040,7 +17008,6 @@ render_pass="bump"> <param id="10000" group="0" - sex="female" name="Breast_Physics_Mass" label="Breast Physics Mass" wearable="physics" @@ -17053,7 +17020,6 @@ render_pass="bump"> <param id="10001" group="0" - sex="female" name="Breast_Physics_Gravity" label="Breast Physics Gravity" wearable="physics" @@ -17067,7 +17033,6 @@ render_pass="bump"> <param id="10002" group="0" - sex="female" name="Breast_Physics_Drag" label="Breast Physics Drag" wearable="physics" @@ -17081,7 +17046,6 @@ render_pass="bump"> <param id="10003" group="0" - sex="female" name="Breast_Physics_UpDown_Max_Effect" label="Breast Physics UpDown Max Effect" wearable="physics" @@ -17094,7 +17058,6 @@ render_pass="bump"> <param id="10004" group="0" - sex="female" name="Breast_Physics_UpDown_Spring" label="Breast Physics UpDown Spring" wearable="physics" @@ -17107,7 +17070,6 @@ render_pass="bump"> <param id="10005" group="0" - sex="female" name="Breast_Physics_UpDown_Gain" label="Breast Physics UpDown Gain" wearable="physics" @@ -17120,7 +17082,6 @@ render_pass="bump"> <param id="10006" group="0" - sex="female" name="Breast_Physics_UpDown_Damping" label="Breast Physics UpDown Damping" wearable="physics" @@ -17134,7 +17095,6 @@ render_pass="bump"> <param id="10007" group="0" - sex="female" name="Breast_Physics_InOut_Max_Effect" label="Breast Physics InOut Max Effect" wearable="physics" @@ -17147,7 +17107,6 @@ render_pass="bump"> <param id="10008" group="0" - sex="female" name="Breast_Physics_InOut_Spring" label="Breast Physics InOut Spring" wearable="physics" @@ -17160,7 +17119,6 @@ render_pass="bump"> <param id="10009" group="0" - sex="female" name="Breast_Physics_InOut_Gain" label="Breast Physics InOut Gain" wearable="physics" @@ -17173,7 +17131,6 @@ render_pass="bump"> <param id="10010" group="0" - sex="female" name="Breast_Physics_InOut_Damping" label="Breast Physics InOut Damping" wearable="physics" @@ -17407,7 +17364,6 @@ render_pass="bump"> <param id="10029" group="0" - sex="female" name="Breast_Physics_LeftRight_Max_Effect" label="Breast Physics LeftRight Max Effect" wearable="physics" @@ -17420,7 +17376,6 @@ render_pass="bump"> <param id="10030" group="0" - sex="female" name="Breast_Physics_LeftRight_Spring" label="Breast Physics LeftRight Spring" wearable="physics" @@ -17433,7 +17388,6 @@ render_pass="bump"> <param id="10031" group="0" - sex="female" name="Breast_Physics_LeftRight_Gain" label="Breast Physics LeftRight Gain" wearable="physics" @@ -17446,7 +17400,6 @@ render_pass="bump"> <param id="10032" group="0" - sex="female" name="Breast_Physics_LeftRight_Damping" label="Breast Physics LeftRight Damping" wearable="physics" diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index e4f99d14e9..2e351cbc65 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -2688,6 +2688,9 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE]. <string name="Full Sides"> Meget hår </string> + <string name="Gender"> + Køn + </string> <string name="Glossy"> Skinnende </string> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index a9e7626dc5..4a4a34911d 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -1248,6 +1248,7 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_ <string name="Full Front">Vorne volles Haar</string> <string name="Full Hair Sides">Seitlich volles Haar</string> <string name="Full Sides">Volle Seiten</string> + <string name="Gender">Geschlecht</string> <string name="Glossy">Glänzend</string> <string name="Glove Fingers">Handschuhfinger</string> <string name="Glove Length">Handschuhlänge</string> diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml index 85d73ece48..b3aadb8ea1 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml @@ -202,57 +202,6 @@ top="10" value="Shape:" width="150" /> - <radio_group - control_name="AvatarSex" - follows="top|right" - height="20" - layout="topleft" - left="210" - name="sex_radio" - top="5" - width="110"> - <radio_item - follows="all" - height="16" - label="" - layout="topleft" - left="0" - name="sex_male" - tool_tip="Male" - value="1" - width="40" /> - <radio_item - follows="all" - height="16" - label="" - layout="topleft" - left_pad="10" - name="sex_female" - tool_tip="Female" - value="0" - width="40"/> - </radio_group> - <!-- graphical labels for the radio buttons above --> - <icon - follows="top|right" - height="16" - image_name="icons/Male.png" - layout="topleft" - left="230" - name="male_icon" - tool_tip="Male" - top="7" - width="16" /> - <icon - follows="top|right" - height="16" - image_name="icons/Female.png" - layout="topleft" - left="280" - name="female_icon" - tool_tip="Female" - top="7" - width="16" /> <line_editor follows="all" height="23" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 3fbb5bc7e8..e7d1233890 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3232,6 +3232,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="Full Front">Full Front</string> <string name="Full Hair Sides">Full Hair Sides</string> <string name="Full Sides">Full Sides</string> +<string name="Gender">Gender</string> <string name="Glossy">Glossy</string> <string name="Glove Fingers">Glove Fingers</string> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index cd8e7687ae..fd85cdc252 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -1227,6 +1227,7 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].</string> <string name="Full Front">Sin cortar</string> <string name="Full Hair Sides">Pelo: volumen a los lados</string> <string name="Full Sides">Volumen total</string> + <string name="Gender">Sexo</string> <string name="Glossy">Con brillo</string> <string name="Glove Fingers">Guantes: dedos</string> <string name="Glove Length">Guantes: largo</string> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 0a3fbeb603..5969856086 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -1249,6 +1249,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].</string> <string name="Full Front">Devant touffu</string> <string name="Full Hair Sides">Côtés touffus</string> <string name="Full Sides">Côtés touffus</string> + <string name="Gender">Sexe</string> <string name="Glossy">Brillant</string> <string name="Glove Fingers">Gants avec doigts</string> <string name="Glove Length">Longueur</string> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 178bb90ca6..e12203c6b7 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -1229,6 +1229,7 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].</string> <string name="Full Front">Anteriore gonfio</string> <string name="Full Hair Sides">Lati capelli gonfi</string> <string name="Full Sides">Lati gonfi</string> + <string name="Gender">Sesso</string> <string name="Glossy">Lucido</string> <string name="Glove Fingers">Dita con guanti</string> <string name="Glove Length">Lunghezza guanti</string> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index fa6c329fe7..8fe69162c5 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -5052,6 +5052,9 @@ www.secondlife.com から最新バージョンをダウンロードしてくだ <string name="Full Sides"> 生え揃ったサイド </string> + <string name="Gender"> + 性別 + </string> <string name="Glossy"> あり </string> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index 26ec6cc9dc..a2d386e8ac 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -3318,6 +3318,9 @@ Jeżeli nadal otrzymujesz ten komunikat, skontaktuj się z [SUPPORT_SITE]. <string name="Full Sides"> Gęste boki </string> + <string name="Gender"> + Płeć + </string> <string name="Glossy"> Błyszcząca </string> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 6db5da2e89..5076e21198 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -1192,6 +1192,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE].</string> <string name="Full Front">Frente cheia</string> <string name="Full Hair Sides">Cabelos laterais cheios</string> <string name="Full Sides">Lados cheios</string> + <string name="Gender">Sexo</string> <string name="Glossy">Brilhante</string> <string name="Glove Fingers">Dedos da luva</string> <string name="Glove Length">Comprimento das luvas</string> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 61d836a2d1..8fc9641624 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -3479,6 +3479,9 @@ support@secondlife.com. <string name="Full Sides"> По бокам </string> + <string name="Gender"> + Пол + </string> <string name="Glossy"> Блестящие </string> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index e709a4c5d6..687de84401 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -3482,6 +3482,9 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne başvurun. <string name="Full Sides"> Saçlar Yanda </string> + <string name="Gender"> + Cinsiyet + </string> <string name="Glossy"> Parlak </string> diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index bdb16c9bf1..cf94391aa4 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -3475,6 +3475,9 @@ http://secondlife.com/support 求助解決問題。 <string name="Full Sides"> 兩側飽滿 </string> + <string name="Gender"> + 性别 + </string> <string name="Glossy"> 光亮 </string> -- cgit v1.2.3 From a249bfa18e492a4317d739f7b9d839b796f005ba Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 11 Mar 2024 12:49:10 -0400 Subject: Make WaitQueue:_wait_waiters() skip dead coroutines. That is, skip coroutines that have gone dead since they decided to wait on Dequeue(). --- indra/newview/scripts/lua/WaitQueue.lua | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index e6adde0573..00766ccae7 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -37,14 +37,21 @@ function WaitQueue:_wake_waiters() -- or Dequeue() calls, recheck every time around to see if we must resume -- another waiting coroutine. while not self:IsEmpty() and #self._waiters > 0 do - -- pop the oldest waiting coroutine instead of the most recent, for - -- more-or-less round robin fairness + -- Pop the oldest waiting coroutine instead of the most recent, for + -- more-or-less round robin fairness. But skip any coroutines that + -- have gone dead in the meantime. local waiter = table.remove(self._waiters, 1) - -- don't pass the head item: let the resumed coroutine retrieve it - local ok, message = coroutine.resume(waiter) - -- if resuming that waiter encountered an error, don't swallow it - if not ok then - error(message) + while waiter and coroutine.status(waiter) ~= "suspended" do + waiter = table.remove(self._waiters, 1) + end + -- do we still have at least one waiting coroutine? + if waiter then + -- don't pass the head item: let the resumed coroutine retrieve it + local ok, message = coroutine.resume(waiter) + -- if resuming that waiter encountered an error, don't swallow it + if not ok then + error(message) + end end end end -- cgit v1.2.3 From 4a8ea879fa62c0131985f625e940c5bc0b3fec46 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 11 Mar 2024 12:55:23 -0400 Subject: Polish up leap.lua to make it pass tests. Add usage comments at the top. Add leap.done() function. Make leap.process() honor leap.done(), also recognize an incoming nil from the viewer to mean it's all done. Support leap.WaitFor with nil priority to mean "don't self-enable." This obviates leap.WaitForReqid:enable() and disable() overrides that do nothing. Add diagnostic logging. --- indra/newview/scripts/lua/leap.lua | 73 ++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 19 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 708df821e8..6477d1b9fd 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -16,6 +16,27 @@ -- was received and the received event data. When the queue is empty, -- get_event_next() blocks the calling Lua script until the next event is -- received. +-- +-- Usage: +-- 1. Launch some number of Lua coroutines. The code in each coroutine may +-- call leap.send(), leap.request() or leap.generate(). leap.send() returns +-- immediately ("fire and forget"). leap.request() blocks the calling +-- coroutine until it receives and returns the viewer's response to its +-- request. leap.generate() expects an arbitrary number of responses to the +-- original request. +-- 2. To handle events from the viewer other than direct responses to +-- requests, instantiate a leap.WaitFor object with a filter(pump, data) +-- override method that returns non-nil for desired events. A coroutine may +-- call wait() on any such WaitFor. +-- 3. Once the coroutines have been launched, call leap.process() on the main +-- coroutine. process() retrieves incoming events from the viewer and +-- dispatches them to waiting request() or generate() calls, or to +-- appropriate WaitFor instances. process() returns when either +-- get_event_next() raises an error or the viewer posts nil to the script's +-- reply pump to indicate it's done. +-- 4. Alternatively, a running coroutine may call leap.done() to break out of +-- leap.process(). process() won't notice until the next event from the +-- viewer, though. local ErrorQueue = require('ErrorQueue') @@ -57,6 +78,8 @@ leap._waitfors = {} -- ["reqid"] values is our very own _reply pump, we can get away with -- an integer. leap._reqid = 0 +-- break leap.process() loop +leap._done = false -- get the name of the reply pump function leap.replypump() @@ -101,6 +124,8 @@ end -- Unless the request data already contains a ["reply"] key, we insert -- reply=self.replypump to try to ensure that the expected reply will be -- returned over the socket. +-- +-- See also send(), generate(). function leap.request(pump, data) local reqid = leap._requestSetup(pump, data) local ok, response = pcall(leap._pending[reqid].wait) @@ -165,20 +190,28 @@ end -- While waiting for responses from the viewer, the C++ coroutine running the -- calling Lua script is blocked: no other Lua coroutine is running. function leap.process() + leap._done = false local ok, pump, data - while true do + while not leap._done do ok, pump, data = pcall(get_event_next) - if not ok then + print_debug('leap.process() got', ok, pump, data) + -- ok false means get_event_next() raised a Lua error + -- data nil means get_event_next() returned (pump, LLSD()) to indicate done + if not (ok and data) then + print_debug('leap.process() done') break end leap._dispatch(pump, data) end -- we're done: clean up all pending coroutines + -- if ok, then we're just done. + -- if not ok, then 'pump' is actually the error message. + message = if ok then 'done' else pump for i, waitfor in pairs(leap._pending) do - waitfor._exception(pump) + waitfor:_exception(message) end for i, waitfor in pairs(leap._waitfors) do - waitfor._exception(pump) + waitfor:_exception(message) end -- now that we're done with cleanup, propagate the error we caught above if not ok then @@ -186,6 +219,10 @@ function leap.process() end end +function leap.done() + leap._done = true +end + -- Route incoming (pump, data) event to the appropriate waiting coroutine. function leap._dispatch(pump, data) local reqid = data['reqid'] @@ -200,7 +237,7 @@ function leap._dispatch(pump, data) end -- found the right WaitForReqid object, let it handle the event data['reqid'] = nil - waitfor._handle(pump, data) + waitfor:_handle(pump, data) end -- Handle an incoming (pump, data) event with no recognizable ['reqid'] @@ -208,7 +245,7 @@ function leap._unsolicited(pump, data) -- we maintain waitfors in descending priority order, so the first waitfor -- to claim this event is the one with the highest priority for i, waitfor in pairs(leap._waitfors) do - if waitfor._handle(pump, data) then + if waitfor:_handle(pump, data) then return end end @@ -284,7 +321,10 @@ function leap.WaitFor:new(priority, name) end obj._queue = ErrorQueue:new() obj._registered = false - obj:enable() + -- if no priority, then don't enable() - remember 0 is truthy + if priority then + obj:enable() + end return obj end @@ -314,7 +354,10 @@ end -- Block the calling coroutine until a suitable unsolicited event (one -- for which filter() returns the event) arrives. function leap.WaitFor:wait() - return self._queue:Dequeue() + print_debug(self.name .. ' about to wait') + item = self._queue:Dequeue() + print_debug(self.name .. ' got ', item) + return item end -- Loop over wait() calls. @@ -335,7 +378,7 @@ end -- return {pump=pump, data=data} -- or some variation. function leap.WaitFor:filter(pump, data) - error('You must subclass WaitFor and override its filter() method') + error('You must override the WaitFor.filter() method') end -- called by leap._unsolicited() for each WaitFor in leap._waitfors @@ -357,6 +400,7 @@ end -- called by leap.process() when get_event_next() raises an error function leap.WaitFor:_exception(message) + print_warning(self.name .. ' error: ' .. message) self._queue:Error(message) end @@ -367,22 +411,13 @@ function leap.WaitForReqid:new(reqid) -- priority is meaningless, since this object won't be added to the -- priority-sorted ViewerClient.waitfors list. Use the reqid as the -- debugging name string. - local obj = leap.WaitFor:new(0, 'WaitForReqid(' .. reqid .. ')') + local obj = leap.WaitFor:new(nil, 'WaitForReqid(' .. reqid .. ')') setmetatable(obj, self) self.__index = self return obj end -function leap.WaitForReqid:enable() - -- Do NOT self-register in the normal way. request() and generate() - -- have an entirely different registry that points directly to the - -- WaitForReqid object of interest. -end - -function leap.WaitForReqid:disable() -end - function leap.WaitForReqid:filter(pump, data) -- Because we expect to directly look up the WaitForReqid object of -- interest based on the incoming ["reqid"] value, it's not necessary -- cgit v1.2.3 From 199907fa280cb3d1ea5a27dbe94e69df9256c101 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 11 Mar 2024 12:57:46 -0400 Subject: Add llluamanager_test test exercising leap.WaitFor. --- indra/newview/tests/llluamanager_test.cpp | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 1c2be900d3..36b8bb046a 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -28,6 +28,7 @@ #include "lluri.h" #include "lluuid.h" #include "lua_function.h" +#include "lualistener.h" #include "stringize.h" class LLTestApp : public LLApp @@ -309,10 +310,44 @@ namespace tut set_test_name("test leap.lua"); const std::string lua( "-- test leap.lua\n" + "\n" "leap = require('leap')\n" + "\n" + "-- negative priority ensures catchall is always last\n" + "catchall = leap.WaitFor:new(-1, 'catchall')\n" + "function catchall:filter(pump, data)\n" + " return data\n" + "end\n" + "\n" + "-- but first, catch events with 'special' key\n" + "catch_special = leap.WaitFor:new(2, 'catch_special')\n" + "function catch_special:filter(pump, data)\n" + " return if data['special'] ~= nil then data else nil\n" + "end\n" + "\n" + "function drain(waitfor)\n" + " print(waitfor.name .. ' start')\n" + " for item in waitfor.wait, waitfor do\n" + " print(waitfor.name .. ' caught', item)\n" + " end\n" + " print(waitfor.name .. ' done')\n" + "end\n" + "\n" + "co_all = coroutine.create(drain)\n" + "co_special = coroutine.create(drain)\n" + "coroutine.resume(co_all, catchall)\n" + "coroutine.resume(co_special, catch_special)\n" + "\n" + "leap.process()\n" ); LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); + auto replyname{ L.obtainListener()->getReplyName() }; + auto& replypump{ LLEventPumps::instance().obtain(replyname) }; + replypump.post(llsd::map("special", "K")); + replypump.post(llsd::map("name", "not special")); + // tell leap.process() we're done + replypump.post(LLSD()); auto [count, result] = future.get(); ensure_equals("leap.lua: " + result.asString(), count, 0); } -- cgit v1.2.3 From 42de5594cd4ebde605e6f93a48a7e7c9ab60ace4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 11 Mar 2024 16:12:07 -0400 Subject: Lua already has a conventional cheap test for empty table. --- indra/newview/scripts/lua/util.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index bb8d492d12..898ddc58e3 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -4,10 +4,7 @@ local util = {} -- cheap test whether table t is empty function util.empty(t) - for _ in pairs(t) do - return false - end - return true + return not next(t) end -- reliable count of the number of entries in table t -- cgit v1.2.3 From c371096fc3320f580fd271dad09c852f2e3d5f78 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 11 Mar 2024 16:49:03 -0400 Subject: Add coro.lua to aggregate created coroutines. --- indra/newview/scripts/lua/coro.lua | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 indra/newview/scripts/lua/coro.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/coro.lua b/indra/newview/scripts/lua/coro.lua new file mode 100644 index 0000000000..8f868f5a48 --- /dev/null +++ b/indra/newview/scripts/lua/coro.lua @@ -0,0 +1,57 @@ +-- Manage Lua coroutines + +local coro = {} + +coro._coros = {} + +-- Launch a Lua coroutine: create and resume. +-- Returns: +-- new coroutine +-- bool ok +-- if not ok: error message +-- if ok: values yielded or returned +function coro.launch(func, ...) + local co = coroutine.create(func) + table.insert(coro._coros, co) + return co, coroutine.resume(co, ...) +end + +-- yield to other coroutines even if you don't know whether you're in a +-- created coroutine or the main coroutine +function coro.yield(...) + if coroutine.running() then + -- this is a real coroutine, yield normally + return coroutine.yield(...) + else + -- This is the main coroutine: coroutine.yield() doesn't work. + -- But we can take a spin through previously-launched coroutines. + -- Walk a copy of coro._coros in case any of these coroutines launches + -- another: next() forbids creating new entries during traversal. + for co in coro._live_coros_iter, table.clone(coro._coros) do + co.resume() + end + end +end + +-- Walk coro._coros table, returning running or suspended coroutines. +-- Once a coroutine becomes dead, remove it from _coros and don't return it. +function coro._live_coros() + return coro._live_coros_iter, coro._coros +end + +-- iterator function for _live_coros() +function coro._live_coros_iter(t, idx) + local k, co = next(t, idx) + while k and coroutine.status(co) == 'dead' do +-- t[k] = nil + -- See coro.yield(): sometimes we traverse a copy of _coros, but if we + -- discover a dead coroutine in that copy, delete it from _coros + -- anyway. Deleting it from a temporary copy does nothing. + coro._coros[k] = nil + coroutine.close(co) + k, co = next(t, k) + end + return co +end + +return coro -- cgit v1.2.3 From 4a07fd3762b6707b737942c87d1c4d5aeb229678 Mon Sep 17 00:00:00 2001 From: nerodevo <100370411+nerodevo@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:03:19 -0500 Subject: Remove invalid text color parameter from login screen #960 (#972) Removed parameter since 'Remember me' isn't using color emphasis. If emphasis color is desired, then let me know if 'Remember me' should use same color emphasis for consistency. --- indra/newview/skins/default/xui/en/panel_login.xml | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 3aba80909a..86b08bb24a 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -144,7 +144,6 @@ control_name="RememberPassword" follows="left|top" font="SansSerifMedium" - text_color="EmphasisColor" height="24" left="408" bottom_delta="0" -- cgit v1.2.3 From 587d65dc127fd72cd72aed5f02dbfd3bf277a9ef Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 13 Mar 2024 14:31:05 -0400 Subject: Make a coro.resume() wrapper and use in coro.launch(), coro.yield(). coro.resume() checks the ok boolean returned by coroutine.resume() and, if not ok, propagates the error. This avoids coroutine errors getting swallowed. --- indra/newview/scripts/lua/coro.lua | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/coro.lua b/indra/newview/scripts/lua/coro.lua index 8f868f5a48..616a797e95 100644 --- a/indra/newview/scripts/lua/coro.lua +++ b/indra/newview/scripts/lua/coro.lua @@ -5,15 +5,25 @@ local coro = {} coro._coros = {} -- Launch a Lua coroutine: create and resume. --- Returns: --- new coroutine --- bool ok --- if not ok: error message --- if ok: values yielded or returned +-- Returns: new coroutine, values yielded or returned from initial resume() +-- If initial resume() encountered an error, propagates the error. function coro.launch(func, ...) local co = coroutine.create(func) table.insert(coro._coros, co) - return co, coroutine.resume(co, ...) + return co, coro.resume(co, ...) +end + +-- resume() wrapper to propagate errors +function coro.resume(co, ...) + -- if there's an idiom other than table.pack() to assign an arbitrary + -- number of return values, I don't yet know it + local ok_result = table.pack(coroutine.resume(co, ...)) + if not ok_result[1] then + -- if [1] is false, then [2] is the error message + error(ok_result[2]) + end + -- ok is true, whew, just return the rest of the values + return table.unpack(ok_result, 2) end -- yield to other coroutines even if you don't know whether you're in a @@ -28,7 +38,7 @@ function coro.yield(...) -- Walk a copy of coro._coros in case any of these coroutines launches -- another: next() forbids creating new entries during traversal. for co in coro._live_coros_iter, table.clone(coro._coros) do - co.resume() + coro.resume(co) end end end -- cgit v1.2.3 From 354d7b55c0a267b542dc51e3985f7d3739ffcdfd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 13 Mar 2024 14:37:48 -0400 Subject: Introduce a resume() wrapper to surface coroutine errors. --- indra/newview/scripts/lua/qtest.lua | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/qtest.lua b/indra/newview/scripts/lua/qtest.lua index 12e425b7b2..009446d0c3 100644 --- a/indra/newview/scripts/lua/qtest.lua +++ b/indra/newview/scripts/lua/qtest.lua @@ -7,6 +7,19 @@ util = require('util') inspect = require('inspect') +-- resume() wrapper to propagate errors +function resume(co, ...) + -- if there's an idiom other than table.pack() to assign an arbitrary + -- number of return values, I don't yet know it + local ok_result = table.pack(coroutine.resume(co, ...)) + if not ok_result[1] then + -- if [1] is false, then [2] is the error message + error(ok_result[2]) + end + -- ok is true, whew, just return the rest of the values + return table.unpack(ok_result, 2) +end + -- ------------------ Queue variables are instance-specific ------------------ q1 = Queue:new() q2 = Queue:new() @@ -51,9 +64,9 @@ coa = coroutine.create(consumer) cob = coroutine.create(consumer) -- Since consumer() doesn't yield while it can still retrieve values, -- consumer(a) will dequeue all values from q1 and return when done. -coroutine.resume(coa, 'a', q1) +resume(coa, 'a', q1) -- consumer(b) will wake up to find the queue empty and closed. -coroutine.resume(cob, 'b', q1) +resume(cob, 'b', q1) coroutine.close(coa) coroutine.close(cob) @@ -72,7 +85,7 @@ for _, name in {'a', 'b'} do local coro = coroutine.create(consumer) table.insert(coros, coro) -- Resuming both coroutines should leave them both waiting for a queue item. - coroutine.resume(coro, name, q3) + resume(coro, name, q3) end for _, s in pairs(values) do @@ -89,6 +102,8 @@ function joinall(coros) for i, coro in pairs(coros) do if coroutine.status(coro) == 'suspended' then running = true + -- directly call coroutine.resume() instead of our resume() + -- wrapper because we explicitly check for errors here local ok, message = coroutine.resume(coro) if not ok then print('*** ' .. message) @@ -105,7 +120,7 @@ end joinall(coros) -print(string.format('%q', util.join(result, ' '))) +print(string.format('%q', table.concat(result, ' '))) assert(util.equal(values, result)) -- ----------------------------- test ErrorQueue ----------------------------- @@ -118,7 +133,7 @@ for _, name in {'a', 'b'} do local coro = coroutine.create(consumer) table.insert(coros, coro) -- Resuming both coroutines should leave them both waiting for a queue item. - coroutine.resume(coro, name, q4) + resume(coro, name, q4) end for i = 1, 4 do -- cgit v1.2.3 From dfd47762afc757777dcdde3960a08951c45fb1ed Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 13 Mar 2024 14:38:25 -0400 Subject: Fix minor bugs. Sprinkle in commented-out diagnostic output. --- indra/newview/scripts/lua/leap.lua | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 6477d1b9fd..2dd0d7b8ec 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -91,12 +91,15 @@ function leap.cmdpump() return leap._command end +-- local inspect = require('inspect') + -- Fire and forget. Send the specified request LLSD, expecting no reply. -- In fact, should the request produce an eventual reply, it will be -- treated as an unsolicited event. -- -- See also request(), generate(). function leap.send(pump, data, reqid) +-- print_debug('leap.send('..pump..', '..inspect(data)..', '..reqid..') entry') local data = data if type(data) == 'table' then data = table.clone(data) @@ -105,7 +108,8 @@ function leap.send(pump, data, reqid) data['reqid'] = reqid end end - post_to(pump, data) +-- print_debug('leap.send('..pump..', '..inspect(data)..') calling post_on()') + post_on(pump, data) end -- Send the specified request LLSD, expecting exactly one reply. Block @@ -128,7 +132,12 @@ end -- See also send(), generate(). function leap.request(pump, data) local reqid = leap._requestSetup(pump, data) - local ok, response = pcall(leap._pending[reqid].wait) + waitfor = leap._pending[reqid] +-- print_debug('leap.request('..tostring(pump)..', '..inspect(data)..') about to wait on '.. +-- tostring(waitfor)) + local ok, response = pcall(waitfor.wait, waitfor) +-- print_debug('leap.request('..tostring(pump)..', '..inspect(data)..') got '.. +-- tostring(ok)..': '..inspect(response)) -- kill off temporary WaitForReqid object, even if error leap._pending[reqid] = nil if ok then @@ -141,14 +150,15 @@ end -- common setup code shared by request() and generate() function leap._requestSetup(pump, data) -- invent a new, unique reqid - local reqid = leap._reqid leap._reqid += 1 + local reqid = leap._reqid -- Instantiate a new WaitForReqid object. The priority is irrelevant -- because, unlike the WaitFor base class, WaitForReqid does not -- self-register on our leap._waitfors list. Instead, capture the new -- WaitForReqid object in leap._pending so _dispatch() can find it. leap._pending[reqid] = leap.WaitForReqid:new(reqid) -- Pass reqid to send() to stamp it into (a copy of) the request data. +-- print_debug('leap._requestSetup('..tostring(pump)..', '..inspect(data)..')') leap.send(pump, data, reqid) return reqid end @@ -193,16 +203,17 @@ function leap.process() leap._done = false local ok, pump, data while not leap._done do +-- print_debug('leap.process() calling get_event_next()') ok, pump, data = pcall(get_event_next) - print_debug('leap.process() got', ok, pump, data) +-- print_debug('leap.process() got '..tostring(ok)..': '..pump..', '..inspect(data)) -- ok false means get_event_next() raised a Lua error -- data nil means get_event_next() returned (pump, LLSD()) to indicate done if not (ok and data) then - print_debug('leap.process() done') break end leap._dispatch(pump, data) end +-- print_debug('leap.process() done') -- we're done: clean up all pending coroutines -- if ok, then we're just done. -- if not ok, then 'pump' is actually the error message. @@ -249,7 +260,7 @@ function leap._unsolicited(pump, data) return end end - print_debug('_unsolicited(', pump, ', ', data, ') discarding unclaimed event') +-- print_debug('_unsolicited(', pump, ', ', data, ') discarding unclaimed event') end -- called by WaitFor.enable() @@ -354,9 +365,9 @@ end -- Block the calling coroutine until a suitable unsolicited event (one -- for which filter() returns the event) arrives. function leap.WaitFor:wait() - print_debug(self.name .. ' about to wait') +-- print_debug(self.name .. ' about to wait') item = self._queue:Dequeue() - print_debug(self.name .. ' got ', item) +-- print_debug(self.name .. ' got ', item) return item end -- cgit v1.2.3 From a5f11a5f9eb0af70e580d15ed87c01530b13d98d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 13 Mar 2024 14:39:43 -0400 Subject: util.join() is unnecessary: luau provides table.concat(). --- indra/newview/scripts/lua/util.lua | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index 898ddc58e3..e3af633ea7 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -36,34 +36,4 @@ function util.equal(t1, t2) return util.empty(temp) end --- Concatentate the strings in the passed list, return the composite string. --- For iterative string building, the theory is that building a list with --- table.insert() and then using join() to allocate the full-size result --- string once should be more efficient than reallocating an intermediate --- string for every partial concatenation. -function util.join(list, sep) - -- This succinct implementation assumes that string.format() precomputes - -- the required size of its output buffer before populating it. We don't - -- know that. Moreover, this implementation predates our sep argument. --- return string.format(string.rep('%s', #list), table.unpack(list)) - - -- this implementation makes it explicit - local sep = sep or '' - local size = if util.empty(list) then 0 else -#sep - for _, s in pairs(list) do - size += #sep + #s - end - local result = buffer.create(size) - size = 0 - for i, s in pairs(list) do - if i > 1 then - buffer.writestring(result, size, sep) - size += #sep - end - buffer.writestring(result, size, s) - size += #s - end - return buffer.tostring(result) -end - return util -- cgit v1.2.3 From 7f25ec566ed671119ecf3d47c4f3be54232969cb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 13 Mar 2024 14:46:14 -0400 Subject: Add tests for leap.request(). Use new coro.lua module. request() test ensures that the response for a given reqid is routed to the correct coroutine even when responses arrive out of order. --- indra/newview/tests/llluamanager_test.cpp | 51 ++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 36b8bb046a..069e10e9cf 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -312,6 +312,7 @@ namespace tut "-- test leap.lua\n" "\n" "leap = require('leap')\n" + "coro = require('coro')\n" "\n" "-- negative priority ensures catchall is always last\n" "catchall = leap.WaitFor:new(-1, 'catchall')\n" @@ -327,25 +328,65 @@ namespace tut "\n" "function drain(waitfor)\n" " print(waitfor.name .. ' start')\n" - " for item in waitfor.wait, waitfor do\n" + " -- It seems as though we ought to be able to code this loop\n" + " -- over waitfor:wait() as:\n" + " -- for item in waitfor.wait, waitfor do\n" + " -- However, that seems to stitch a detour through C code into\n" + " -- the coroutine call stack, which prohibits coroutine.yield():\n" + " -- 'attempt to yield across metamethod/C-call boundary'\n" + " -- So we resort to two different calls to waitfor:wait().\n" + " item = waitfor:wait()\n" + " while item do\n" " print(waitfor.name .. ' caught', item)\n" + " item = waitfor:wait()\n" " end\n" " print(waitfor.name .. ' done')\n" "end\n" "\n" - "co_all = coroutine.create(drain)\n" - "co_special = coroutine.create(drain)\n" - "coroutine.resume(co_all, catchall)\n" - "coroutine.resume(co_special, catch_special)\n" + "function requester(name)\n" + " print('requester('..name..') start')\n" + " response = leap.request('testpump', {name=name})\n" + " print('requester('..name..') got '..tostring(response))\n" + " -- verify that the correct response was dispatched to this coroutine\n" + " assert(response.name == name)\n" + "end\n" + "\n" + "coro.launch(drain, catchall)\n" + "coro.launch(drain, catch_special)\n" + "coro.launch(requester, 'a')\n" + "coro.launch(requester, 'b')\n" "\n" "leap.process()\n" ); + + LLSD requests; + LLEventStream pump("testpump", false); + LLTempBoundListener conn{ + pump.listen("test<5>()", + listener([&requests](const LLSD& data) + { + LL_DEBUGS("Lua") << "testpump got: " << data << LL_ENDL; + requests.append(data); + })) + }; + LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); auto replyname{ L.obtainListener()->getReplyName() }; auto& replypump{ LLEventPumps::instance().obtain(replyname) }; + // By the time leap.process() calls get_event_next() and wakes us up, + // we expect that both requester() coroutines have posted and are + // waiting for a reply. + ensure_equals("didn't get both requests", requests.size(), 2); + // moreover, we expect they arrived in the order they were created + ensure_equals("a wasn't first", requests[0]["name"].asString(), "a"); + ensure_equals("b wasn't second", requests[1]["name"].asString(), "b"); replypump.post(llsd::map("special", "K")); + // respond to requester(b) FIRST + replypump.post(requests[1]); replypump.post(llsd::map("name", "not special")); + // now respond to requester(a) + replypump.post(requests[0]); // tell leap.process() we're done replypump.post(LLSD()); auto [count, result] = future.get(); -- cgit v1.2.3 From b0ea6f5e0aed993b0f05de6bf7d03d81b520a5d0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 13 Mar 2024 22:15:56 +0200 Subject: viewer#945 Some worn items are missing from Avatar floater's Outfits tab --- indra/newview/llaisapi.cpp | 2 -- indra/newview/llinventorymodelbackgroundfetch.cpp | 17 +++++++++++++++++ indra/newview/lloutfitslist.cpp | 12 ++---------- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 17e1a27934..68b07a46c4 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -1385,8 +1385,6 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN && version > curr_cat->getVersion()) { - // Potentially should new_cat->setVersion(unknown) here, - // but might be waiting for a callback that would increment LL_DEBUGS("Inventory") << "Category " << category_id << " is stale. Known version: " << curr_cat->getVersion() << " server version: " << version << LL_ENDL; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 1f410bea10..c36b4b9726 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -30,6 +30,7 @@ #include "llaisapi.h" #include "llagent.h" #include "llappviewer.h" +#include "llappearancemgr.h" #include "llcallbacklist.h" #include "llinventorymodel.h" #include "llinventorypanel.h" @@ -423,6 +424,22 @@ void LLInventoryModelBackgroundFetch::fetchCOF(nullary_func_t callback) callback(); LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); LLInventoryModelBackgroundFetch::getInstance()->onAISFolderCalback(cat_id, id, FT_DEFAULT); + + if (id.notNull()) + { + // COF might have fetched base outfit folder through a link, but it hasn't + // fetched base outfit's content, which doesn't nessesary match COF, + // so make sure it's up to date + LLUUID baseoutfit_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID(); + if (baseoutfit_id.notNull()) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(baseoutfit_id); + if (!cat || cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + LLInventoryModelBackgroundFetch::getInstance()->fetchFolderAndLinks(baseoutfit_id, no_op); + } + } + } }); // start idle loop to track completion diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 5c7792b0df..ba714cbedd 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -885,18 +885,10 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) ++items_iter) { LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter); - if (!cat) + if (cat) { - LLInventoryObject* obj = gInventory.getObject(*items_iter); - if(!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) - { - return; - } - cat = (LLViewerInventoryCategory*)obj; + updateChangedCategoryName(cat, cat->getName()); } - std::string name = cat->getName(); - - updateChangedCategoryName(cat, name); } sortOutfits(); -- cgit v1.2.3 From e9231a987d64d2ad7e19dee30645409cab0b48e5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 14 Mar 2024 11:22:52 -0400 Subject: Fix a bug in leap.generate(). We weren't passing the WaitForReqid instance to WaitForReqid:wait(). Also remove 'reqid' from responses returned by leap.request() and generate(). --- indra/newview/scripts/lua/leap.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 2dd0d7b8ec..81728e7230 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -132,7 +132,7 @@ end -- See also send(), generate(). function leap.request(pump, data) local reqid = leap._requestSetup(pump, data) - waitfor = leap._pending[reqid] + local waitfor = leap._pending[reqid] -- print_debug('leap.request('..tostring(pump)..', '..inspect(data)..') about to wait on '.. -- tostring(waitfor)) local ok, response = pcall(waitfor.wait, waitfor) @@ -141,6 +141,7 @@ function leap.request(pump, data) -- kill off temporary WaitForReqid object, even if error leap._pending[reqid] = nil if ok then + response.reqid = nil return response else error(response) @@ -178,12 +179,14 @@ function leap.generate(pump, data, checklast) -- bearing that reqid. Stamp the outbound request with that reqid, and -- send it. local reqid = leap._requestSetup(pump, data) + local waitfor = leap._pending[reqid] local ok, response repeat - ok, response = pcall(leap._pending[reqid].wait) + ok, response = pcall(waitfor.wait, waitfor) if not ok then break end + response.reqid = nil coroutine.yield(response) until checklast and checklast(response) -- If we break the above loop, whether or not due to error, clean up. -- cgit v1.2.3 From bac113e30d987d7884c58490e6ea39a1bbd87d05 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 14 Mar 2024 11:24:51 -0400 Subject: Add preliminary Lua viewer API modules, with test scripts. --- indra/newview/scripts/lua/LLFloaterAbout.lua | 11 ++++++++ indra/newview/scripts/lua/LLGesture.lua | 23 ++++++++++++++++ indra/newview/scripts/lua/UI.lua | 16 ++++++++++++ indra/newview/scripts/lua/test_LLFloaterAbout.lua | 14 ++++++++++ indra/newview/scripts/lua/test_LLGesture.lua | 32 +++++++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 indra/newview/scripts/lua/LLFloaterAbout.lua create mode 100644 indra/newview/scripts/lua/LLGesture.lua create mode 100644 indra/newview/scripts/lua/UI.lua create mode 100644 indra/newview/scripts/lua/test_LLFloaterAbout.lua create mode 100644 indra/newview/scripts/lua/test_LLGesture.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/LLFloaterAbout.lua b/indra/newview/scripts/lua/LLFloaterAbout.lua new file mode 100644 index 0000000000..44afee2e5c --- /dev/null +++ b/indra/newview/scripts/lua/LLFloaterAbout.lua @@ -0,0 +1,11 @@ +-- Engage the LLFloaterAbout LLEventAPI + +leap = require 'leap' + +local LLFloaterAbout = {} + +function LLFloaterAbout.getInfo() + return leap.request('LLFloaterAbout', {op='getInfo'}) +end + +return LLFloaterAbout diff --git a/indra/newview/scripts/lua/LLGesture.lua b/indra/newview/scripts/lua/LLGesture.lua new file mode 100644 index 0000000000..cb410446d7 --- /dev/null +++ b/indra/newview/scripts/lua/LLGesture.lua @@ -0,0 +1,23 @@ +-- Engage the LLGesture LLEventAPI + +leap = require 'leap' + +local LLGesture = {} + +function LLGesture.getActiveGestures() + return leap.request('LLGesture', {op='getActiveGestures'})['gestures'] +end + +function LLGesture.isGesturePlaying(id) + return leap.request('LLGesture', {op='isGesturePlaying', id=id})['playing'] +end + +function LLGesture.startGesture(id) + leap.send('LLGesture', {op='startGesture', id=id}) +end + +function LLGesture.stopGesture(id) + leap.send('LLGesture', {op='stopGesture', id=id}) +end + +return LLGesture diff --git a/indra/newview/scripts/lua/UI.lua b/indra/newview/scripts/lua/UI.lua new file mode 100644 index 0000000000..f851632bad --- /dev/null +++ b/indra/newview/scripts/lua/UI.lua @@ -0,0 +1,16 @@ +-- Engage the UI LLEventAPI + +leap = require 'leap' + +local UI = {} + +function UI.call(func, parameter) + -- 'call' is fire-and-forget + leap.send('UI', {op='call', ['function']=func, parameter=parameter}) +end + +function UI.getValue(path) + return leap.request('UI', {op='getValue', path=path})['value'] +end + +return UI diff --git a/indra/newview/scripts/lua/test_LLFloaterAbout.lua b/indra/newview/scripts/lua/test_LLFloaterAbout.lua new file mode 100644 index 0000000000..7abc437b79 --- /dev/null +++ b/indra/newview/scripts/lua/test_LLFloaterAbout.lua @@ -0,0 +1,14 @@ +-- test LLFloaterAbout + +LLFloaterAbout = require('LLFloaterAbout') +leap = require('leap') +coro = require('coro') +inspect = require('inspect') + +coro.launch(function () + print(inspect(LLFloaterAbout.getInfo())) + leap.done() +end) + +leap.process() + diff --git a/indra/newview/scripts/lua/test_LLGesture.lua b/indra/newview/scripts/lua/test_LLGesture.lua new file mode 100644 index 0000000000..5c0db6c063 --- /dev/null +++ b/indra/newview/scripts/lua/test_LLGesture.lua @@ -0,0 +1,32 @@ +-- exercise LLGesture API + +LLGesture = require 'LLGesture' +inspect = require 'inspect' +coro = require 'coro' +leap = require 'leap' + +coro.launch(function() + -- getActiveGestures() returns {<UUID>: {name, playing, trigger}} + gestures_uuid = LLGesture.getActiveGestures() + -- convert to {<name>: <uuid>} + gestures = {} + for uuid, info in pairs(gestures_uuid) do + gestures[info.name] = uuid + end + -- now run through the list + for name, uuid in pairs(gestures) do + if name == 'afk' then + -- afk has a long timeout, and isn't interesting to look at + continue + end + print(name) + LLGesture.startGesture(uuid) + repeat + sleep(1) + until not LLGesture.isGesturePlaying(uuid) + end + print('Done.') + leap.done() +end) + +leap.process() -- cgit v1.2.3 From 7975a45eb0e72c78a90f2fde449e14c1f607561b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 14 Mar 2024 23:04:54 +0200 Subject: viewer#970 Fixed param validation warnings --- indra/newview/llfloateremojipicker.cpp | 1 + indra/newview/llpanelemojicomplete.cpp | 3 +++ indra/newview/skins/default/xui/en/floater_fast_timers.xml | 2 ++ indra/newview/skins/default/xui/en/floater_world_map.xml | 3 ++- 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index 1578caa39c..6d80a18599 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -424,6 +424,7 @@ void LLFloaterEmojiPicker::fillGroups() LLButton::Params params; params.font = LLFontGL::getFontEmoji(); + params.name = "all_categories"; LLRect rect; rect.mTop = mGroups->getRect().getHeight(); diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp index e6e3a10e13..c7c0627009 100644 --- a/indra/newview/llpanelemojicomplete.cpp +++ b/indra/newview/llpanelemojicomplete.cpp @@ -68,6 +68,9 @@ LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p { LLScrollbar::Params sbparams; sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(mTotalEmojis); + sbparams.doc_pos(0); + sbparams.page_size(mVisibleEmojis); sbparams.change_callback([this](S32 index, LLScrollbar*) { onScrollbarChange(index); }); mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams); addChild(mScrollbar); diff --git a/indra/newview/skins/default/xui/en/floater_fast_timers.xml b/indra/newview/skins/default/xui/en/floater_fast_timers.xml index 645003cc14..f4e61a828e 100644 --- a/indra/newview/skins/default/xui/en/floater_fast_timers.xml +++ b/indra/newview/skins/default/xui/en/floater_fast_timers.xml @@ -74,6 +74,8 @@ orientation="vertical" step_size="16" doc_size="3000" + page_size="50" + doc_pos="0" /> </layout_panel> <layout_panel name="timers_panel" diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml index c965a4427c..fbba1290c0 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -34,7 +34,8 @@ top="16" left="0" right="-1" - bottom="-1"> + bottom="-1" + orientation="horizontal"> <layout_panel name="map_lp" width="385" -- cgit v1.2.3 From ad1f5ac8906316f8e90355a4ebdbf33400758080 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 19 Mar 2024 15:32:47 +0200 Subject: search xml file in the lib, if path is not full; add test lua floater scripts --- indra/newview/scripts/lua/luafloater_demo.xml | 82 ++++++++++++++++++++++ .../scripts/lua/luafloater_gesture_list.xml | 21 ++++++ indra/newview/scripts/lua/test_luafloater_demo.lua | 69 ++++++++++++++++++ .../scripts/lua/test_luafloater_gesture_list.lua | 62 ++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 indra/newview/scripts/lua/luafloater_demo.xml create mode 100644 indra/newview/scripts/lua/luafloater_gesture_list.xml create mode 100644 indra/newview/scripts/lua/test_luafloater_demo.lua create mode 100644 indra/newview/scripts/lua/test_luafloater_gesture_list.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/luafloater_demo.xml b/indra/newview/scripts/lua/luafloater_demo.xml new file mode 100644 index 0000000000..069f229128 --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_demo.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="150" + layout="topleft" + name="lua_demo" + title="LUA" + width="320"> + <check_box + height="16" + label="Disable button" + layout="topleft" + top_pad="35" + left="5" + name="disable_ctrl" + width="146" /> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="openfloater_cmd" + top_delta="25" + width="100" /> + <button + follows="left|bottom" + height="23" + label="Open floater" + layout="topleft" + name="open_btn" + top_delta="25" + width="100" > + </button> + <text + type="string" + follows="left|top" + height="10" + layout="topleft" + top="30" + left_delta="170" + name="title_lbl"> + Select title + </text> + <combo_box + follows="top|left" + height="23" + name="title_cmb" + top_pad="5" + width="100"> + <combo_box.item + label="LUA" + value="LUA" /> + <combo_box.item + label="LUA floater" + value="LUA floater" /> + <combo_box.item + label="LUA-U title" + value="LUA-U title" /> + </combo_box> + <text + type="string" + follows="left|bottom" + height="10" + layout="topleft" + top_delta="50" + name="show_time_lbl"> + Double click me + </text> + <text + type="string" + follows="left|top" + height="10" + layout="topleft" + top_pad="15" + font="SansSerif" + text_color="white" + left_delta="15" + name="time_lbl"/> +</floater> diff --git a/indra/newview/scripts/lua/luafloater_gesture_list.xml b/indra/newview/scripts/lua/luafloater_gesture_list.xml new file mode 100644 index 0000000000..a38a04eed0 --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_gesture_list.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="150" + layout="topleft" + name="lua_gestures" + title="Gestures" + width="320"> + <scroll_list + draw_heading="false" + left="5" + width="310" + height="115" + top_pad ="25" + follows="all" + name="gesture_list"> + <scroll_list.columns + name="gesture_name" + label="Name"/> + </scroll_list> +</floater> diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua new file mode 100644 index 0000000000..a7bbdccb30 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -0,0 +1,69 @@ +XML_FILE_PATH = "luafloater_demo.xml" + +leap = require 'leap' +coro = require 'coro' + +--event pump for sending actions to the floater +COMMAND_PUMP_NAME = "" +--table of floater UI events +e={} +coro.launch(function () + e = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] + leap.done() +end) +leap.process() + +function post(action) + leap.send(COMMAND_PUMP_NAME, action) +end + +function getCurrentTime() + local currentTime = os.date("*t") + return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec) +end + +function handleEvents(event_data) + if event_data.event == e.COMMIT_EVENT then + if event_data.ctrl_name == "disable_ctrl" then + post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) + elseif event_data.ctrl_name == "title_cmb" then + post({action="set_title", value= event_data.value}) + elseif event_data.ctrl_name == "open_btn" then + floater_name = leap.request(COMMAND_PUMP_NAME, {action="get_value", ctrl_name='openfloater_cmd'})['value'] + leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) + end + elseif event_data.event == e.DOUBLE_CLICK_EVENT then + if event_data.ctrl_name == "show_time_lbl" then + post({action="set_value", ctrl_name="time_lbl", value= getCurrentTime()}) + end + elseif event_data.event == e.CLOSE_EVENT then + print_warning("Floater was closed") + leap.done() + --script received event pump name, after floater was built + elseif event_data.event == e.POST_BUILD_EVENT then + COMMAND_PUMP_NAME = event_data.command_name + end +end + +catch_events = leap.WaitFor:new(-1, "all_events") +function catch_events:filter(pump, data) + return data +end + +function process_events(waitfor) + event_data = waitfor:wait() + while event_data do + handleEvents(event_data) + event_data = waitfor:wait() + end +end + +local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} + +--sign for additional events for defined control {<control_name>= {action1, action2, ...}} +key.extra_events={show_time_lbl = {e.RIGHT_MOUSE_DOWN_EVENT, e.DOUBLE_CLICK_EVENT}} +leap.send("LLFloaterReg", key) + +coro.launch(process_events, catch_events) +leap.process() +print_warning("End of the script") diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua new file mode 100644 index 0000000000..070ff8415a --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -0,0 +1,62 @@ +XML_FILE_PATH = "luafloater_gesture_list.xml" + +leap = require 'leap' +coro = require 'coro' +LLGesture = require 'LLGesture' + +--event pump for sending actions to the floater +COMMAND_PUMP_NAME = "" +--table of floater UI events +e={} +coro.launch(function () + e = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] + leap.done() +end) +leap.process() + +function post(action) + leap.send(COMMAND_PUMP_NAME, action) +end + +function handleEvents(event_data) + if event_data.event == e.CLOSE_EVENT then + leap.done() + elseif event_data.event == e.POST_BUILD_EVENT then + COMMAND_PUMP_NAME = event_data.command_name + gestures_uuid = LLGesture.getActiveGestures() + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "gesture_list" + gestures = {} + for uuid, info in pairs(gestures_uuid) do + element={value = uuid, columns ={column = "gesture_name", value = info.name}} + action_data.value = element + post(action_data) + end + elseif event_data.event == e.DOUBLE_CLICK_EVENT then + if event_data.ctrl_name == "gesture_list" then + LLGesture.startGesture(event_data.value) + end + end +end + +catch_events = leap.WaitFor:new(-1, "all_events") +function catch_events:filter(pump, data) + return data +end + +function process_events(waitfor) + event_data = waitfor:wait() + while event_data do + handleEvents(event_data) + event_data = waitfor:wait() + end +end + +local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} +--receive additional events for defined control {<control_name>= {action1, action2, ...}} +key.extra_events={gesture_list = {e.DOUBLE_CLICK_EVENT}} +leap.send("LLFloaterReg", key) + +coro.launch(process_events, catch_events) +leap.process() -- cgit v1.2.3 From ba6784647b53919c09ef339fd99af152aa0f8458 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 20 Mar 2024 23:21:48 +0200 Subject: LLLuaFloater code clean up --- indra/newview/scripts/lua/test_luafloater_demo.lua | 2 +- indra/newview/scripts/lua/test_luafloater_gesture_list.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index a7bbdccb30..2cbafcec14 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -62,7 +62,7 @@ local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --sign for additional events for defined control {<control_name>= {action1, action2, ...}} key.extra_events={show_time_lbl = {e.RIGHT_MOUSE_DOWN_EVENT, e.DOUBLE_CLICK_EVENT}} -leap.send("LLFloaterReg", key) +leap.send("LLFloaterReg", key, "floater1") coro.launch(process_events, catch_events) leap.process() diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index 070ff8415a..5ea2b1e30d 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -56,7 +56,7 @@ end local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --receive additional events for defined control {<control_name>= {action1, action2, ...}} key.extra_events={gesture_list = {e.DOUBLE_CLICK_EVENT}} -leap.send("LLFloaterReg", key) +leap.send("LLFloaterReg", key, "floater1") coro.launch(process_events, catch_events) leap.process() -- cgit v1.2.3 From 0566af988790e95414ed18cd82206710094d8fae Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 21 Mar 2024 23:56:46 +0900 Subject: WIP: Add fiber.lua module and use in leap.lua and WaitQueue.lua. fiber.lua goes beyond coro.lua in that it distinguishes ready suspended coroutines from waiting suspended coroutines, and presents a rudimentary scheduler in fiber.yield(). yield() can determine that when all coroutines are waiting, it's time to retrieve the next incoming event from the viewer. Moreover, it can detect when all coroutines have completed and exit without being explicitly told. fiber.launch() associates a name with each fiber for debugging purposes. fiber.get_name() retrieves the name of the specified fiber, or the running fiber. fiber.status() is like coroutine.status(), but can return 'ready' or 'waiting' instead of 'suspended'. fiber.yield() leaves the calling fiber ready, but lets other ready fibers run. fiber.wait() suspends the calling fiber and lets other ready fibers run. fiber.wake(), called from some other coroutine, returns the passed fiber to ready status for a future call to fiber.yield(). fiber.run() drives the scheduler to run all fibers to completion. If, on completion of the subject Lua script, LuaState::expr() detects that the script loaded fiber.lua, it calls fiber.run() to finish running any dangling fibers. This lets a script make calls to fiber.launch() and then just fall off the end, leaving the implicit fiber.run() call to run them all. fiber.lua is designed to allow the main thread, as well as explicitly launched coroutines, to make leap.request() calls. This part still needs debugging. The leap.lua module now configures a fiber.set_idle() function that honors leap.done(), but calls get_event_next() and dispatches the next incoming event. leap.request() and generate() now leave the reqid stamp in the response. This lets a caller handle subsequent events with the same reqid, e.g. for LLLuaFloater. Remove leap.process(): it has been superseded by fiber.run(). Remove leap.WaitFor:iterate(): unfortunately that would run afoul of the Luau bug that prevents suspending the calling coroutine within a generic 'for' iterator function. Make leap.lua use weak tables to track WaitFor objects. Make WaitQueue:Dequeue() call fiber.wait() to suspend its caller when the queue is empty, and Enqueue() call fiber.wake() to set it ready again when a new item is pushed. Make llluamanager_test.cpp's leap test script use the fiber module to launch coroutines, instead of the coro module. Fix a bug in which its drain() function was inadvertently setting and testing the global 'item' variable instead of one local to the function. Since some other modules had the same bug, it was getting confused. Also add printf.lua, providing a printf() function. printf() is short for print(string.format()), but it can also print tables: anything not a number or string is formatted using the inspect() function. Clean up some LL_DEBUGS() output left over from debugging lua_tollsd(). --- indra/newview/scripts/lua/WaitQueue.lua | 29 ++- indra/newview/scripts/lua/fiber.lua | 301 ++++++++++++++++++++++++++++++ indra/newview/scripts/lua/leap.lua | 195 ++++++++++--------- indra/newview/scripts/lua/printf.lua | 19 ++ indra/newview/tests/llluamanager_test.cpp | 34 ++-- 5 files changed, 448 insertions(+), 130 deletions(-) create mode 100644 indra/newview/scripts/lua/fiber.lua create mode 100644 indra/newview/scripts/lua/printf.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index 00766ccae7..b15e9c443b 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -2,8 +2,12 @@ -- the Dequeue() operation blocks the calling coroutine until some other -- coroutine Enqueue()s a new value. +local fiber = require('fiber') local Queue = require('Queue') +-- local debug = print_debug +local function debug(...) end + local WaitQueue = Queue:new() function WaitQueue:new() @@ -32,11 +36,9 @@ function WaitQueue:_wake_waiters() -- cases. With multiple consumers, if more than one is trying to -- Dequeue() from an empty WaitQueue, we'll have multiple waiters. -- Unlike OS threads, with cooperative concurrency it doesn't make sense - -- to "notify all": we need resume only one of the waiting Dequeue() - -- callers. But since resuming that caller might entail either Enqueue() - -- or Dequeue() calls, recheck every time around to see if we must resume - -- another waiting coroutine. - while not self:IsEmpty() and #self._waiters > 0 do + -- to "notify all": we need wake only one of the waiting Dequeue() + -- callers. + if not self:IsEmpty() and next(self._waiters) then -- Pop the oldest waiting coroutine instead of the most recent, for -- more-or-less round robin fairness. But skip any coroutines that -- have gone dead in the meantime. @@ -47,11 +49,7 @@ function WaitQueue:_wake_waiters() -- do we still have at least one waiting coroutine? if waiter then -- don't pass the head item: let the resumed coroutine retrieve it - local ok, message = coroutine.resume(waiter) - -- if resuming that waiter encountered an error, don't swallow it - if not ok then - error(message) - end + fiber.wake(waiter) end end end @@ -62,18 +60,17 @@ function WaitQueue:Dequeue() -- the queue while there are still items left, and we want the -- consumer(s) to retrieve those last few items. if self._closed then + debug('WaitQueue:Dequeue(): closed') return nil end - local coro = coroutine.running() - if coro == nil then - error("WaitQueue:Dequeue() trying to suspend main coroutine") - end + debug('WaitQueue:Dequeue(): waiting') -- add the running coroutine to the list of waiters - table.insert(self._waiters, coro) + table.insert(self._waiters, fiber.running()) -- then let somebody else run - coroutine.yield() + fiber.wait() end -- here we're sure this queue isn't empty + debug('WaitQueue:Dequeue() calling Queue.Dequeue()') return Queue.Dequeue(self) end diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua new file mode 100644 index 0000000000..f18d133cc8 --- /dev/null +++ b/indra/newview/scripts/lua/fiber.lua @@ -0,0 +1,301 @@ +-- Organize Lua coroutines into fibers. + +-- In this usage, the difference between coroutines and fibers is that fibers +-- have a scheduler. Yielding a fiber means allowing other fibers, plural, to +-- run: it's more than just returning control to the specific Lua thread that +-- resumed the running coroutine. + +-- fiber.launch() creates a new fiber ready to run. +-- fiber.status() reports (augmented) status of the passed fiber: instead of +-- 'suspended', it returns either 'ready' or 'waiting' +-- fiber.yield() allows other fibers to run, but leaves the calling fiber +-- ready to run. +-- fiber.wait() marks the running fiber not ready, and resumes other fibers. +-- fiber.wake() marks the designated suspended fiber ready to run, but does +-- not yet resume it. +-- fiber.run() runs all current fibers until all have terminated (successfully +-- or with an error). + +local printf = require 'printf' +-- local debug = printf +local function debug(...) end +local coro = require 'coro' + +local fiber = {} + +-- The tables in which we track fibers must have weak keys so dead fibers +-- can be garbage-collected. +local weak_values = {__mode='v'} +local weak_keys = {__mode='k'} + +-- Track each current fiber as being either ready to run or not ready +-- (waiting). wait() moves the running fiber from ready to waiting; wake() +-- moves the designated fiber from waiting back to ready. +-- The ready table is used as a list so yield() can go round robin. +local ready = setmetatable({'main'}, weak_keys) +-- The waiting table is used as a set because order doesn't matter. +local waiting = setmetatable({}, weak_keys) + +-- Every fiber has a name, for diagnostic purposes. Names must be unique. +-- A colliding name will be suffixed with an integer. +-- Predefine 'main' with our marker so nobody else claims that name. +local names = setmetatable({main='main'}, weak_keys) +local byname = setmetatable({main='main'}, weak_values) +-- each colliding name has its own distinct suffix counter +local suffix = {} + +-- Specify a nullary idle() callback to be called whenever there are no ready +-- fibers but there are waiting fibers. The idle() callback is responsible for +-- changing zero or more waiting fibers to ready fibers by calling +-- fiber.wake(), although a given call may leave them all still waiting. +-- When there are no ready fibers, it's a good idea for the idle() function to +-- return control to a higher-level execution agent. Simply returning without +-- changing any fiber's status will spin the CPU. +-- The idle() callback can return non-nil to exit fiber.run() with that value. +function fiber._idle() + error('fiber.yield(): you must first call set_idle(nullary idle() function)') +end + +function fiber.set_idle(func) + fiber._idle = func +end + +-- Launch a new Lua fiber, ready to run. +function fiber.launch(name, func, ...) + local args = table.pack(...) + local co = coroutine.create(function() func(table.unpack(args)) end) + -- a new fiber is ready to run + table.insert(ready, co) + local namekey = name + while byname[namekey] do + if not suffix[name] then + suffix[name] = 1 + end + suffix[name] += 1 + namekey = name .. tostring(suffix[name]) + end + -- found a namekey not yet in byname: set it + byname[namekey] = co + -- and remember it as this fiber's name + names[co] = namekey +-- debug('launch(%s)', namekey) +-- debug('byname[%s] = %s', namekey, tostring(byname[namekey])) +-- debug('names[%s] = %s', tostring(co), names[co]) +-- debug('ready[-1] = %s', tostring(ready[#ready])) +end + +-- for debugging +function fiber.print_all() + print('Ready fibers:' .. if next(ready) then '' else ' none') + for _, co in pairs(ready) do + printf(' %s: %s', fiber.get_name(co), fiber.status(co)) + end + print('Waiting fibers:' .. if next(waiting) then '' else ' none') + for co in pairs(waiting) do + printf(' %s: %s', fiber.get_name(co), fiber.status(co)) + end +end + +-- return either the running coroutine or, if called from the main thread, +-- 'main' +function fiber.running() + return coroutine.running() or 'main' +end + +-- Query a fiber's name (nil for the running fiber) +function fiber.get_name(co) + if not co then + co = fiber.running() + end + if not names[co] then + return 'unknown' + end + return names[co] +end + +-- Query status of the passed fiber +function fiber.status(co) + local running = coroutine.running() + if (not co) or co == running then + -- silly to ask the status of the running fiber: it's 'running' + return 'running' + end + if co ~= 'main' then + -- for any coroutine but main, consult coroutine.status() + local status = coroutine.status(co) + if status ~= 'suspended' then + return status + end + -- here co is suspended, answer needs further refinement + else + -- co == 'main' + if not running then + -- asking about 'main' from the main fiber + return 'running' + end + -- asking about 'main' from some other fiber, so presumably main is suspended + end + -- here we know co is suspended -- but is it ready to run? + if waiting[co] then + return 'waiting' + end + -- not waiting should imply ready: sanity check + for _, maybe in pairs(ready) do + if maybe == co then + return 'ready' + end + end + -- Calls within yield() between popping the next ready fiber and + -- re-appending it to the list are in this state. Once we're done + -- debugging yield(), we could reinstate either of the below. +-- error(string.format('fiber.status(%s) is stumped', fiber.get_name(co))) +-- print(string.format('*** fiber.status(%s) is stumped', fiber.get_name(co))) + return '(unknown)' +end + +-- change the running fiber's status to waiting +local function set_waiting() + -- if called from the main fiber, inject a 'main' marker into the list + co = fiber.running() + -- delete from ready list + for i, maybe in pairs(ready) do + if maybe == co then + table.remove(ready, i) + break + end + end + -- add to waiting list + waiting[co] = true +end + +-- Suspend the current fiber until some other fiber calls fiber.wake() on it +function fiber.wait() + set_waiting() + -- now yield to other fibers + fiber.yield() +end + +-- Mark a suspended fiber as being ready to run +function fiber.wake(co) + if not waiting[co] then + error(string.format('fiber.wake(%s) but status=%s, ready=%s, waiting=%s', + names[co], fiber.status(co), ready[co], waiting[co])) + end + -- delete from waiting list + waiting[co] = nil + -- add to end of ready list + table.insert(ready, co) + -- but don't yet resume it: that happens next time we reach yield() +end + +-- Run fibers until all but main have terminated: return nil. +-- Or until configured idle() callback returns x ~= nil: return x. +function fiber.run() + -- A fiber calling run() is not also doing other useful work. Tell yield() + -- that we're waiting. Otherwise it would keep seeing that our caller is + -- ready and return to us, instead of realizing that all coroutines are + -- waiting and call idle(). + set_waiting() + local others, idle_done + repeat + debug('%s calling fiber.run() calling yield()', fiber.get_name()) + others, idle_done = fiber.yield() + debug("%s fiber.run()'s yield() returned %s, %s", fiber.get_name(), + tostring(others), tostring(idle_done)) + until (not others) + debug('%s fiber.run() done', fiber.get_name()) + fiber.wake(fiber.running()) + -- Once there are no more waiting fibers, and the only ready fiber is + -- main, return to main. All previously-launched fibers are done. Possibly + -- the chunk is done, or the chunk may decide to launch a new batch of + -- fibers. + return idle_done +end + +-- pop and return the next not-dead fiber in the ready list, or nil if none remain +local function live_ready_iter() + -- don't write + -- for co in table.remove, ready, 1 + -- because it would keep passing a new second parameter! + for co in function() return table.remove(ready, 1) end do + debug('%s live_ready_iter() sees %s, status %s', + fiber.get_name(), fiber.get_name(co), fiber.status(co)) + -- keep removing the head entry until we find one that's not dead, + -- discarding any dead coroutines along the way + if co == 'main' or coroutine.status(co) ~= 'dead' then + debug('%s live_ready_iter() returning %s', + fiber.get_name(), fiber.get_name(co)) + return co + end + end + debug('%s live_ready_iter() returning nil', fiber.get_name()) + return nil +end + +-- prune the set of waiting fibers +local function prune_waiting() + for waiter in pairs(waiting) do + if waiter ~= 'main' and coroutine.status(waiter) == 'dead' then + waiting[waiter] = nil + end + end +end + +-- Give other ready fibers a chance to run, leaving this one ready, returning +-- after a cycle. Returns: +-- * true, nil if there remain other live fibers, whether ready or waiting +-- * false, nil if this is the only remaining fiber +-- * nil, x if configured idle() callback returned non-nil x +function fiber.yield() + if coroutine.running() then + -- seize the opportunity to make sure the viewer isn't shutting down +-- check_stop() + -- this is a real coroutine, yield normally to main or whoever + coroutine.yield() + -- main certainly still exists + return true + end + + -- This is the main fiber: coroutine.yield() doesn't work. + -- Instead, resume each of the ready fibers. + -- Prune the set of waiting fibers after every time fiber business logic + -- runs (i.e. other fibers might have terminated or hit error), such as + -- here on entry. + prune_waiting() + local others, idle_stop + repeat + for co in live_ready_iter do + -- seize the opportunity to make sure the viewer isn't shutting down +-- check_stop() + -- before we re-append co, is it the only remaining entry? + others = next(ready) + -- co is live, re-append it to the ready list + table.insert(ready, co) + if co == 'main' then + -- Since we know the caller is the main fiber, it's our turn. + -- Tell caller if there are other ready or waiting fibers. + return others or next(waiting) + end + -- not main, but some other ready coroutine: + -- use coro.resume() so we'll propagate any error encountered + coro.resume(co) + prune_waiting() + end + -- Here there are no ready fibers. Are there any waiting fibers? + if not next(waiting) then + return false + end + -- there are waiting fibers: call consumer's configured idle() function + idle_stop = fiber._idle() + if idle_stop ~= nil then + return nil, idle_stop + end + prune_waiting() + -- loop "forever", that is, until: + -- * main is ready, or + -- * there are neither ready fibers nor waiting fibers, or + -- * fiber._idle() returned non-nil + until false +end + +return fiber diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 81728e7230..60e8266a76 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -38,7 +38,10 @@ -- leap.process(). process() won't notice until the next event from the -- viewer, though. +local fiber = require('fiber') local ErrorQueue = require('ErrorQueue') +-- local debug = require('printf') +local function debug(...) end local leap = {} @@ -68,11 +71,13 @@ leap._reply, leap._command = get_event_pumps() -- later one. That means that no incoming event will ever be given to -- the old WaitForReqid object. Any coroutine waiting on the discarded -- WaitForReqid object would therefore wait forever. -leap._pending = {} +-- these are weak values tables +local weak_values = {__mode='v'} +leap._pending = setmetatable({}, weak_values) -- Our consumer will instantiate some number of WaitFor subclass objects. -- As these are traversed in descending priority order, we must keep -- them in a list. -leap._waitfors = {} +leap._waitfors = setmetatable({}, weak_values) -- It has been suggested that we should use UUIDs as ["reqid"] values, -- since UUIDs are guaranteed unique. However, as the "namespace" for -- ["reqid"] values is our very own _reply pump, we can get away with @@ -91,15 +96,13 @@ function leap.cmdpump() return leap._command end --- local inspect = require('inspect') - -- Fire and forget. Send the specified request LLSD, expecting no reply. -- In fact, should the request produce an eventual reply, it will be -- treated as an unsolicited event. -- -- See also request(), generate(). function leap.send(pump, data, reqid) --- print_debug('leap.send('..pump..', '..inspect(data)..', '..reqid..') entry') + debug('leap.send(%s, %s, %s) entry', pump, data, reqid) local data = data if type(data) == 'table' then data = table.clone(data) @@ -108,10 +111,26 @@ function leap.send(pump, data, reqid) data['reqid'] = reqid end end --- print_debug('leap.send('..pump..', '..inspect(data)..') calling post_on()') + debug('leap.send(%s, %s) calling post_on()', pump, data) post_on(pump, data) end +-- common setup code shared by request() and generate() +local function requestSetup(pump, data) + -- invent a new, unique reqid + leap._reqid += 1 + local reqid = leap._reqid + -- Instantiate a new WaitForReqid object. The priority is irrelevant + -- because, unlike the WaitFor base class, WaitForReqid does not + -- self-register on our leap._waitfors list. Instead, capture the new + -- WaitForReqid object in leap._pending so dispatch() can find it. + leap._pending[reqid] = leap.WaitForReqid:new(reqid) + -- Pass reqid to send() to stamp it into (a copy of) the request data. + debug('requestSetup(%s, %s)', pump, data) + leap.send(pump, data, reqid) + return reqid +end + -- Send the specified request LLSD, expecting exactly one reply. Block -- the calling coroutine until we receive that reply. -- @@ -131,39 +150,20 @@ end -- -- See also send(), generate(). function leap.request(pump, data) - local reqid = leap._requestSetup(pump, data) + local reqid = requestSetup(pump, data) local waitfor = leap._pending[reqid] --- print_debug('leap.request('..tostring(pump)..', '..inspect(data)..') about to wait on '.. --- tostring(waitfor)) + debug('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor)) local ok, response = pcall(waitfor.wait, waitfor) --- print_debug('leap.request('..tostring(pump)..', '..inspect(data)..') got '.. --- tostring(ok)..': '..inspect(response)) + debug('leap.request(%s, %s) got %s: %s', pump, data, ok, response) -- kill off temporary WaitForReqid object, even if error leap._pending[reqid] = nil if ok then - response.reqid = nil return response else error(response) end end --- common setup code shared by request() and generate() -function leap._requestSetup(pump, data) - -- invent a new, unique reqid - leap._reqid += 1 - local reqid = leap._reqid - -- Instantiate a new WaitForReqid object. The priority is irrelevant - -- because, unlike the WaitFor base class, WaitForReqid does not - -- self-register on our leap._waitfors list. Instead, capture the new - -- WaitForReqid object in leap._pending so _dispatch() can find it. - leap._pending[reqid] = leap.WaitForReqid:new(reqid) - -- Pass reqid to send() to stamp it into (a copy of) the request data. --- print_debug('leap._requestSetup('..tostring(pump)..', '..inspect(data)..')') - leap.send(pump, data, reqid) - return reqid -end - -- Send the specified request LLSD, expecting an arbitrary number of replies. -- Each one is yielded on receipt. If you omit checklast, this is an infinite -- generator; it's up to the caller to recognize when the last reply has been @@ -178,7 +178,7 @@ function leap.generate(pump, data, checklast) -- Invent a new, unique reqid. Arrange to handle incoming events -- bearing that reqid. Stamp the outbound request with that reqid, and -- send it. - local reqid = leap._requestSetup(pump, data) + local reqid = requestSetup(pump, data) local waitfor = leap._pending[reqid] local ok, response repeat @@ -186,7 +186,6 @@ function leap.generate(pump, data, checklast) if not ok then break end - response.reqid = nil coroutine.yield(response) until checklast and checklast(response) -- If we break the above loop, whether or not due to error, clean up. @@ -196,78 +195,79 @@ function leap.generate(pump, data, checklast) end end --- Kick off response processing. The calling script must create and resume one --- or more coroutines to perform viewer requests using send(), request() or --- generate() before calling this function to handle responses. --- --- While waiting for responses from the viewer, the C++ coroutine running the --- calling Lua script is blocked: no other Lua coroutine is running. -function leap.process() - leap._done = false - local ok, pump, data - while not leap._done do --- print_debug('leap.process() calling get_event_next()') - ok, pump, data = pcall(get_event_next) --- print_debug('leap.process() got '..tostring(ok)..': '..pump..', '..inspect(data)) - -- ok false means get_event_next() raised a Lua error - -- data nil means get_event_next() returned (pump, LLSD()) to indicate done - if not (ok and data) then - break - end - leap._dispatch(pump, data) - end --- print_debug('leap.process() done') +local function cleanup(message) -- we're done: clean up all pending coroutines - -- if ok, then we're just done. - -- if not ok, then 'pump' is actually the error message. - message = if ok then 'done' else pump for i, waitfor in pairs(leap._pending) do - waitfor:_exception(message) + waitfor:exception(message) end for i, waitfor in pairs(leap._waitfors) do - waitfor:_exception(message) - end - -- now that we're done with cleanup, propagate the error we caught above - if not ok then - error(pump) + waitfor:exception(message) end end -function leap.done() - leap._done = true +-- Handle an incoming (pump, data) event with no recognizable ['reqid'] +local function unsolicited(pump, data) + -- we maintain waitfors in descending priority order, so the first waitfor + -- to claim this event is the one with the highest priority + for i, waitfor in pairs(leap._waitfors) do + debug('unsolicited() checking %s', waitfor.name) + if waitfor:handle(pump, data) then + return + end + end + print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', pump, data)) end -- Route incoming (pump, data) event to the appropriate waiting coroutine. -function leap._dispatch(pump, data) +local function dispatch(pump, data) local reqid = data['reqid'] -- if the response has no 'reqid', it's not from request() or generate() if reqid == nil then - return leap._unsolicited(pump, data) + return unsolicited(pump, data) end -- have reqid; do we have a WaitForReqid? local waitfor = leap._pending[reqid] if waitfor == nil then - return leap._unsolicited(pump, data) + return unsolicited(pump, data) end -- found the right WaitForReqid object, let it handle the event - data['reqid'] = nil - waitfor:_handle(pump, data) + waitfor:handle(pump, data) end --- Handle an incoming (pump, data) event with no recognizable ['reqid'] -function leap._unsolicited(pump, data) - -- we maintain waitfors in descending priority order, so the first waitfor - -- to claim this event is the one with the highest priority - for i, waitfor in pairs(leap._waitfors) do - if waitfor:_handle(pump, data) then - return - end +-- We configure fiber.set_idle() function. fiber.yield() calls the configured +-- idle callback whenever there are waiting fibers but no ready fibers. In +-- our case, that means it's time to fetch another incoming viewer event. +fiber.set_idle(function () + -- If someone has called leap.done(), then tell fiber.yield() to break loop. + if leap._done then + cleanup('done') + return 'done' + end + debug('leap.idle() calling get_event_next()') + local ok, pump, data = pcall(get_event_next) + debug('leap.idle() got %s: %s, %s', ok, pump, data) + -- ok false means get_event_next() raised a Lua error, pump is message + if not ok then + cleanup(pump) + error(pump) + end + -- data nil means get_event_next() returned (pump, LLSD()) to indicate done + if not data then + cleanup('end') + return 'end' end --- print_debug('_unsolicited(', pump, ', ', data, ') discarding unclaimed event') + -- got a real pump, data pair + dispatch(pump, data) + -- return to fiber.yield(): any incoming message might result in one or + -- more fibers becoming ready +end) + +function leap.done() + leap._done = true end -- called by WaitFor.enable() -function leap._registerWaitFor(waitfor) +local function registerWaitFor(waitfor) table.insert(leap._waitfors, waitfor) -- keep waitfors sorted in descending order of specified priority table.sort(leap._waitfors, @@ -275,7 +275,7 @@ function leap._registerWaitFor(waitfor) end -- called by WaitFor.disable() -function leap._unregisterWaitFor(waitfor) +local function unregisterWaitFor(waitfor) for i, w in pairs(leap._waitfors) do if w == waitfor then leap._waitfors[i] = nil @@ -322,8 +322,13 @@ end -- --------------------------------- WaitFor --------------------------------- leap.WaitFor = { _id=0 } +function leap.WaitFor.tostring(self) + -- Lua (sub)classes have no name; can't prefix with that + return self.name +end + function leap.WaitFor:new(priority, name) - local obj = setmetatable({}, self) + local obj = setmetatable({__tostring=leap.WaitFor.tostring}, self) self.__index = self obj.priority = priority @@ -343,16 +348,11 @@ function leap.WaitFor:new(priority, name) return obj end -function leap.WaitFor.tostring(self) - -- Lua (sub)classes have no name; can't prefix with that - return self.name -end - -- Re-enable a disable()d WaitFor object. New WaitFor objects are -- enable()d by default. function leap.WaitFor:enable() if not self._registered then - leap._registerWaitFor(self) + registerWaitFor(self) self._registered = true end end @@ -360,7 +360,7 @@ end -- Disable an enable()d WaitFor object. function leap.WaitFor:disable() if self._registered then - leap._unregisterWaitFor(self) + unregisterWaitFor(self) self._registered = false end end @@ -368,18 +368,12 @@ end -- Block the calling coroutine until a suitable unsolicited event (one -- for which filter() returns the event) arrives. function leap.WaitFor:wait() --- print_debug(self.name .. ' about to wait') - item = self._queue:Dequeue() --- print_debug(self.name .. ' got ', item) + debug('%s about to wait', self.name) + local item = self._queue:Dequeue() + debug('%s got %s', self.name, item) return item end --- Loop over wait() calls. -function leap.WaitFor:iterate() - -- on each iteration, call self.wait(self) - return self.wait, self, nil -end - -- Override filter() to examine the incoming event in whatever way -- makes sense. -- @@ -395,9 +389,10 @@ function leap.WaitFor:filter(pump, data) error('You must override the WaitFor.filter() method') end --- called by leap._unsolicited() for each WaitFor in leap._waitfors -function leap.WaitFor:_handle(pump, data) - item = self:filter(pump, data) +-- called by unsolicited() for each WaitFor in leap._waitfors +function leap.WaitFor:handle(pump, data) + local item = self:filter(pump, data) + debug('%s.filter() returned %s', self.name, item) -- if this item doesn't pass the filter, we're not interested if not item then return false @@ -407,13 +402,13 @@ function leap.WaitFor:_handle(pump, data) return true end --- called by WaitFor:_handle() for an accepted event +-- called by WaitFor:handle() for an accepted event function leap.WaitFor:process(item) self._queue:Enqueue(item) end -- called by leap.process() when get_event_next() raises an error -function leap.WaitFor:_exception(message) +function leap.WaitFor:exception(message) print_warning(self.name .. ' error: ' .. message) self._queue:Error(message) end diff --git a/indra/newview/scripts/lua/printf.lua b/indra/newview/scripts/lua/printf.lua new file mode 100644 index 0000000000..584cd4f391 --- /dev/null +++ b/indra/newview/scripts/lua/printf.lua @@ -0,0 +1,19 @@ +-- printf(...) is short for print(string.format(...)) + +local inspect = require 'inspect' + +local function printf(...) + -- string.format() only handles numbers and strings. + -- Convert anything else to string using the inspect module. + local args = {} + for _, arg in pairs(table.pack(...)) do + if type(arg) == 'number' or type(arg) == 'string' then + table.insert(args, arg) + else + table.insert(args, inspect(arg)) + end + end + print(string.format(table.unpack(args))) +end + +return printf diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 069e10e9cf..1dd081fb98 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -311,23 +311,27 @@ namespace tut const std::string lua( "-- test leap.lua\n" "\n" + "fiber = require('fiber')\n" "leap = require('leap')\n" - "coro = require('coro')\n" + "-- debug = require('printf')\n" + "local function debug(...) end\n" "\n" "-- negative priority ensures catchall is always last\n" "catchall = leap.WaitFor:new(-1, 'catchall')\n" "function catchall:filter(pump, data)\n" + " debug('catchall:filter(%s, %s)', pump, data)\n" " return data\n" "end\n" "\n" "-- but first, catch events with 'special' key\n" "catch_special = leap.WaitFor:new(2, 'catch_special')\n" "function catch_special:filter(pump, data)\n" + " debug('catch_special:filter(%s, %s)', pump, data)\n" " return if data['special'] ~= nil then data else nil\n" "end\n" "\n" "function drain(waitfor)\n" - " print(waitfor.name .. ' start')\n" + " debug('%s start', waitfor.name)\n" " -- It seems as though we ought to be able to code this loop\n" " -- over waitfor:wait() as:\n" " -- for item in waitfor.wait, waitfor do\n" @@ -335,28 +339,30 @@ namespace tut " -- the coroutine call stack, which prohibits coroutine.yield():\n" " -- 'attempt to yield across metamethod/C-call boundary'\n" " -- So we resort to two different calls to waitfor:wait().\n" - " item = waitfor:wait()\n" + " local item = waitfor:wait()\n" " while item do\n" - " print(waitfor.name .. ' caught', item)\n" + " debug('%s caught %s', waitfor.name, item)\n" " item = waitfor:wait()\n" " end\n" - " print(waitfor.name .. ' done')\n" + " debug('%s done', waitfor.name)\n" "end\n" "\n" "function requester(name)\n" - " print('requester('..name..') start')\n" - " response = leap.request('testpump', {name=name})\n" - " print('requester('..name..') got '..tostring(response))\n" + " debug('requester(%s) start', name)\n" + " local response = leap.request('testpump', {name=name})\n" + " debug('requester(%s) got %s', name, response)\n" " -- verify that the correct response was dispatched to this coroutine\n" " assert(response.name == name)\n" "end\n" "\n" - "coro.launch(drain, catchall)\n" - "coro.launch(drain, catch_special)\n" - "coro.launch(requester, 'a')\n" - "coro.launch(requester, 'b')\n" - "\n" - "leap.process()\n" + "-- fiber.print_all()\n" + "fiber.launch('catchall', drain, catchall)\n" + "fiber.launch('catch_special', drain, catch_special)\n" + "fiber.launch('requester(a)', requester, 'a')\n" + "-- requester(a)\n" + "fiber.launch('requester(b)', requester, 'b')\n" + "-- fiber.print_all()\n" + "-- fiber.run()\n" ); LLSD requests; -- cgit v1.2.3 From 76752d6fc00a2789d96480da2a1e862ffecc812a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 21 Mar 2024 18:26:48 +0200 Subject: Switch to LLDispatchListener --- indra/newview/scripts/lua/test_luafloater_demo.lua | 19 ++++++++++--------- .../scripts/lua/test_luafloater_gesture_list.lua | 14 +++++++++----- 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index 2cbafcec14..308cebcb88 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -39,12 +39,19 @@ function handleEvents(event_data) elseif event_data.event == e.CLOSE_EVENT then print_warning("Floater was closed") leap.done() - --script received event pump name, after floater was built - elseif event_data.event == e.POST_BUILD_EVENT then - COMMAND_PUMP_NAME = event_data.command_name end end +local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} +--sign for additional events for defined control {<control_name>= {action1, action2, ...}} +key.extra_events={show_time_lbl = {e.RIGHT_MOUSE_DOWN_EVENT, e.DOUBLE_CLICK_EVENT}} +coro.launch(function () + --script received event pump name, after floater was built + COMMAND_PUMP_NAME = leap.request("LLFloaterReg", key)["command_name"] + leap.done() +end) +leap.process() + catch_events = leap.WaitFor:new(-1, "all_events") function catch_events:filter(pump, data) return data @@ -58,12 +65,6 @@ function process_events(waitfor) end end -local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} - ---sign for additional events for defined control {<control_name>= {action1, action2, ...}} -key.extra_events={show_time_lbl = {e.RIGHT_MOUSE_DOWN_EVENT, e.DOUBLE_CLICK_EVENT}} -leap.send("LLFloaterReg", key, "floater1") - coro.launch(process_events, catch_events) leap.process() print_warning("End of the script") diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index 5ea2b1e30d..57f737ce9b 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -40,6 +40,15 @@ function handleEvents(event_data) end end +local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} +--receive additional events for defined control {<control_name>= {action1, action2, ...}} +key.extra_events={gesture_list = {e.DOUBLE_CLICK_EVENT}} +coro.launch(function () + handleEvents(leap.request("LLFloaterReg", key)) + leap.done() +end) +leap.process() + catch_events = leap.WaitFor:new(-1, "all_events") function catch_events:filter(pump, data) return data @@ -53,10 +62,5 @@ function process_events(waitfor) end end -local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} ---receive additional events for defined control {<control_name>= {action1, action2, ...}} -key.extra_events={gesture_list = {e.DOUBLE_CLICK_EVENT}} -leap.send("LLFloaterReg", key, "floater1") - coro.launch(process_events, catch_events) leap.process() -- cgit v1.2.3 From 4ffdae72392ba2f081edf8d740b688b95ac4fc65 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 21 Mar 2024 20:24:24 +0200 Subject: Accept an array for "add_list_item" and change EVENT_LIST type --- indra/newview/scripts/lua/test_luafloater_demo.lua | 20 ++++++++++++----- .../scripts/lua/test_luafloater_gesture_list.lua | 26 ++++++++++++++-------- indra/newview/scripts/lua/util.lua | 10 +++++++++ 3 files changed, 41 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index 308cebcb88..b81259c060 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -2,17 +2,25 @@ XML_FILE_PATH = "luafloater_demo.xml" leap = require 'leap' coro = require 'coro' +util = require 'util' --event pump for sending actions to the floater COMMAND_PUMP_NAME = "" --table of floater UI events -e={} +event_list={} coro.launch(function () - e = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] + event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] leap.done() end) leap.process() +local function _event(event_name) + if not util.contains(event_list, event_name) then + print_warning("Incorrect event name: " .. event_name) + end + return event_name +end + function post(action) leap.send(COMMAND_PUMP_NAME, action) end @@ -23,7 +31,7 @@ function getCurrentTime() end function handleEvents(event_data) - if event_data.event == e.COMMIT_EVENT then + if event_data.event == _event("commit") then if event_data.ctrl_name == "disable_ctrl" then post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) elseif event_data.ctrl_name == "title_cmb" then @@ -32,11 +40,11 @@ function handleEvents(event_data) floater_name = leap.request(COMMAND_PUMP_NAME, {action="get_value", ctrl_name='openfloater_cmd'})['value'] leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) end - elseif event_data.event == e.DOUBLE_CLICK_EVENT then + elseif event_data.event == _event("double_click") then if event_data.ctrl_name == "show_time_lbl" then post({action="set_value", ctrl_name="time_lbl", value= getCurrentTime()}) end - elseif event_data.event == e.CLOSE_EVENT then + elseif event_data.event == _event("floater_close") then print_warning("Floater was closed") leap.done() end @@ -44,7 +52,7 @@ end local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --sign for additional events for defined control {<control_name>= {action1, action2, ...}} -key.extra_events={show_time_lbl = {e.RIGHT_MOUSE_DOWN_EVENT, e.DOUBLE_CLICK_EVENT}} +key.extra_events={show_time_lbl = {_event("right_mouse_down"), _event("double_click")}} coro.launch(function () --script received event pump name, after floater was built COMMAND_PUMP_NAME = leap.request("LLFloaterReg", key)["command_name"] diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index 57f737ce9b..b46e36b4d9 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -2,26 +2,34 @@ XML_FILE_PATH = "luafloater_gesture_list.xml" leap = require 'leap' coro = require 'coro' +util = require 'util' LLGesture = require 'LLGesture' --event pump for sending actions to the floater COMMAND_PUMP_NAME = "" --table of floater UI events -e={} +event_list={} coro.launch(function () - e = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] + event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] leap.done() end) leap.process() +local function _event(event_name) + if not util.contains(event_list, event_name) then + print_warning("Incorrect event name: " .. event_name) + end + return event_name +end + function post(action) leap.send(COMMAND_PUMP_NAME, action) end function handleEvents(event_data) - if event_data.event == e.CLOSE_EVENT then + if event_data.event == _event("floater_close") then leap.done() - elseif event_data.event == e.POST_BUILD_EVENT then + elseif event_data.event == _event("post_build") then COMMAND_PUMP_NAME = event_data.command_name gestures_uuid = LLGesture.getActiveGestures() local action_data = {} @@ -29,11 +37,11 @@ function handleEvents(event_data) action_data.ctrl_name = "gesture_list" gestures = {} for uuid, info in pairs(gestures_uuid) do - element={value = uuid, columns ={column = "gesture_name", value = info.name}} - action_data.value = element - post(action_data) + table.insert(gestures, {value = uuid, columns ={column = "gesture_name", value = info.name}}) end - elseif event_data.event == e.DOUBLE_CLICK_EVENT then + action_data.value = gestures + post(action_data) + elseif event_data.event == _event("double_click") then if event_data.ctrl_name == "gesture_list" then LLGesture.startGesture(event_data.value) end @@ -42,7 +50,7 @@ end local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --receive additional events for defined control {<control_name>= {action1, action2, ...}} -key.extra_events={gesture_list = {e.DOUBLE_CLICK_EVENT}} +key.extra_events={gesture_list = {_event("double_click")}} coro.launch(function () handleEvents(leap.request("LLFloaterReg", key)) leap.done() diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index e3af633ea7..5d6042dfe5 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -36,4 +36,14 @@ function util.equal(t1, t2) return util.empty(temp) end +-- check if array-like table contains certain value +function util.contains(t, v) + for _, value in ipairs(t) do + if value == v then + return true + end + end + return false +end + return util -- cgit v1.2.3 From bb39a8b223f78205a10ffcb61e3b3bfe05b3fd1a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 22 Mar 2024 21:04:48 +0900 Subject: Fix a couple bugs in fiber.lua machinery. This fixes a hang if the Lua script explicitly calls fiber.run() before LuaState::expr()'s implicit fiber.run() call. Make fiber.run() remove the calling fiber from the ready list to avoid an infinite loop when all other fibers have terminated: "You're ready!" "Okay, yield()." "You're ready again!" ... But don't claim it's waiting, either, because then when all other fibers have terminated, we'd call idle() in the vain hope that something would make that one last fiber ready. WaitQueue:_wake_waiters() needs to wake waiting fibers if the queue's not empty OR it's been closed. Introduce leap.WaitFor:close() to close the queue gracefully so that a looping waiter can terminate, instead of using WaitFor:exception(), which stops the whole script once it propagates. Make leap's cleanup() function call close(). Streamline fiber.get_name() by using 'or' instead of if ... then. Streamline fiber.status() and fiber.set_waiting() by using table.find() instead of a loop. --- indra/newview/scripts/lua/ErrorQueue.lua | 4 +++ indra/newview/scripts/lua/WaitQueue.lua | 2 +- indra/newview/scripts/lua/fiber.lua | 42 ++++++++++++++----------------- indra/newview/scripts/lua/leap.lua | 9 +++++-- indra/newview/tests/llluamanager_test.cpp | 2 +- 5 files changed, 32 insertions(+), 27 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index a6d4470044..076742815a 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -3,18 +3,22 @@ -- raise that error. local WaitQueue = require('WaitQueue') +-- local debug = require('printf') +local function debug(...) end local ErrorQueue = WaitQueue:new() function ErrorQueue:Error(message) -- Setting Error() is a marker, like closing the queue. Once we reach the -- error, every subsequent Dequeue() call will raise the same error. + debug('Setting self._closed to %q', message) self._closed = message self:_wake_waiters() end function ErrorQueue:Dequeue() local value = WaitQueue.Dequeue(self) + debug('ErrorQueue:Dequeue: base Dequeue() got %s', value) if value ~= nil then -- queue not yet closed, show caller return value diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index b15e9c443b..f69baff09b 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -38,7 +38,7 @@ function WaitQueue:_wake_waiters() -- Unlike OS threads, with cooperative concurrency it doesn't make sense -- to "notify all": we need wake only one of the waiting Dequeue() -- callers. - if not self:IsEmpty() and next(self._waiters) then + if ((not self:IsEmpty()) or self._closed) and next(self._waiters) then -- Pop the oldest waiting coroutine instead of the most recent, for -- more-or-less round robin fairness. But skip any coroutines that -- have gone dead in the meantime. diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua index f18d133cc8..8ed99f12b7 100644 --- a/indra/newview/scripts/lua/fiber.lua +++ b/indra/newview/scripts/lua/fiber.lua @@ -104,13 +104,7 @@ end -- Query a fiber's name (nil for the running fiber) function fiber.get_name(co) - if not co then - co = fiber.running() - end - if not names[co] then - return 'unknown' - end - return names[co] + return names[co or fiber.running()] or 'unknown' end -- Query status of the passed fiber @@ -140,10 +134,8 @@ function fiber.status(co) return 'waiting' end -- not waiting should imply ready: sanity check - for _, maybe in pairs(ready) do - if maybe == co then - return 'ready' - end + if table.find(ready, co) then + return 'ready' end -- Calls within yield() between popping the next ready fiber and -- re-appending it to the list are in this state. Once we're done @@ -158,11 +150,9 @@ local function set_waiting() -- if called from the main fiber, inject a 'main' marker into the list co = fiber.running() -- delete from ready list - for i, maybe in pairs(ready) do - if maybe == co then - table.remove(ready, i) - break - end + local i = table.find(ready, co) + if i then + table.remove(ready, i) end -- add to waiting list waiting[co] = true @@ -191,11 +181,16 @@ end -- Run fibers until all but main have terminated: return nil. -- Or until configured idle() callback returns x ~= nil: return x. function fiber.run() - -- A fiber calling run() is not also doing other useful work. Tell yield() - -- that we're waiting. Otherwise it would keep seeing that our caller is - -- ready and return to us, instead of realizing that all coroutines are - -- waiting and call idle(). - set_waiting() + -- A fiber calling run() is not also doing other useful work. Remove the + -- calling fiber from the ready list. Otherwise yield() would keep seeing + -- that our caller is ready and return to us, instead of realizing that + -- all coroutines are waiting and call idle(). But don't say we're + -- waiting, either, because then when all other fibers have terminated + -- we'd call idle() forever waiting for something to make us ready again. + local i = table.find(ready, fiber.running()) + if i then + table.remove(ready, i) + end local others, idle_done repeat debug('%s calling fiber.run() calling yield()', fiber.get_name()) @@ -204,9 +199,10 @@ function fiber.run() tostring(others), tostring(idle_done)) until (not others) debug('%s fiber.run() done', fiber.get_name()) - fiber.wake(fiber.running()) + -- For whatever it's worth, put our own fiber back in the ready list. + table.insert(ready, fiber.running()) -- Once there are no more waiting fibers, and the only ready fiber is - -- main, return to main. All previously-launched fibers are done. Possibly + -- us, return to caller. All previously-launched fibers are done. Possibly -- the chunk is done, or the chunk may decide to launch a new batch of -- fibers. return idle_done diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 60e8266a76..77f3a3e116 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -198,10 +198,10 @@ end local function cleanup(message) -- we're done: clean up all pending coroutines for i, waitfor in pairs(leap._pending) do - waitfor:exception(message) + waitfor:close() end for i, waitfor in pairs(leap._waitfors) do - waitfor:exception(message) + waitfor:close() end end @@ -407,6 +407,11 @@ function leap.WaitFor:process(item) self._queue:Enqueue(item) end +-- called by cleanup() at end +function leap.WaitFor:close() + self._queue:close() +end + -- called by leap.process() when get_event_next() raises an error function leap.WaitFor:exception(message) print_warning(self.name .. ' error: ' .. message) diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 1dd081fb98..d1beed84ef 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -361,8 +361,8 @@ namespace tut "fiber.launch('requester(a)', requester, 'a')\n" "-- requester(a)\n" "fiber.launch('requester(b)', requester, 'b')\n" + "fiber.run()\n" "-- fiber.print_all()\n" - "-- fiber.run()\n" ); LLSD requests; -- cgit v1.2.3 From 2dc003779443db99f46b3db6d17a1954f7b141dd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Sat, 23 Mar 2024 17:43:07 +0900 Subject: Make leap.request() work even from Lua's main thread. Recast fiber.yield() as internal function scheduler(). Move fiber.run() after it so it can call scheduler() as a local function. Add new fiber.yield() that also calls scheduler(); the added value of this new fiber.yield() over plain scheduler() is that if scheduler() returns before the caller is ready (because the configured set_idle() function returned non-nil), it produces an explicit error rather than returning to its caller. So the caller can assume that when fiber.yield() returns normally, the calling fiber is ready. This allows any fiber, including the main thread, to call fiber.yield() or fiber.wait(). This supports using leap.request(), which posts a request and then waits on a WaitForReqid, which calls ErrorQueue:Dequeue(), which calls fiber.wait(). WaitQueue:_wake_waiters() must call fiber.status() instead of coroutine.status() so it understands the special token 'main'. Add a new llluamanager_test.cpp test to exercise calling leap.request() from Lua's main thread. --- indra/newview/scripts/lua/WaitQueue.lua | 2 +- indra/newview/scripts/lua/fiber.lua | 106 ++++++++++++++++++++---------- indra/newview/tests/llluamanager_test.cpp | 43 ++++++++++-- 3 files changed, 108 insertions(+), 43 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index f69baff09b..a34dbef4d7 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -43,7 +43,7 @@ function WaitQueue:_wake_waiters() -- more-or-less round robin fairness. But skip any coroutines that -- have gone dead in the meantime. local waiter = table.remove(self._waiters, 1) - while waiter and coroutine.status(waiter) ~= "suspended" do + while waiter and fiber.status(waiter) == "dead" do waiter = table.remove(self._waiters, 1) end -- do we still have at least one waiting coroutine? diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua index 8ed99f12b7..7dc67f510c 100644 --- a/indra/newview/scripts/lua/fiber.lua +++ b/indra/newview/scripts/lua/fiber.lua @@ -178,36 +178,6 @@ function fiber.wake(co) -- but don't yet resume it: that happens next time we reach yield() end --- Run fibers until all but main have terminated: return nil. --- Or until configured idle() callback returns x ~= nil: return x. -function fiber.run() - -- A fiber calling run() is not also doing other useful work. Remove the - -- calling fiber from the ready list. Otherwise yield() would keep seeing - -- that our caller is ready and return to us, instead of realizing that - -- all coroutines are waiting and call idle(). But don't say we're - -- waiting, either, because then when all other fibers have terminated - -- we'd call idle() forever waiting for something to make us ready again. - local i = table.find(ready, fiber.running()) - if i then - table.remove(ready, i) - end - local others, idle_done - repeat - debug('%s calling fiber.run() calling yield()', fiber.get_name()) - others, idle_done = fiber.yield() - debug("%s fiber.run()'s yield() returned %s, %s", fiber.get_name(), - tostring(others), tostring(idle_done)) - until (not others) - debug('%s fiber.run() done', fiber.get_name()) - -- For whatever it's worth, put our own fiber back in the ready list. - table.insert(ready, fiber.running()) - -- Once there are no more waiting fibers, and the only ready fiber is - -- us, return to caller. All previously-launched fibers are done. Possibly - -- the chunk is done, or the chunk may decide to launch a new batch of - -- fibers. - return idle_done -end - -- pop and return the next not-dead fiber in the ready list, or nil if none remain local function live_ready_iter() -- don't write @@ -237,16 +207,24 @@ local function prune_waiting() end end --- Give other ready fibers a chance to run, leaving this one ready, returning --- after a cycle. Returns: --- * true, nil if there remain other live fibers, whether ready or waiting +-- Run other ready fibers, leaving this one ready, returning after a cycle. +-- Returns: +-- * true, nil if there remain other live fibers, whether ready or waiting, +-- but it's our turn to run -- * false, nil if this is the only remaining fiber --- * nil, x if configured idle() callback returned non-nil x -function fiber.yield() +-- * nil, x if configured idle() callback returns non-nil x +local function scheduler() + -- scheduler() is asymmetric because Lua distinguishes the main thread + -- from other coroutines. The main thread can't yield; it can only resume + -- other coroutines. So although an arbitrary coroutine could resume still + -- other arbitrary coroutines, it could NOT resume the main thread because + -- the main thread can't yield. Therefore, scheduler() delegates its real + -- processing to the main thread. If called from a coroutine, pass control + -- back to the main thread. if coroutine.running() then -- seize the opportunity to make sure the viewer isn't shutting down -- check_stop() - -- this is a real coroutine, yield normally to main or whoever + -- this is a real coroutine, yield normally to main thread coroutine.yield() -- main certainly still exists return true @@ -294,4 +272,60 @@ function fiber.yield() until false end +-- Let other fibers run. This is useful in either of two cases: +-- * fiber.wait() calls this to run other fibers while this one is waiting. +-- fiber.yield() (and therefore fiber.wait()) works from the main thread as +-- well as from explicitly-launched fibers, without the caller having to +-- care. +-- * A long-running fiber that doesn't often call fiber.wait() should sprinkle +-- in fiber.yield() calls to interleave processing on other fibers. +function fiber.yield() + -- The difference between this and fiber.run() is that fiber.yield() + -- assumes its caller has work to do. yield() returns to its caller as + -- soon as scheduler() pops this fiber from the ready list. fiber.run() + -- continues looping until all other fibers have terminated, or the + -- set_idle() callback tells it to stop. + local others, idle_done = scheduler() + -- scheduler() returns either if we're ready, or if idle_done ~= nil. + if idle_done ~= nil then + -- Returning normally from yield() means the caller can carry on with + -- its pending work. But in this case scheduler() returned because the + -- configured set_idle() function interrupted it -- not because we're + -- actually ready. Don't return normally. + error('fiber.set_idle() interrupted yield() with: ' .. tostring(idle_done)) + end + -- We're ready! Just return to caller. In this situation we don't care + -- whether there are other ready fibers. +end + +-- Run fibers until all but main have terminated: return nil. +-- Or until configured idle() callback returns x ~= nil: return x. +function fiber.run() + -- A fiber calling run() is not also doing other useful work. Remove the + -- calling fiber from the ready list. Otherwise yield() would keep seeing + -- that our caller is ready and return to us, instead of realizing that + -- all coroutines are waiting and call idle(). But don't say we're + -- waiting, either, because then when all other fibers have terminated + -- we'd call idle() forever waiting for something to make us ready again. + local i = table.find(ready, fiber.running()) + if i then + table.remove(ready, i) + end + local others, idle_done + repeat + debug('%s calling fiber.run() calling scheduler()', fiber.get_name()) + others, idle_done = scheduler() + debug("%s fiber.run()'s scheduler() returned %s, %s", fiber.get_name(), + tostring(others), tostring(idle_done)) + until (not others) + debug('%s fiber.run() done', fiber.get_name()) + -- For whatever it's worth, put our own fiber back in the ready list. + table.insert(ready, fiber.running()) + -- Once there are no more waiting fibers, and the only ready fiber is + -- us, return to caller. All previously-launched fibers are done. Possibly + -- the chunk is done, or the chunk may decide to launch a new batch of + -- fibers. + return idle_done +end + return fiber diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index d1beed84ef..0fd91c1354 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -307,9 +307,43 @@ namespace tut template<> template<> void object::test<5>() { - set_test_name("test leap.lua"); + set_test_name("leap.request() from main thread"); const std::string lua( - "-- test leap.lua\n" + "-- leap.request() from main thread\n" + "\n" + "leap = require 'leap'\n" + "\n" + "return {\n" + " a=leap.request('echo', {data='a'}).data,\n" + " b=leap.request('echo', {data='b'}).data\n" + "}\n" + ); + + LLEventStream pump("echo", false); + LLTempBoundListener conn{ + pump.listen( + "test<5>()", + listener([](const LLSD& data) + { + LL_DEBUGS("Lua") << "echo pump got: " << data << LL_ENDL; + LLEventPumps::instance().post( + data["reply"], + llsd::map("reqid", data["reqid"], "data", data["data"])); + })) + }; + + LuaState L; + auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + ensure_equals("Lua script didn't return item", count, 1); + ensure_equals("echo failed", result, llsd::map("a", "a", "b", "b")); + } + + template<> template<> + void object::test<6>() + { + set_test_name("interleave leap.request() responses"); + const std::string lua( + "-- interleave leap.request() responses\n" "\n" "fiber = require('fiber')\n" "leap = require('leap')\n" @@ -359,16 +393,13 @@ namespace tut "fiber.launch('catchall', drain, catchall)\n" "fiber.launch('catch_special', drain, catch_special)\n" "fiber.launch('requester(a)', requester, 'a')\n" - "-- requester(a)\n" "fiber.launch('requester(b)', requester, 'b')\n" - "fiber.run()\n" - "-- fiber.print_all()\n" ); LLSD requests; LLEventStream pump("testpump", false); LLTempBoundListener conn{ - pump.listen("test<5>()", + pump.listen("test<6>()", listener([&requests](const LLSD& data) { LL_DEBUGS("Lua") << "testpump got: " << data << LL_ENDL; -- cgit v1.2.3 From 93b30f960ea327fe3c36deed72a8075ce0d13f19 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Sun, 24 Mar 2024 02:16:55 +0900 Subject: Introduce LLStreamListener: bundle LLEventStream+LLTempBoundListener. This is a very common pattern, especially in test code, but elsewhere in the viewer too. Use it in llluamanager_test.cpp. --- indra/newview/tests/llluamanager_test.cpp | 53 ++++++++++++------------------- 1 file changed, 21 insertions(+), 32 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 0fd91c1354..872d7827fe 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -105,10 +105,8 @@ namespace tut void from_lua(const std::string& desc, const std::string_view& construct, const LLSD& expect) { LLSD fromlua; - LLEventStream replypump("testpump"); - LLTempBoundListener conn( - replypump.listen("llluamanager_test", - listener([&fromlua](const LLSD& data){ fromlua = data; }))); + LLStreamListener pump("testpump", + listener([&fromlua](const LLSD& data){ fromlua = data; })); const std::string lua(stringize( "data = ", construct, "\n" "post_on('testpump', data)\n" @@ -137,11 +135,9 @@ namespace tut { set_test_name("test post_on(), get_event_pumps(), get_event_next()"); StringVec posts; - LLEventStream replypump("testpump"); - LLTempBoundListener conn( - replypump.listen("test<3>", - listener([&posts](const LLSD& data) - { posts.push_back(data.asString()); }))); + LLStreamListener pump("testpump", + listener([&posts](const LLSD& data) + { posts.push_back(data.asString()); })); const std::string lua( "-- test post_on,get_event_pumps,get_event_next\n" "post_on('testpump', 'entry')\n" @@ -180,7 +176,7 @@ namespace tut void round_trip(const std::string& desc, const LLSD& send, const LLSD& expect) { - LLEventMailDrop replypump("testpump"); + LLEventMailDrop testpump("testpump"); const std::string lua( "-- test LLSD round trip\n" "replypump, cmdpump = get_event_pumps()\n" @@ -194,7 +190,7 @@ namespace tut // reached the get_event_next() call, which suspends the calling C++ // coroutine (including the Lua code running on it) until we post // something to that reply pump. - auto luapump{ llcoro::suspendUntilEventOn(replypump).asString() }; + auto luapump{ llcoro::suspendUntilEventOn(testpump).asString() }; LLEventPumps::instance().post(luapump, send); // The C++ coroutine running the Lua script is now ready to run. Run // it so it will echo the LLSD back to us. @@ -319,18 +315,13 @@ namespace tut "}\n" ); - LLEventStream pump("echo", false); - LLTempBoundListener conn{ - pump.listen( - "test<5>()", - listener([](const LLSD& data) - { - LL_DEBUGS("Lua") << "echo pump got: " << data << LL_ENDL; - LLEventPumps::instance().post( - data["reply"], - llsd::map("reqid", data["reqid"], "data", data["data"])); - })) - }; + LLStreamListener pump( + "echo", + listener([](const LLSD& data) + { + LL_DEBUGS("Lua") << "echo pump got: " << data << LL_ENDL; + sendReply(data, data); + })); LuaState L; auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); @@ -397,15 +388,13 @@ namespace tut ); LLSD requests; - LLEventStream pump("testpump", false); - LLTempBoundListener conn{ - pump.listen("test<6>()", - listener([&requests](const LLSD& data) - { - LL_DEBUGS("Lua") << "testpump got: " << data << LL_ENDL; - requests.append(data); - })) - }; + LLStreamListener pump( + "testpump", + listener([&requests](const LLSD& data) + { + LL_DEBUGS("Lua") << "testpump got: " << data << LL_ENDL; + requests.append(data); + })); LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); -- cgit v1.2.3 From 41e14d35ae2dfa644716cb195545d59c468538c5 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 25 Mar 2024 15:06:11 +0200 Subject: Add keystroke event support and allow adding text lines to the line editor --- indra/newview/scripts/lua/luafloater_demo.xml | 13 ++++++++++++- indra/newview/scripts/lua/test_luafloater_demo.lua | 4 ++-- indra/newview/scripts/lua/test_luafloater_gesture_list.lua | 3 +-- indra/newview/scripts/lua/util.lua | 10 ---------- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/luafloater_demo.xml b/indra/newview/scripts/lua/luafloater_demo.xml index 069f229128..b2273d7718 100644 --- a/indra/newview/scripts/lua/luafloater_demo.xml +++ b/indra/newview/scripts/lua/luafloater_demo.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="150" + height="300" layout="topleft" name="lua_demo" title="LUA" @@ -79,4 +79,15 @@ text_color="white" left_delta="15" name="time_lbl"/> + <text_editor + follows="top|left" + font="SansSerif" + height="140" + left="5" + enabled="false" + name="events_editor" + top_pad="15" + word_wrap="true" + max_length="65536" + width="310"/> </floater> diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index b81259c060..22ed7d7b3a 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -2,7 +2,6 @@ XML_FILE_PATH = "luafloater_demo.xml" leap = require 'leap' coro = require 'coro' -util = require 'util' --event pump for sending actions to the floater COMMAND_PUMP_NAME = "" @@ -15,7 +14,7 @@ end) leap.process() local function _event(event_name) - if not util.contains(event_list, event_name) then + if not table.find(event_list, event_name) then print_warning("Incorrect event name: " .. event_name) end return event_name @@ -31,6 +30,7 @@ function getCurrentTime() end function handleEvents(event_data) + post({action="add_text", ctrl_name="events_editor", value = event_data}) if event_data.event == _event("commit") then if event_data.ctrl_name == "disable_ctrl" then post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index b46e36b4d9..b1ff129d85 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -2,7 +2,6 @@ XML_FILE_PATH = "luafloater_gesture_list.xml" leap = require 'leap' coro = require 'coro' -util = require 'util' LLGesture = require 'LLGesture' --event pump for sending actions to the floater @@ -16,7 +15,7 @@ end) leap.process() local function _event(event_name) - if not util.contains(event_list, event_name) then + if not table.find(event_list, event_name) then print_warning("Incorrect event name: " .. event_name) end return event_name diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index 5d6042dfe5..e3af633ea7 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -36,14 +36,4 @@ function util.equal(t1, t2) return util.empty(temp) end --- check if array-like table contains certain value -function util.contains(t, v) - for _, value in ipairs(t) do - if value == v then - return true - end - end - return false -end - return util -- cgit v1.2.3 From 6cedaecad9c4830aa29068b90611b8b9da301ac9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 25 Mar 2024 20:41:33 +0200 Subject: Update test scripts to call leap.request() from main thread --- indra/newview/scripts/lua/test_luafloater_demo.lua | 16 ++-------------- .../newview/scripts/lua/test_luafloater_gesture_list.lua | 14 ++------------ 2 files changed, 4 insertions(+), 26 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index 22ed7d7b3a..f2cf34206e 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -6,12 +6,7 @@ coro = require 'coro' --event pump for sending actions to the floater COMMAND_PUMP_NAME = "" --table of floater UI events -event_list={} -coro.launch(function () - event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] - leap.done() -end) -leap.process() +event_list=leap.request("LLFloaterReg", {op="getFloaterEvents"}).events local function _event(event_name) if not table.find(event_list, event_name) then @@ -53,12 +48,7 @@ end local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --sign for additional events for defined control {<control_name>= {action1, action2, ...}} key.extra_events={show_time_lbl = {_event("right_mouse_down"), _event("double_click")}} -coro.launch(function () - --script received event pump name, after floater was built - COMMAND_PUMP_NAME = leap.request("LLFloaterReg", key)["command_name"] - leap.done() -end) -leap.process() +COMMAND_PUMP_NAME = leap.request("LLFloaterReg", key).command_name catch_events = leap.WaitFor:new(-1, "all_events") function catch_events:filter(pump, data) @@ -74,5 +64,3 @@ function process_events(waitfor) end coro.launch(process_events, catch_events) -leap.process() -print_warning("End of the script") diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index b1ff129d85..049ba757d3 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -7,12 +7,7 @@ LLGesture = require 'LLGesture' --event pump for sending actions to the floater COMMAND_PUMP_NAME = "" --table of floater UI events -event_list={} -coro.launch(function () - event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"})["events"] - leap.done() -end) -leap.process() +event_list=leap.request("LLFloaterReg", {op="getFloaterEvents"}).events local function _event(event_name) if not table.find(event_list, event_name) then @@ -50,11 +45,7 @@ end local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --receive additional events for defined control {<control_name>= {action1, action2, ...}} key.extra_events={gesture_list = {_event("double_click")}} -coro.launch(function () - handleEvents(leap.request("LLFloaterReg", key)) - leap.done() -end) -leap.process() +handleEvents(leap.request("LLFloaterReg", key)) catch_events = leap.WaitFor:new(-1, "all_events") function catch_events:filter(pump, data) @@ -70,4 +61,3 @@ function process_events(waitfor) end coro.launch(process_events, catch_events) -leap.process() -- cgit v1.2.3 From ac4fa418e3a7402f9d9122c726d2fbfc4b8767b2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 25 Mar 2024 16:29:17 -0400 Subject: Add LL. prefix to viewer entry points, fix existing references. --- indra/newview/scripts/lua/WaitQueue.lua | 2 +- indra/newview/scripts/lua/leap.lua | 10 ++++----- indra/newview/scripts/lua/test_LLGesture.lua | 2 +- indra/newview/scripts/lua/test_luafloater_demo.lua | 6 +++--- .../scripts/lua/test_luafloater_gesture_list.lua | 2 +- indra/newview/tests/llluamanager_test.cpp | 24 +++++++++++----------- 6 files changed, 23 insertions(+), 23 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index a34dbef4d7..1fbcc50847 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -5,7 +5,7 @@ local fiber = require('fiber') local Queue = require('Queue') --- local debug = print_debug +-- local debug = LL.print_debug local function debug(...) end local WaitQueue = Queue:new() diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 77f3a3e116..a60819d493 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -51,7 +51,7 @@ local leap = {} -- _command: string name of command LLEventPump. post_to(_command, ...) -- engages LLLeapListener operations such as listening on a specified other -- LLEventPump, etc. -leap._reply, leap._command = get_event_pumps() +leap._reply, leap._command = LL.get_event_pumps() -- Dict of features added to the LEAP protocol since baseline implementation. -- Before engaging a new feature that might break an older viewer, we can -- check for the presence of that feature key. This table is solely about the @@ -112,7 +112,7 @@ function leap.send(pump, data, reqid) end end debug('leap.send(%s, %s) calling post_on()', pump, data) - post_on(pump, data) + LL.post_on(pump, data) end -- common setup code shared by request() and generate() @@ -215,7 +215,7 @@ local function unsolicited(pump, data) return end end - print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', pump, data)) + LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', pump, data)) end -- Route incoming (pump, data) event to the appropriate waiting coroutine. @@ -244,7 +244,7 @@ fiber.set_idle(function () return 'done' end debug('leap.idle() calling get_event_next()') - local ok, pump, data = pcall(get_event_next) + local ok, pump, data = pcall(LL.get_event_next) debug('leap.idle() got %s: %s, %s', ok, pump, data) -- ok false means get_event_next() raised a Lua error, pump is message if not ok then @@ -414,7 +414,7 @@ end -- called by leap.process() when get_event_next() raises an error function leap.WaitFor:exception(message) - print_warning(self.name .. ' error: ' .. message) + LL.print_warning(self.name .. ' error: ' .. message) self._queue:Error(message) end diff --git a/indra/newview/scripts/lua/test_LLGesture.lua b/indra/newview/scripts/lua/test_LLGesture.lua index 5c0db6c063..5897a0e3cb 100644 --- a/indra/newview/scripts/lua/test_LLGesture.lua +++ b/indra/newview/scripts/lua/test_LLGesture.lua @@ -22,7 +22,7 @@ coro.launch(function() print(name) LLGesture.startGesture(uuid) repeat - sleep(1) + LL.sleep(1) until not LLGesture.isGesturePlaying(uuid) end print('Done.') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index b81259c060..4e071e4abe 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -16,7 +16,7 @@ leap.process() local function _event(event_name) if not util.contains(event_list, event_name) then - print_warning("Incorrect event name: " .. event_name) + LL.print_warning("Incorrect event name: " .. event_name) end return event_name end @@ -45,7 +45,7 @@ function handleEvents(event_data) post({action="set_value", ctrl_name="time_lbl", value= getCurrentTime()}) end elseif event_data.event == _event("floater_close") then - print_warning("Floater was closed") + LL.print_warning("Floater was closed") leap.done() end end @@ -75,4 +75,4 @@ end coro.launch(process_events, catch_events) leap.process() -print_warning("End of the script") +LL.print_warning("End of the script") diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index b46e36b4d9..9c718c353b 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -17,7 +17,7 @@ leap.process() local function _event(event_name) if not util.contains(event_list, event_name) then - print_warning("Incorrect event name: " .. event_name) + LL.print_warning("Incorrect event name: " .. event_name) end return event_name end diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 872d7827fe..e10dedcf53 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -109,7 +109,7 @@ namespace tut listener([&fromlua](const LLSD& data){ fromlua = data; })); const std::string lua(stringize( "data = ", construct, "\n" - "post_on('testpump', data)\n" + "LL.post_on('testpump', data)\n" )); LuaState L; auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); @@ -140,14 +140,14 @@ namespace tut { posts.push_back(data.asString()); })); const std::string lua( "-- test post_on,get_event_pumps,get_event_next\n" - "post_on('testpump', 'entry')\n" - "post_on('testpump', 'get_event_pumps()')\n" - "replypump, cmdpump = get_event_pumps()\n" - "post_on('testpump', replypump)\n" - "post_on('testpump', 'get_event_next()')\n" - "pump, data = get_event_next()\n" - "post_on('testpump', data)\n" - "post_on('testpump', 'exit')\n" + "LL.post_on('testpump', 'entry')\n" + "LL.post_on('testpump', 'get_event_pumps()')\n" + "replypump, cmdpump = LL.get_event_pumps()\n" + "LL.post_on('testpump', replypump)\n" + "LL.post_on('testpump', 'get_event_next()')\n" + "pump, data = LL.get_event_next()\n" + "LL.post_on('testpump', data)\n" + "LL.post_on('testpump', 'exit')\n" ); LuaState L; // It's important to let the startScriptLine() coroutine run @@ -179,9 +179,9 @@ namespace tut LLEventMailDrop testpump("testpump"); const std::string lua( "-- test LLSD round trip\n" - "replypump, cmdpump = get_event_pumps()\n" - "post_on('testpump', replypump)\n" - "pump, data = get_event_next()\n" + "replypump, cmdpump = LL.get_event_pumps()\n" + "LL.post_on('testpump', replypump)\n" + "pump, data = LL.get_event_next()\n" "return data\n" ); LuaState L; -- cgit v1.2.3 From 98e6356aed0c757f16267cc2ae921f9c90a249fe Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 25 Mar 2024 16:57:28 -0400 Subject: Add LL.check_stop() entry point and call it in fiber scheduler(). fiber.lua's scheduler() is greedy, in the sense that it wants to run every ready Lua fiber before retrieving the next incoming event from the viewer (and possibly blocking for some real time before it becomes available). But check for viewer shutdown before resuming any suspended-but-ready Lua fiber. --- indra/newview/scripts/lua/fiber.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua index 7dc67f510c..aebf27357f 100644 --- a/indra/newview/scripts/lua/fiber.lua +++ b/indra/newview/scripts/lua/fiber.lua @@ -222,8 +222,6 @@ local function scheduler() -- processing to the main thread. If called from a coroutine, pass control -- back to the main thread. if coroutine.running() then - -- seize the opportunity to make sure the viewer isn't shutting down --- check_stop() -- this is a real coroutine, yield normally to main thread coroutine.yield() -- main certainly still exists @@ -240,7 +238,7 @@ local function scheduler() repeat for co in live_ready_iter do -- seize the opportunity to make sure the viewer isn't shutting down --- check_stop() + LL.check_stop() -- before we re-append co, is it the only remaining entry? others = next(ready) -- co is live, re-append it to the ready list -- cgit v1.2.3 From 18c4d8732aae9a8bf10d6a84bc37261b242d16c6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 25 Mar 2024 22:53:47 +0200 Subject: viewer-private#216 Viewer fails to rename vivox logs --- indra/newview/llvoicevivox.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 3725510b6a..bda8c35702 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -989,6 +989,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old"); if (gDirUtilp->fileExists(new_log)) { + LLFile::remove(old_log, ENOENT); LLFile::rename(new_log, old_log); } -- cgit v1.2.3 From eeb43b604ccb3348907bd06c0135e7824879fe57 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 25 Mar 2024 22:59:08 +0200 Subject: viewer-private#217 Rotate cef log file --- indra/newview/llviewermedia.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 02108e861a..59701cc5b3 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1723,7 +1723,13 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ std::string user_data_path_cache = gDirUtilp->getCacheDir(false); user_data_path_cache += gDirUtilp->getDirDelimiter(); - std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef_log.txt"); + std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.txt"); + std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); + if (gDirUtilp->fileExists(user_data_path_cef_log)) + { + LLFile::remove(user_data_path_cef_old, ENOENT); + LLFile::rename(user_data_path_cef_log, user_data_path_cef_old); + } // See if the plugin executable exists llstat s; -- cgit v1.2.3 From 5b04ae7812e6cb0d0c9895aec6db6a206d4e09e8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 25 Mar 2024 17:35:28 -0400 Subject: util.lua claims functions are in alpha order - make it so. Also streamline util.contains(), given table.find(). --- indra/newview/scripts/lua/util.lua | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index 5d6042dfe5..a2191288f6 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -2,9 +2,9 @@ local util = {} --- cheap test whether table t is empty -function util.empty(t) - return not next(t) +-- check if array-like table contains certain value +function util.contains(t, v) + return table.find(t, v) ~= nil end -- reliable count of the number of entries in table t @@ -17,6 +17,11 @@ function util.count(t) return count end +-- cheap test whether table t is empty +function util.empty(t) + return not next(t) +end + -- recursive table equality function util.equal(t1, t2) if not (type(t1) == 'table' and type(t2) == 'table') then @@ -36,14 +41,4 @@ function util.equal(t1, t2) return util.empty(temp) end --- check if array-like table contains certain value -function util.contains(t, v) - for _, value in ipairs(t) do - if value == v then - return true - end - end - return false -end - return util -- cgit v1.2.3 From 24a7842b9b08dc5cfb89fe36e5ebcd9c2598fa44 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 26 Mar 2024 19:12:13 +0200 Subject: update scripts to use fiber.launch() --- indra/newview/scripts/lua/test_luafloater_demo.lua | 3 ++- indra/newview/scripts/lua/test_luafloater_gesture_list.lua | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index f2cf34206e..be189bc146 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -2,6 +2,7 @@ XML_FILE_PATH = "luafloater_demo.xml" leap = require 'leap' coro = require 'coro' +fiber = require 'fiber' --event pump for sending actions to the floater COMMAND_PUMP_NAME = "" @@ -63,4 +64,4 @@ function process_events(waitfor) end end -coro.launch(process_events, catch_events) +fiber.launch("catch_events", process_events, catch_events) diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index 049ba757d3..7e2139468f 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -2,6 +2,7 @@ XML_FILE_PATH = "luafloater_gesture_list.xml" leap = require 'leap' coro = require 'coro' +fiber = require 'fiber' LLGesture = require 'LLGesture' --event pump for sending actions to the floater @@ -60,4 +61,4 @@ function process_events(waitfor) end end -coro.launch(process_events, catch_events) +fiber.launch("catch_events", process_events, catch_events) -- cgit v1.2.3 From aa892d2c35d1f03ad49aceba0f89f0ab3d40c315 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 25 Mar 2024 15:50:47 +0200 Subject: viewer#1016 Incorrect behavior of Physics Shapes rendering --- indra/newview/llphysicsshapebuilderutil.cpp | 53 +++++++++++++++++++++++------ indra/newview/llphysicsshapebuilderutil.h | 2 ++ 2 files changed, 45 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp index 9603ee6329..a79cc984c1 100644 --- a/indra/newview/llphysicsshapebuilderutil.cpp +++ b/indra/newview/llphysicsshapebuilderutil.cpp @@ -28,6 +28,26 @@ #include "llphysicsshapebuilderutil.h" +#include "llmeshrepository.h" + +bool LLPhysicsVolumeParams::hasDecomposition() const + { + if (!isMeshSculpt()) + { + return false; + } + + LLUUID mesh_id = getSculptID(); + if (mesh_id.isNull()) + { + return false; + } + + LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); + + return decomp != NULL; +} + /* static */ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut) { @@ -200,19 +220,32 @@ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumePara { specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; } - else if (volume_params.isMeshSculpt() && - // Check overall dimensions, not individual triangles. - (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE || - scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE || - scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE - ) ) + else if (volume_params.isMeshSculpt()) { - // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't. - specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; + // Check overall dimensions, not individual triangles. + if (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE + || scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE + || scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE + ) + { + if (volume_params.hasDecomposition()) + { + specOut.mType = PhysicsShapeSpecification::USER_MESH; + } + else + { + // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't. + specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; + } + } + else + { + specOut.mType = PhysicsShapeSpecification::USER_MESH; + } } - else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy) + else if ( volume_params.isSculpt() ) { - specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT; + specOut.mType = PhysicsShapeSpecification::SCULPT; } else // Resort to mesh { diff --git a/indra/newview/llphysicsshapebuilderutil.h b/indra/newview/llphysicsshapebuilderutil.h index b3b100296f..24e68fcf77 100644 --- a/indra/newview/llphysicsshapebuilderutil.h +++ b/indra/newview/llphysicsshapebuilderutil.h @@ -78,6 +78,8 @@ public: bool shouldForceConvex() const { return mForceConvex; } + bool hasDecomposition() const; + private: bool mForceConvex; }; -- cgit v1.2.3 From f25f51a20a7bcefcf51de5e71f827c74c659571a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 27 Mar 2024 00:28:04 +0200 Subject: viewer-private#131 landmark panel closes after a rename if destination was changed --- indra/newview/llfloatercreatelandmark.cpp | 4 ++-- indra/newview/llfloatercreatelandmark.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp index b82d8a29ba..7dc3e4afe3 100644 --- a/indra/newview/llfloatercreatelandmark.cpp +++ b/indra/newview/llfloatercreatelandmark.cpp @@ -389,6 +389,7 @@ void LLFloaterCreateLandmark::setItem(const uuid_set_t& items) { mItem = item; mAssetID = mItem->getAssetUUID(); + mParentID = mItem->getParentUUID(); setVisibleAndFrontmost(true); break; } @@ -418,8 +419,7 @@ void LLFloaterCreateLandmark::updateItem(const uuid_set_t& items, U32 mask) closeFloater(); } - LLUUID folder_id = mFolderCombo->getValue().asUUID(); - if (folder_id != mItem->getParentUUID()) + if (mParentID != mItem->getParentUUID()) { // user moved landmark in inventory, // assume that we are done all other changes should already be commited diff --git a/indra/newview/llfloatercreatelandmark.h b/indra/newview/llfloatercreatelandmark.h index d84f5ae1fc..8a1d5ae099 100644 --- a/indra/newview/llfloatercreatelandmark.h +++ b/indra/newview/llfloatercreatelandmark.h @@ -69,6 +69,7 @@ private: LLTextEditor* mNotesEditor; LLUUID mLandmarksID; LLUUID mAssetID; + LLUUID mParentID; LLLandmarksInventoryObserver* mInventoryObserver; LLPointer<LLInventoryItem> mItem; -- cgit v1.2.3 From cc68803f24d231b89061d855f7bbfe99b99740b9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 27 Mar 2024 20:13:04 +0200 Subject: viewer#1061 Altitudes are invisible in region's environment --- indra/newview/skins/default/xui/en/panel_region_environment.xml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/panel_region_environment.xml b/indra/newview/skins/default/xui/en/panel_region_environment.xml index 0b3639f779..67eb8f2ca9 100644 --- a/indra/newview/skins/default/xui/en/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/en/panel_region_environment.xml @@ -264,8 +264,7 @@ top_pad="1" halign="right" name="txt_alt1"> - Sky [INDEX] - [ALTITUDE]m + Sky [INDEX]
[ALTITUDE]m </text> <line_editor follows="left|top" @@ -310,8 +309,7 @@ top_pad="1" halign="right" name="txt_alt2"> - Sky [INDEX] - [ALTITUDE]m + Sky [INDEX]
[ALTITUDE]m </text> <line_editor follows="left|top" @@ -356,8 +354,7 @@ top_pad="1" halign="right" name="txt_alt3"> - Sky [INDEX] - [ALTITUDE]m + Sky [INDEX]
[ALTITUDE]m </text> <line_editor follows="left|top" -- cgit v1.2.3 From c618758c7c91917905b1075e29944ef70e7e9b33 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Mar 2024 15:53:48 -0400 Subject: Run loaded `require()` module on Lua's main thread. The problem with running a `require()` module on a Lua coroutine is that it prohibits calling `leap.request()` at module load time. When a coroutine calls `leap.request()`, it must yield back to Lua's main thread -- but a `require()` module is forbidden from yielding. Running on Lua's main thread means that (after potentially giving time slices to other ready coroutines) `fiber.lua` will request the response event from the viewer, and continue processing the loaded module without having to yield. --- indra/newview/llluamanager.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c65f062fd7..aed6aee239 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -508,12 +508,14 @@ void LLRequireResolver::runModule(const std::string& desc, const std::string& co // Module needs to run in a new thread, isolated from the rest. // Note: we create ML on main thread so that it doesn't inherit environment of L. lua_State *GL = lua_mainthread(L); - lua_State *ML = lua_newthread(GL); +// lua_State *ML = lua_newthread(GL); + // Try loading modules on Lua's main thread instead. + lua_State *ML = GL; // lua_newthread() pushed the new thread object on GL's stack. Move to L's. - lua_xmove(GL, L, 1); +// lua_xmove(GL, L, 1); // new thread needs to have the globals sandboxed - luaL_sandboxthread(ML); +// luaL_sandboxthread(ML); { // If loadstring() returns (! LUA_OK) then there's an error message on @@ -523,7 +525,9 @@ void LLRequireResolver::runModule(const std::string& desc, const std::string& co { // luau uses Lua 5.3's version of lua_resume(): // run the coroutine on ML, "from" L, passing no arguments. - int status = lua_resume(ML, L, 0); +// int status = lua_resume(ML, L, 0); + // we expect one return value + int status = lua_pcall(ML, 0, 1, 0); if (status == LUA_OK) { @@ -545,9 +549,12 @@ void LLRequireResolver::runModule(const std::string& desc, const std::string& co } // There's now a return value (string error message or module) on top of ML. // Move return value to L's stack. - lua_xmove(ML, L, 1); + if (ML != L) + { + lua_xmove(ML, L, 1); + } // remove ML from L's stack - lua_remove(L, -2); +// lua_remove(L, -2); // // DON'T call lua_close(ML)! Since ML is only a thread of L, corrupts L too! // lua_close(ML); } -- cgit v1.2.3 From 58d5e288e0bfaa9819b68b376767a8a39a97fef8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Mar 2024 16:20:36 -0400 Subject: poetry --- indra/newview/scripts/lua/Queue.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/Queue.lua b/indra/newview/scripts/lua/Queue.lua index b0a5a87f87..5ab2a8a72c 100644 --- a/indra/newview/scripts/lua/Queue.lua +++ b/indra/newview/scripts/lua/Queue.lua @@ -1,6 +1,12 @@ -- from https://create.roblox.com/docs/luau/queues#implementing-queues, -- amended per https://www.lua.org/pil/16.1.html +-- While coding some scripting in Lua +-- I found that I needed a queua +-- I thought of linked list +-- But had to resist +-- For fear it might be too obscua. + local Queue = {} function Queue:new() -- cgit v1.2.3 From af38e606865c2ed49a13bd6bd91d9604997798c8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 27 Mar 2024 16:38:45 -0400 Subject: Enhance Lua debugging output. Don't use "debug" as the name of a function to conditionally write debug messages: "debug" is a Luau built-in library, and assigning that name locally would shadow the builtin. Use "dbg" instead. Recast fiber.print_all() as fiber.format_all() that returns a string; then print_all() is simply print(format_all()). This refactoring allows us to use dbg(format_all()) as well. Add a couple new dbg() messages at fiber state changes. --- indra/newview/scripts/lua/ErrorQueue.lua | 8 +++--- indra/newview/scripts/lua/WaitQueue.lua | 11 ++++---- indra/newview/scripts/lua/fiber.lua | 45 +++++++++++++++++++------------- indra/newview/scripts/lua/leap.lua | 26 +++++++++--------- 4 files changed, 50 insertions(+), 40 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index 076742815a..6ed1c10d5c 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -3,22 +3,22 @@ -- raise that error. local WaitQueue = require('WaitQueue') --- local debug = require('printf') -local function debug(...) end +-- local dbg = require('printf') +local function dbg(...) end local ErrorQueue = WaitQueue:new() function ErrorQueue:Error(message) -- Setting Error() is a marker, like closing the queue. Once we reach the -- error, every subsequent Dequeue() call will raise the same error. - debug('Setting self._closed to %q', message) + dbg('Setting self._closed to %q', message) self._closed = message self:_wake_waiters() end function ErrorQueue:Dequeue() local value = WaitQueue.Dequeue(self) - debug('ErrorQueue:Dequeue: base Dequeue() got %s', value) + dbg('ErrorQueue:Dequeue: base Dequeue() got %s', value) if value ~= nil then -- queue not yet closed, show caller return value diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index 1fbcc50847..ad4fdecf43 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -5,8 +5,8 @@ local fiber = require('fiber') local Queue = require('Queue') --- local debug = LL.print_debug -local function debug(...) end +-- local dbg = require('printf') +local function dbg(...) end local WaitQueue = Queue:new() @@ -60,17 +60,18 @@ function WaitQueue:Dequeue() -- the queue while there are still items left, and we want the -- consumer(s) to retrieve those last few items. if self._closed then - debug('WaitQueue:Dequeue(): closed') + dbg('WaitQueue:Dequeue(): closed') return nil end - debug('WaitQueue:Dequeue(): waiting') + dbg('WaitQueue:Dequeue(): waiting') -- add the running coroutine to the list of waiters + dbg('WaitQueue:Dequeue() running %s', tostring(coroutine.running() or 'main')) table.insert(self._waiters, fiber.running()) -- then let somebody else run fiber.wait() end -- here we're sure this queue isn't empty - debug('WaitQueue:Dequeue() calling Queue.Dequeue()') + dbg('WaitQueue:Dequeue() calling Queue.Dequeue()') return Queue.Dequeue(self) end diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua index aebf27357f..9057e6c890 100644 --- a/indra/newview/scripts/lua/fiber.lua +++ b/indra/newview/scripts/lua/fiber.lua @@ -17,8 +17,8 @@ -- or with an error). local printf = require 'printf' --- local debug = printf -local function debug(...) end +-- local dbg = printf +local function dbg(...) end local coro = require 'coro' local fiber = {} @@ -78,22 +78,28 @@ function fiber.launch(name, func, ...) byname[namekey] = co -- and remember it as this fiber's name names[co] = namekey --- debug('launch(%s)', namekey) --- debug('byname[%s] = %s', namekey, tostring(byname[namekey])) --- debug('names[%s] = %s', tostring(co), names[co]) --- debug('ready[-1] = %s', tostring(ready[#ready])) +-- dbg('launch(%s)', namekey) +-- dbg('byname[%s] = %s', namekey, tostring(byname[namekey])) +-- dbg('names[%s] = %s', tostring(co), names[co]) +-- dbg('ready[-1] = %s', tostring(ready[#ready])) end -- for debugging -function fiber.print_all() - print('Ready fibers:' .. if next(ready) then '' else ' none') +function format_all() + output = {} + table.insert(output, 'Ready fibers:' .. if next(ready) then '' else ' none') for _, co in pairs(ready) do - printf(' %s: %s', fiber.get_name(co), fiber.status(co)) + table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co))) end - print('Waiting fibers:' .. if next(waiting) then '' else ' none') + table.insert(output, 'Waiting fibers:' .. if next(waiting) then '' else ' none') for co in pairs(waiting) do - printf(' %s: %s', fiber.get_name(co), fiber.status(co)) + table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co))) end + return table.concat(output, '\n') +end + +function fiber.print_all() + print(format_all()) end -- return either the running coroutine or, if called from the main thread, @@ -160,6 +166,7 @@ end -- Suspend the current fiber until some other fiber calls fiber.wake() on it function fiber.wait() + dbg('Fiber %q waiting', fiber.get_name()) set_waiting() -- now yield to other fibers fiber.yield() @@ -175,26 +182,27 @@ function fiber.wake(co) waiting[co] = nil -- add to end of ready list table.insert(ready, co) + dbg('Fiber %q ready', fiber.get_name(co)) -- but don't yet resume it: that happens next time we reach yield() end -- pop and return the next not-dead fiber in the ready list, or nil if none remain local function live_ready_iter() - -- don't write + -- don't write: -- for co in table.remove, ready, 1 -- because it would keep passing a new second parameter! for co in function() return table.remove(ready, 1) end do - debug('%s live_ready_iter() sees %s, status %s', + dbg('%s live_ready_iter() sees %s, status %s', fiber.get_name(), fiber.get_name(co), fiber.status(co)) -- keep removing the head entry until we find one that's not dead, -- discarding any dead coroutines along the way if co == 'main' or coroutine.status(co) ~= 'dead' then - debug('%s live_ready_iter() returning %s', + dbg('%s live_ready_iter() returning %s', fiber.get_name(), fiber.get_name(co)) return co end end - debug('%s live_ready_iter() returning nil', fiber.get_name()) + dbg('%s live_ready_iter() returning nil', fiber.get_name()) return nil end @@ -214,6 +222,7 @@ end -- * false, nil if this is the only remaining fiber -- * nil, x if configured idle() callback returns non-nil x local function scheduler() + dbg('scheduler():\n%s', format_all()) -- scheduler() is asymmetric because Lua distinguishes the main thread -- from other coroutines. The main thread can't yield; it can only resume -- other coroutines. So although an arbitrary coroutine could resume still @@ -311,12 +320,12 @@ function fiber.run() end local others, idle_done repeat - debug('%s calling fiber.run() calling scheduler()', fiber.get_name()) + dbg('%s calling fiber.run() calling scheduler()', fiber.get_name()) others, idle_done = scheduler() - debug("%s fiber.run()'s scheduler() returned %s, %s", fiber.get_name(), + dbg("%s fiber.run()'s scheduler() returned %s, %s", fiber.get_name(), tostring(others), tostring(idle_done)) until (not others) - debug('%s fiber.run() done', fiber.get_name()) + dbg('%s fiber.run() done', fiber.get_name()) -- For whatever it's worth, put our own fiber back in the ready list. table.insert(ready, fiber.running()) -- Once there are no more waiting fibers, and the only ready fiber is diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index a60819d493..9da1839c68 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -40,8 +40,8 @@ local fiber = require('fiber') local ErrorQueue = require('ErrorQueue') --- local debug = require('printf') -local function debug(...) end +-- local dbg = require('printf') +local function dbg(...) end local leap = {} @@ -102,7 +102,7 @@ end -- -- See also request(), generate(). function leap.send(pump, data, reqid) - debug('leap.send(%s, %s, %s) entry', pump, data, reqid) + dbg('leap.send(%s, %s, %s) entry', pump, data, reqid) local data = data if type(data) == 'table' then data = table.clone(data) @@ -111,7 +111,7 @@ function leap.send(pump, data, reqid) data['reqid'] = reqid end end - debug('leap.send(%s, %s) calling post_on()', pump, data) + dbg('leap.send(%s, %s) calling post_on()', pump, data) LL.post_on(pump, data) end @@ -126,7 +126,7 @@ local function requestSetup(pump, data) -- WaitForReqid object in leap._pending so dispatch() can find it. leap._pending[reqid] = leap.WaitForReqid:new(reqid) -- Pass reqid to send() to stamp it into (a copy of) the request data. - debug('requestSetup(%s, %s)', pump, data) + dbg('requestSetup(%s, %s)', pump, data) leap.send(pump, data, reqid) return reqid end @@ -152,9 +152,9 @@ end function leap.request(pump, data) local reqid = requestSetup(pump, data) local waitfor = leap._pending[reqid] - debug('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor)) + dbg('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor)) local ok, response = pcall(waitfor.wait, waitfor) - debug('leap.request(%s, %s) got %s: %s', pump, data, ok, response) + dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) -- kill off temporary WaitForReqid object, even if error leap._pending[reqid] = nil if ok then @@ -210,7 +210,7 @@ local function unsolicited(pump, data) -- we maintain waitfors in descending priority order, so the first waitfor -- to claim this event is the one with the highest priority for i, waitfor in pairs(leap._waitfors) do - debug('unsolicited() checking %s', waitfor.name) + dbg('unsolicited() checking %s', waitfor.name) if waitfor:handle(pump, data) then return end @@ -243,9 +243,9 @@ fiber.set_idle(function () cleanup('done') return 'done' end - debug('leap.idle() calling get_event_next()') + dbg('leap.idle() calling get_event_next()') local ok, pump, data = pcall(LL.get_event_next) - debug('leap.idle() got %s: %s, %s', ok, pump, data) + dbg('leap.idle() got %s: %s, %s', ok, pump, data) -- ok false means get_event_next() raised a Lua error, pump is message if not ok then cleanup(pump) @@ -368,9 +368,9 @@ end -- Block the calling coroutine until a suitable unsolicited event (one -- for which filter() returns the event) arrives. function leap.WaitFor:wait() - debug('%s about to wait', self.name) + dbg('%s about to wait', self.name) local item = self._queue:Dequeue() - debug('%s got %s', self.name, item) + dbg('%s got %s', self.name, item) return item end @@ -392,7 +392,7 @@ end -- called by unsolicited() for each WaitFor in leap._waitfors function leap.WaitFor:handle(pump, data) local item = self:filter(pump, data) - debug('%s.filter() returned %s', self.name, item) + dbg('%s.filter() returned %s', self.name, item) -- if this item doesn't pass the filter, we're not interested if not item then return false -- cgit v1.2.3 From bfeedacf5a32fb77bd505c43126f3b5dc4394296 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 27 Mar 2024 23:11:24 +0200 Subject: Run each script file with new LuaState --- indra/newview/llfloaterluadebug.cpp | 3 +- indra/newview/llluamanager.cpp | 39 +++++++------------ indra/newview/llluamanager.h | 8 ++-- indra/newview/scripts/lua/test_LLFloaterAbout.lua | 10 +---- indra/newview/scripts/lua/test_LLGesture.lua | 46 ++++++++++------------- 5 files changed, 39 insertions(+), 67 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index b63600e0e6..f247528231 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -111,8 +111,7 @@ void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filena if (!filepath.empty()) { mScriptPath->setText(filepath); - cleanLuaState(); - LLLUAmanager::runScriptFile(mState, filepath, [this](int count, const LLSD& result) + LLLUAmanager::runScriptFile(filepath, [this](int count, const LLSD &result) { completion(count, result); }); diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c65f062fd7..3194182ceb 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -195,61 +195,50 @@ lua_function(get_event_next, return 2; } -void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb) -{ - // A script_finished_fn is used to initialize the LuaState. - // It will be called when the LuaState is destroyed. - LuaState L(cb); - runScriptFile(L, filename); -} - -void LLLUAmanager::runScriptFile(const std::string& filename, script_result_fn cb) -{ - LuaState L; - // A script_result_fn will be called when LuaState::expr() completes. - runScriptFile(L, filename, cb); -} - LLCoros::Future<std::pair<int, LLSD>> -LLLUAmanager::startScriptFile(LuaState& L, const std::string& filename) +LLLUAmanager::startScriptFile(const std::string& filename) { // Despite returning from startScriptFile(), we need this Promise to // remain alive until the callback has fired. auto promise{ std::make_shared<LLCoros::Promise<std::pair<int, LLSD>>>() }; - runScriptFile(L, filename, + runScriptFile(filename, [promise](int count, LLSD result) { promise->set_value({ count, result }); }); return LLCoros::getFuture(*promise); } -std::pair<int, LLSD> LLLUAmanager::waitScriptFile(LuaState& L, const std::string& filename) +std::pair<int, LLSD> LLLUAmanager::waitScriptFile(const std::string& filename) { - return startScriptFile(L, filename).get(); + return startScriptFile(filename).get(); } -void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, script_result_fn cb) +void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb) { - LLCoros::instance().launch(filename, [&L, filename, cb]() + // A script_result_fn will be called when LuaState::expr() completes. + LLCoros::instance().launch(filename, [filename, result_cb, finished_cb]() { llifstream in_file; in_file.open(filename.c_str()); if (in_file.is_open()) { + // A script_finished_fn is used to initialize the LuaState. + // It will be called when the LuaState is destroyed. + LuaState L(finished_cb); std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); - if (cb) + if (result_cb) { - cb(count, result); + result_cb(count, result); } } else { auto msg{ stringize("unable to open script file '", filename, "'") }; LL_WARNS("Lua") << msg << LL_ENDL; - if (cb) + if (result_cb) { - cb(-1, msg); + result_cb(-1, msg); } } }); diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index fb9f1b8141..a297d14502 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -53,19 +53,17 @@ public: // results, represented as the entries of the result array. typedef std::function<void(int count, const LLSD& result)> script_result_fn; - static void runScriptFile(const std::string &filename, script_finished_fn cb = {}); - static void runScriptFile(const std::string &filename, script_result_fn cb); - static void runScriptFile(LuaState& L, const std::string &filename, script_result_fn cb = {}); + static void runScriptFile(const std::string &filename, script_result_fn result_cb = {}, script_finished_fn finished_cb = {}); // Start running a Lua script file, returning an LLCoros::Future whose // get() method will pause the calling coroutine until it can deliver the // (count, result) pair described above. Between startScriptFile() and // Future::get(), the caller and the Lua script coroutine will run // concurrently. static LLCoros::Future<std::pair<int, LLSD>> - startScriptFile(LuaState& L, const std::string& filename); + startScriptFile(const std::string& filename); // Run a Lua script file, and pause the calling coroutine until it completes. // The return value is the (count, result) pair described above. - static std::pair<int, LLSD> waitScriptFile(LuaState& L, const std::string& filename); + static std::pair<int, LLSD> waitScriptFile(const std::string& filename); static void runScriptLine(const std::string &chunk, script_finished_fn cb = {}); static void runScriptLine(const std::string &chunk, script_result_fn cb); diff --git a/indra/newview/scripts/lua/test_LLFloaterAbout.lua b/indra/newview/scripts/lua/test_LLFloaterAbout.lua index 7abc437b79..6bbf61982d 100644 --- a/indra/newview/scripts/lua/test_LLFloaterAbout.lua +++ b/indra/newview/scripts/lua/test_LLFloaterAbout.lua @@ -1,14 +1,6 @@ -- test LLFloaterAbout LLFloaterAbout = require('LLFloaterAbout') -leap = require('leap') -coro = require('coro') inspect = require('inspect') -coro.launch(function () - print(inspect(LLFloaterAbout.getInfo())) - leap.done() -end) - -leap.process() - +print(inspect(LLFloaterAbout.getInfo())) diff --git a/indra/newview/scripts/lua/test_LLGesture.lua b/indra/newview/scripts/lua/test_LLGesture.lua index 5897a0e3cb..1cce674565 100644 --- a/indra/newview/scripts/lua/test_LLGesture.lua +++ b/indra/newview/scripts/lua/test_LLGesture.lua @@ -2,31 +2,25 @@ LLGesture = require 'LLGesture' inspect = require 'inspect' -coro = require 'coro' -leap = require 'leap' -coro.launch(function() - -- getActiveGestures() returns {<UUID>: {name, playing, trigger}} - gestures_uuid = LLGesture.getActiveGestures() - -- convert to {<name>: <uuid>} - gestures = {} - for uuid, info in pairs(gestures_uuid) do - gestures[info.name] = uuid - end - -- now run through the list - for name, uuid in pairs(gestures) do - if name == 'afk' then - -- afk has a long timeout, and isn't interesting to look at - continue - end - print(name) - LLGesture.startGesture(uuid) - repeat - LL.sleep(1) - until not LLGesture.isGesturePlaying(uuid) - end - print('Done.') - leap.done() -end) -leap.process() +-- getActiveGestures() returns {<UUID>: {name, playing, trigger}} +gestures_uuid = LLGesture.getActiveGestures() +-- convert to {<name>: <uuid>} +gestures = {} +for uuid, info in pairs(gestures_uuid) do + gestures[info.name] = uuid +end +-- now run through the list +for name, uuid in pairs(gestures) do + if name == 'afk' then + -- afk has a long timeout, and isn't interesting to look at + continue + end + print(name) + LLGesture.startGesture(uuid) + repeat + LL.sleep(1) + until not LLGesture.isGesturePlaying(uuid) +end +print('Done.') -- cgit v1.2.3 From 9fbfd3d0ad1ed2cb721129a59421f06fedd071bf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Mar 2024 07:10:10 -0400 Subject: Remove llluamanager.cpp "FIXME extremely hacky way" cruft. --- indra/newview/llluamanager.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c65f062fd7..d1fcf21941 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -35,16 +35,6 @@ #include "lualistener.h" #include "stringize.h" -// skip all these link dependencies for integration testing -#ifndef LL_TEST -#include "lluilistener.h" -#include "llviewercontrol.h" - -// FIXME extremely hacky way to get to the UI Listener framework. There's -// a cleaner way. -extern LLUIListener sUIListener; -#endif // ! LL_TEST - #include <boost/algorithm/string/replace.hpp> #include <filesystem> -- cgit v1.2.3 From ce73e5c5ab0c33673067d9322c98ae8800fa9224 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Mar 2024 07:11:31 -0400 Subject: Terminate Lua scripts hanging in LL.get_event_next(). Make LuaListener listen for "LLApp" viewer shutdown events. On receiving such, it closes its queue. Then the C++ coroutine calling getNext() wakes up with an LLThreadSafeQueue exception, and calls LLCoros::checkStop() to throw one of the exceptions recognized by LLCoros::toplevel(). Add an llluamanager_test.cpp test to verify this behavior. --- indra/newview/tests/llluamanager_test.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index e10dedcf53..682289bd93 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -418,4 +418,25 @@ namespace tut auto [count, result] = future.get(); ensure_equals("leap.lua: " + result.asString(), count, 0); } + + template<> template<> + void object::test<7>() + { + set_test_name("stop hanging Lua script"); + const std::string lua( + "-- hanging Lua script should terminate\n" + "\n" + "LL.get_event_next()\n" + ); + LuaState L; + auto future = LLLUAmanager::startScriptLine(L, lua); + // The problem with this test is that the LuaState is destroyed + // (disconnecting the listener) before the LLTestApp instance mApp is + // destroyed (sending the shutdown event). Explicitly simulate LLApp's + // event. + LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", "quitting")); + // but now we have to give the startScriptLine() coroutine a chance to run + auto [count, result] = future.get(); + ensure_equals(result.asString(), count, 0); + } } // namespace tut -- cgit v1.2.3 From ba74839cd19c3b17757345ba81b1aa97c57f43d4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Mar 2024 11:49:19 -0400 Subject: Use LLApp::setQuitting(). Expect killed-script error. --- indra/newview/tests/llluamanager_test.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 682289bd93..b907ac6619 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -430,13 +430,12 @@ namespace tut ); LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); - // The problem with this test is that the LuaState is destroyed - // (disconnecting the listener) before the LLTestApp instance mApp is - // destroyed (sending the shutdown event). Explicitly simulate LLApp's - // event. - LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", "quitting")); + // Poke LLTestApp to send its preliminary shutdown message. + mApp.setQuitting(); // but now we have to give the startScriptLine() coroutine a chance to run auto [count, result] = future.get(); - ensure_equals(result.asString(), count, 0); + ensure_equals("killed Lua script terminated normally", count, -1); + ensure_equals("unexpected killed Lua script error", + result.asString(), "viewer is stopping"); } } // namespace tut -- cgit v1.2.3 From 53ce38b106a086a4e3bc1ed0663bb47b0f0d967c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 28 Mar 2024 12:11:34 -0400 Subject: Remove rest of prototype UI access. --- indra/newview/llluamanager.cpp | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index d1fcf21941..74306a60ba 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -31,6 +31,7 @@ #include "llcoros.h" #include "llerror.h" #include "lleventcoro.h" +#include "llviewercontrol.h" #include "lua_function.h" #include "lualistener.h" #include "stringize.h" @@ -116,37 +117,6 @@ lua_function(print_warning, "print_warning(args...): WARNING level logging") return 0; } -#ifndef LL_TEST - -lua_function(run_ui_command, - "run_ui_command(name [, parameter]): " - "call specified UI command with specified parameter") -{ - int top = lua_gettop(L); - std::string func_name; - if (top >= 1) - { - func_name = lua_tostring(L,1); - } - std::string parameter; - if (top >= 2) - { - parameter = lua_tostring(L,2); - } - LL_WARNS("LUA") << "running ui func " << func_name << " parameter " << parameter << LL_ENDL; - LLSD event; - event["function"] = func_name; - if (!parameter.empty()) - { - event["parameter"] = parameter; - } - sUIListener.call(event); - - lua_settop(L, 0); - return 0; -} -#endif // ! LL_TEST - lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLEventPump") { std::string pumpname{ lua_tostdstring(L, 1) }; -- cgit v1.2.3 From 836f8dc26f2041aea51c5c953b99f34859db6387 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 1 Apr 2024 13:13:53 +0300 Subject: Add 'Lua Scripts' floater --- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloaterluascripts.cpp | 123 +++++++++++++++++++++ indra/newview/llfloaterluascripts.h | 55 +++++++++ indra/newview/llluamanager.cpp | 5 + indra/newview/llluamanager.h | 5 + indra/newview/llviewerfloaterreg.cpp | 2 + .../skins/default/xui/en/floater_lua_scripts.xml | 36 ++++++ .../skins/default/xui/en/menu_lua_scripts.xml | 11 ++ indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++ 9 files changed, 249 insertions(+) create mode 100644 indra/newview/llfloaterluascripts.cpp create mode 100644 indra/newview/llfloaterluascripts.h create mode 100644 indra/newview/skins/default/xui/en/floater_lua_scripts.xml create mode 100644 indra/newview/skins/default/xui/en/menu_lua_scripts.xml (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b26ce7d06d..f41e481b26 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -243,6 +243,7 @@ set(viewer_SOURCE_FILES llfloaterlinkreplace.cpp llfloaterloadprefpreset.cpp llfloaterluadebug.cpp + llfloaterluascripts.cpp llfloatermarketplacelistings.cpp llfloatermap.cpp llfloatermediasettings.cpp @@ -901,6 +902,7 @@ set(viewer_HEADER_FILES llfloaterlinkreplace.h llfloaterloadprefpreset.h llfloaterluadebug.h + llfloaterluascripts.h llfloatermap.h llfloatermarketplacelistings.h llfloatermediasettings.h diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp new file mode 100644 index 0000000000..87d2cf0c69 --- /dev/null +++ b/indra/newview/llfloaterluascripts.cpp @@ -0,0 +1,123 @@ +/** + * @file llfloaterluascriptsinfo.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterluascripts.h" +#include "llevents.h" +#include <filesystem> +#include "llluamanager.h" +#include "llscrolllistctrl.h" +#include "llviewerwindow.h" +#include "llwindow.h" +#include "llviewermenu.h" + +const F32 REFRESH_INTERVAL = 1.0f; + +LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) + : LLFloater(key), + mUpdateTimer(new LLTimer()), + mContextMenuHandle() +{ + mCommitCallbackRegistrar.add("Script.OpenFolder", [this](LLUICtrl*, const LLSD &userdata) + { + gViewerWindow->getWindow()->openFolder(mTargetFolderPath); + }); +} + + +BOOL LLFloaterLUAScripts::postBuild() +{ + mScriptList = getChild<LLScrollListCtrl>("scripts_list"); + mScriptList->setRightMouseDownCallback(boost::bind(&LLFloaterLUAScripts::onScrollListRightClicked, this, _1, _2, _3)); + + LLContextMenu *menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( + "menu_lua_scripts.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (menu) + { + mContextMenuHandle = menu->getHandle(); + } + + return TRUE; +} + +LLFloaterLUAScripts::~LLFloaterLUAScripts() +{ + auto menu = mContextMenuHandle.get(); + if (menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } + + delete mUpdateTimer; +} + +void LLFloaterLUAScripts::draw() +{ + if (mUpdateTimer->hasExpired()) + { + populateScriptList(); + } + LLFloater::draw(); +} + +void LLFloaterLUAScripts::populateScriptList() +{ + S32 prev_pos = mScriptList->getScrollPos(); + LLSD prev_selected = mScriptList->getSelectedValue(); + mScriptList->clearRows(); + mScriptList->updateColumns(true); + std::map<std::string, std::string> scripts = LLLUAmanager::getScriptNames(); + for (auto &it : scripts) + { + LLSD row; + row["value"] = it.first; + row["columns"][0]["value"] = std::filesystem::path((it.second)).stem().string(); + row["columns"][0]["column"] = "script_name"; + row["columns"][1]["value"] = it.second; + row["columns"][1]["column"] = "script_path"; + mScriptList->addElement(row); + } + mScriptList->setScrollPos(prev_pos); + mScriptList->setSelectedByValue(prev_selected, true); + mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); +} + +void LLFloaterLUAScripts::onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y) +{ + LLScrollListItem *item = mScriptList->hitItem(x, y); + if (item) + { + mScriptList->selectItemAt(x, y, MASK_NONE); + auto menu = mContextMenuHandle.get(); + if (menu) + { + mTargetFolderPath = std::filesystem::path((item->getColumn(1)->getValue().asString())).parent_path().string(); + menu->show(x, y); + LLMenuGL::showPopup(this, menu, x, y); + } + } +} diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h new file mode 100644 index 0000000000..c8c9e7f020 --- /dev/null +++ b/indra/newview/llfloaterluascripts.h @@ -0,0 +1,55 @@ +/** + * @file llfloaterluascriptsinfo.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERLUASCRIPTS_H +#define LL_LLFLOATERLUASCRIPTS_H + +#include "llfloater.h" + +class LLScrollListCtrl; + +class LLFloaterLUAScripts : + public LLFloater +{ + public: + LLFloaterLUAScripts(const LLSD &key); + virtual ~LLFloaterLUAScripts(); + + BOOL postBuild(); + void draw(); + +private: + void populateScriptList(); + void onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y); + + LLTimer* mUpdateTimer; + LLScrollListCtrl* mScriptList; + std::string mTargetFolderPath; + + LLHandle<LLContextMenu> mContextMenuHandle; +}; + +#endif // LL_LLFLOATERLUASCRIPTS_H + diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index be332a7244..343c7c7459 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -48,6 +48,8 @@ #include <string_view> #include <vector> +std::map<std::string, std::string> LLLUAmanager::sScriptNames; + lua_function(sleep, "sleep(seconds): pause the running coroutine") { F32 seconds = lua_tonumber(L, -1); @@ -177,6 +179,8 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // A script_result_fn will be called when LuaState::expr() completes. LLCoros::instance().launch(filename, [filename, result_cb, finished_cb]() { + std::string coro_name = LLCoros::getName(); + sScriptNames[coro_name] = filename; llifstream in_file; in_file.open(filename.c_str()); @@ -201,6 +205,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r result_cb(-1, msg); } } + sScriptNames.erase(coro_name); }); } diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index a297d14502..70728f958e 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -80,6 +80,11 @@ public: static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& chunk); static void runScriptOnLogin(); + + static std::map<std::string, std::string> getScriptNames() { return sScriptNames; } + + private: + static std::map<std::string, std::string> sScriptNames; }; class LLRequireResolver diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f72ef71241..de328639f8 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -94,6 +94,7 @@ #include "llfloaterlinkreplace.h" #include "llfloaterloadprefpreset.h" #include "llfloaterluadebug.h" +#include "llfloaterluascripts.h" #include "llfloatermap.h" #include "llfloatermarketplacelistings.h" #include "llfloatermediasettings.h" @@ -402,6 +403,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>); LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUADebug>); + LLFloaterReg::add("lua_scripts", "floater_lua_scripts.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUAScripts>); LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); diff --git a/indra/newview/skins/default/xui/en/floater_lua_scripts.xml b/indra/newview/skins/default/xui/en/floater_lua_scripts.xml new file mode 100644 index 0000000000..6859201650 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_lua_scripts.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_minimize="false" + can_resize="true" + can_close="true" + bevel_style="in" + height="220" + min_height="220" + layout="topleft" + name="LUA scripts" + save_rect="true" + title="LUA Scripts" + single_instance="true" + width="555" + min_width="555"> + <scroll_list + column_padding="0" + draw_stripes="true" + draw_heading="true" + height="200" + left="10" + follows="all" + layout="topleft" + sort_column="script_name" + name="scripts_list" + top_pad="10" + width="535"> + <scroll_list.columns + label="Name" + name="script_name" + width="180" /> + <scroll_list.columns + label="Path" + name="script_path"/> + </scroll_list> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_lua_scripts.xml b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml new file mode 100644 index 0000000000..8f718abe17 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + name="Scripts"> + <menu_item_call + label="Open Containing Folder" + layout="topleft" + name="open_folder"> + <menu_item_call.on_click + function="Script.OpenFolder" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index b259b101b4..40f5c40dfe 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2539,6 +2539,16 @@ function="World.EnvPreset" function="Floater.Toggle" parameter="lua_debug" /> </menu_item_check> + <menu_item_check + label="LUA Scripts Info" + name="LUA Scripts"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="lua_scripts" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="lua_scripts" /> + </menu_item_check> <menu_item_separator/> <menu_item_call -- cgit v1.2.3 From 74900fd4380dd57eb444b2fc1379bd83872a0726 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 1 Apr 2024 23:59:02 +0300 Subject: triage#150 on OSX any file can be chosen for model upload --- indra/newview/llfilepicker.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview') diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 4ad136e13a..7ca212e062 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -663,6 +663,7 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF allowedv->push_back("gltf"); allowedv->push_back("glb"); break; + case FFLOAD_MODEL: case FFLOAD_COLLADA: allowedv->push_back("dae"); break; -- cgit v1.2.3 From dcc77324736c84705fdde1056b7ae04c583b9db1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 2 Apr 2024 00:38:51 +0300 Subject: viewer#1104 Crash at populateFoldersList Ensure folder creation callbacks remain alive --- indra/newview/llfloatercreatelandmark.cpp | 10 +++++++--- indra/newview/llfloatercreatelandmark.h | 2 +- indra/newview/llinventorybridge.cpp | 20 +++++++++++++++++--- indra/newview/llinventorybridge.h | 5 ++++- 4 files changed, 29 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp index 7dc3e4afe3..351f4a844c 100644 --- a/indra/newview/llfloatercreatelandmark.cpp +++ b/indra/newview/llfloatercreatelandmark.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llagentui.h" #include "llcombobox.h" +#include "llfloaterreg.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "lllandmarkactions.h" @@ -286,8 +287,7 @@ void LLFloaterCreateLandmark::onCreateFolderClicked() std::string folder_name = resp["message"].asString(); if (!folder_name.empty()) { - inventory_func_type func = boost::bind(&LLFloaterCreateLandmark::folderCreatedCallback, this, _1); - gInventory.createNewCategory(mLandmarksID, LLFolderType::FT_NONE, folder_name, func); + gInventory.createNewCategory(mLandmarksID, LLFolderType::FT_NONE, folder_name, folderCreatedCallback); gInventory.notifyObservers(); } } @@ -296,7 +296,11 @@ void LLFloaterCreateLandmark::onCreateFolderClicked() void LLFloaterCreateLandmark::folderCreatedCallback(LLUUID folder_id) { - populateFoldersList(folder_id); + LLFloaterCreateLandmark* floater = LLFloaterReg::findTypedInstance<LLFloaterCreateLandmark>("add_landmark"); + if (floater && !floater->isDead()) + { + floater->populateFoldersList(folder_id); + } } void LLFloaterCreateLandmark::onSaveClicked() diff --git a/indra/newview/llfloatercreatelandmark.h b/indra/newview/llfloatercreatelandmark.h index 8a1d5ae099..f91c302df7 100644 --- a/indra/newview/llfloatercreatelandmark.h +++ b/indra/newview/llfloatercreatelandmark.h @@ -62,7 +62,7 @@ private: void onSaveClicked(); void onCancelClicked(); - void folderCreatedCallback(LLUUID folder_id); + static void folderCreatedCallback(LLUUID folder_id); LLComboBox* mFolderCombo; LLLineEditor* mLandmarkTitleEditor; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 932a0316dd..0ed89292a5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5118,7 +5118,7 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLI // Note: creation will take time, so passing folder id to callback is slightly unreliable, // but so is collecting and passing descendants' ids - inventory_func_type func = boost::bind(&LLFolderBridge::outfitFolderCreatedCallback, this, inv_cat->getUUID(), _1, cb); + inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel); gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), @@ -5126,11 +5126,25 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLI inv_cat->getThumbnailUUID()); } -void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb) +void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, + LLUUID cat_dest_id, + LLPointer<LLInventoryCallback> cb, + LLHandle<LLInventoryPanel> inventory_panel) { LLInventoryModel::cat_array_t* categories; LLInventoryModel::item_array_t* items; - getInventoryModel()->getDirectDescendentsOf(cat_source_id, categories, items); + + LLInventoryPanel* panel = inventory_panel.get(); + if (!panel) + { + return; + } + LLInventoryModel* model = panel->getModel(); + if (!model) + { + return; + } + model->getDirectDescendentsOf(cat_source_id, categories, items); LLInventoryObject::const_object_list_t link_array; diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3cbbd68e51..ea756f5c14 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -379,7 +379,10 @@ public: static void staticFolderOptionsMenu(); protected: - void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb); + static void outfitFolderCreatedCallback(LLUUID cat_source_id, + LLUUID cat_dest_id, + LLPointer<LLInventoryCallback> cb, + LLHandle<LLInventoryPanel> inventory_panel); void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response); void perform_pasteFromClipboard(); void gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level); -- cgit v1.2.3 From a6b99dbcb4ea69db73401a3101266ee49b88c9bc Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Sat, 9 Mar 2024 19:19:49 +0200 Subject: Revert "Remove gender-based restrictions on shape and physics sliders" This reverts commit 1ebd23ffed912a5c8c94d109f37a2c25cf169523. --- indra/newview/character/avatar_lad.xml | 59 +++++++++++++++++++--- indra/newview/skins/default/xui/da/strings.xml | 3 -- indra/newview/skins/default/xui/de/strings.xml | 1 - .../skins/default/xui/en/panel_edit_wearable.xml | 51 +++++++++++++++++++ indra/newview/skins/default/xui/en/strings.xml | 1 - indra/newview/skins/default/xui/es/strings.xml | 1 - indra/newview/skins/default/xui/fr/strings.xml | 1 - indra/newview/skins/default/xui/it/strings.xml | 1 - indra/newview/skins/default/xui/ja/strings.xml | 3 -- indra/newview/skins/default/xui/pl/strings.xml | 3 -- indra/newview/skins/default/xui/pt/strings.xml | 1 - indra/newview/skins/default/xui/ru/strings.xml | 3 -- indra/newview/skins/default/xui/tr/strings.xml | 3 -- indra/newview/skins/default/xui/zh/strings.xml | 3 -- 14 files changed, 104 insertions(+), 30 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 9be6275929..2cdd86267e 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -3822,6 +3822,7 @@ <param id="30879" group="1" + sex="male" name="Male_Package" value_min="-.5" value_max="2"> @@ -5812,6 +5813,7 @@ <param id="400" + sex="male" group="1" name="Displace_Hair_Facial" label="Hair Thickess" @@ -6836,6 +6838,7 @@ <param id="626" + sex="female" group="1" name="Big_Chest" label="Chest Size" @@ -6862,6 +6865,7 @@ <param id="627" + sex="female" group="1" name="Small_Chest" label="Chest Size" @@ -6887,6 +6891,7 @@ <param id="843" + sex="female" group="1" name="No_Chest" label="Chest Size" @@ -6915,6 +6920,7 @@ group="1" name="Muscular_Torso" label="Torso Muscles" + sex="male" show_simple="true" wearable="shape" edit_group="shape_torso" @@ -6957,6 +6963,7 @@ group="1" name="Muscular_Torso" label="Torso Muscles" + sex="female" show_simple="true" wearable="shape" edit_group="shape_torso" @@ -6997,6 +7004,7 @@ <param id="648" group="1" + sex="female" name="Scrawny_Torso" label="Torso Muscles" show_simple="true" @@ -7051,6 +7059,7 @@ <param id="677" group="1" + sex="male" name="Scrawny_Torso_Male" label="Torso Scrawny" wearable="shape" @@ -7183,6 +7192,7 @@ <param id="507" group="0" + sex="female" name="Breast_Gravity" label="Breast Buoyancy" wearable="shape" @@ -7269,6 +7279,7 @@ <param id="684" group="0" + sex="female" name="Breast_Female_Cleavage" label="Breast Cleavage" wearable="shape" @@ -7296,6 +7307,7 @@ <param id="685" group="0" + sex="male" name="Chest_Male_No_Pecs" label="Pectorals" wearable="shape" @@ -7513,6 +7525,7 @@ <param id="1200" group="1" + sex="female" name="Breast_Physics_UpDown_Driven" wearable="physics" edit_group="driven" @@ -7534,6 +7547,7 @@ <param id="1201" group="1" + sex="female" name="Breast_Physics_InOut_Driven" wearable="physics" edit_group="driven" @@ -8065,6 +8079,7 @@ <param id="20879" group="1" + sex="male" name="Male_Package" value_min="-.5" value_max="2"> @@ -9822,6 +9837,7 @@ render_pass="bump"> <param id="1004" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9836,6 +9852,7 @@ render_pass="bump"> <param id="1006" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9850,6 +9867,7 @@ render_pass="bump"> <param id="1008" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9864,6 +9882,7 @@ render_pass="bump"> <param id="1010" + sex="male" group="1" edit_group="driven" wearable="hair" @@ -9879,6 +9898,7 @@ render_pass="bump"> <param id="1012" group="1" + sex="male" wearable="hair" edit_group="driven" name="5 O'Clock Shadow bump" @@ -9904,6 +9924,7 @@ render_pass="bump"> <param id="1005" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9918,6 +9939,7 @@ render_pass="bump"> <param id="1007" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9932,6 +9954,7 @@ render_pass="bump"> <param id="1009" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9946,6 +9969,7 @@ render_pass="bump"> <param id="1011" + sex="male" group="1" wearable="hair" edit_group="driven" @@ -9962,6 +9986,7 @@ render_pass="bump"> id="751" group="1" wearable="hair" + sex="male" edit_group="hair_facial" name="5 O'Clock Shadow" label_min="Dense hair" @@ -15072,6 +15097,7 @@ render_pass="bump"> <param id="105" group="0" + sex="female" wearable="shape" edit_group="shape_torso" edit_group_order="6" @@ -15236,6 +15262,7 @@ render_pass="bump"> <param id="649" group="0" + sex="female" wearable="shape" edit_group="shape_torso" edit_group_order="1.1" @@ -15270,6 +15297,7 @@ render_pass="bump"> <param id="678" group="0" + sex="male" wearable="shape" edit_group="shape_torso" edit_group_order="1" @@ -15337,14 +15365,10 @@ render_pass="bump"> id="80" name="male" group="0" - edit_group="shape_body" - label="Gender" - label_min="Female" - label_max="Male" + edit_group="dummy" wearable="shape" value_min="0" - value_max="1" - camera_distance="2.2"> + value_max="1"> <param_driver> <driven id="32" /> @@ -15559,6 +15583,7 @@ render_pass="bump"> <param id="752" group="0" + sex="male" wearable="hair" edit_group="hair_facial" edit_group_order="1" @@ -15840,6 +15865,7 @@ render_pass="bump"> <param id="879" group="0" + sex="male" name="Male_Package" label="Package" wearable="shape" @@ -16027,6 +16053,7 @@ render_pass="bump"> <param id="166" + sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16052,6 +16079,7 @@ render_pass="bump"> <param id="167" + sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16077,6 +16105,7 @@ render_pass="bump"> <param id="168" + sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16102,6 +16131,7 @@ render_pass="bump"> <param id="169" + sex="male" group="0" wearable="hair" edit_group="hair_facial" @@ -16914,6 +16944,7 @@ render_pass="bump"> <param id="1100" group="1" + sex="female" wearable="physics" name="Breast_Physics_UpDown_Controller" label="Breast Physics UpDown Controller" @@ -16929,6 +16960,7 @@ render_pass="bump"> <param id="1101" group="1" + sex="female" wearable="physics" name="Breast_Physics_InOut_Controller" label="Breast Physics InOut Controller" @@ -17008,6 +17040,7 @@ render_pass="bump"> <param id="10000" group="0" + sex="female" name="Breast_Physics_Mass" label="Breast Physics Mass" wearable="physics" @@ -17020,6 +17053,7 @@ render_pass="bump"> <param id="10001" group="0" + sex="female" name="Breast_Physics_Gravity" label="Breast Physics Gravity" wearable="physics" @@ -17033,6 +17067,7 @@ render_pass="bump"> <param id="10002" group="0" + sex="female" name="Breast_Physics_Drag" label="Breast Physics Drag" wearable="physics" @@ -17046,6 +17081,7 @@ render_pass="bump"> <param id="10003" group="0" + sex="female" name="Breast_Physics_UpDown_Max_Effect" label="Breast Physics UpDown Max Effect" wearable="physics" @@ -17058,6 +17094,7 @@ render_pass="bump"> <param id="10004" group="0" + sex="female" name="Breast_Physics_UpDown_Spring" label="Breast Physics UpDown Spring" wearable="physics" @@ -17070,6 +17107,7 @@ render_pass="bump"> <param id="10005" group="0" + sex="female" name="Breast_Physics_UpDown_Gain" label="Breast Physics UpDown Gain" wearable="physics" @@ -17082,6 +17120,7 @@ render_pass="bump"> <param id="10006" group="0" + sex="female" name="Breast_Physics_UpDown_Damping" label="Breast Physics UpDown Damping" wearable="physics" @@ -17095,6 +17134,7 @@ render_pass="bump"> <param id="10007" group="0" + sex="female" name="Breast_Physics_InOut_Max_Effect" label="Breast Physics InOut Max Effect" wearable="physics" @@ -17107,6 +17147,7 @@ render_pass="bump"> <param id="10008" group="0" + sex="female" name="Breast_Physics_InOut_Spring" label="Breast Physics InOut Spring" wearable="physics" @@ -17119,6 +17160,7 @@ render_pass="bump"> <param id="10009" group="0" + sex="female" name="Breast_Physics_InOut_Gain" label="Breast Physics InOut Gain" wearable="physics" @@ -17131,6 +17173,7 @@ render_pass="bump"> <param id="10010" group="0" + sex="female" name="Breast_Physics_InOut_Damping" label="Breast Physics InOut Damping" wearable="physics" @@ -17364,6 +17407,7 @@ render_pass="bump"> <param id="10029" group="0" + sex="female" name="Breast_Physics_LeftRight_Max_Effect" label="Breast Physics LeftRight Max Effect" wearable="physics" @@ -17376,6 +17420,7 @@ render_pass="bump"> <param id="10030" group="0" + sex="female" name="Breast_Physics_LeftRight_Spring" label="Breast Physics LeftRight Spring" wearable="physics" @@ -17388,6 +17433,7 @@ render_pass="bump"> <param id="10031" group="0" + sex="female" name="Breast_Physics_LeftRight_Gain" label="Breast Physics LeftRight Gain" wearable="physics" @@ -17400,6 +17446,7 @@ render_pass="bump"> <param id="10032" group="0" + sex="female" name="Breast_Physics_LeftRight_Damping" label="Breast Physics LeftRight Damping" wearable="physics" diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index 2e351cbc65..e4f99d14e9 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -2688,9 +2688,6 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE]. <string name="Full Sides"> Meget hår </string> - <string name="Gender"> - Køn - </string> <string name="Glossy"> Skinnende </string> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 4a4a34911d..a9e7626dc5 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -1248,7 +1248,6 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_ <string name="Full Front">Vorne volles Haar</string> <string name="Full Hair Sides">Seitlich volles Haar</string> <string name="Full Sides">Volle Seiten</string> - <string name="Gender">Geschlecht</string> <string name="Glossy">Glänzend</string> <string name="Glove Fingers">Handschuhfinger</string> <string name="Glove Length">Handschuhlänge</string> diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml index b3aadb8ea1..85d73ece48 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml @@ -202,6 +202,57 @@ top="10" value="Shape:" width="150" /> + <radio_group + control_name="AvatarSex" + follows="top|right" + height="20" + layout="topleft" + left="210" + name="sex_radio" + top="5" + width="110"> + <radio_item + follows="all" + height="16" + label="" + layout="topleft" + left="0" + name="sex_male" + tool_tip="Male" + value="1" + width="40" /> + <radio_item + follows="all" + height="16" + label="" + layout="topleft" + left_pad="10" + name="sex_female" + tool_tip="Female" + value="0" + width="40"/> + </radio_group> + <!-- graphical labels for the radio buttons above --> + <icon + follows="top|right" + height="16" + image_name="icons/Male.png" + layout="topleft" + left="230" + name="male_icon" + tool_tip="Male" + top="7" + width="16" /> + <icon + follows="top|right" + height="16" + image_name="icons/Female.png" + layout="topleft" + left="280" + name="female_icon" + tool_tip="Female" + top="7" + width="16" /> <line_editor follows="all" height="23" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 87f866881d..7360c06f86 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3242,7 +3242,6 @@ Please reinstall viewer from https://secondlife.com/support/downloads/ and cont <string name="Full Front">Full Front</string> <string name="Full Hair Sides">Full Hair Sides</string> <string name="Full Sides">Full Sides</string> -<string name="Gender">Gender</string> <string name="Glossy">Glossy</string> <string name="Glove Fingers">Glove Fingers</string> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index fd85cdc252..cd8e7687ae 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -1227,7 +1227,6 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].</string> <string name="Full Front">Sin cortar</string> <string name="Full Hair Sides">Pelo: volumen a los lados</string> <string name="Full Sides">Volumen total</string> - <string name="Gender">Sexo</string> <string name="Glossy">Con brillo</string> <string name="Glove Fingers">Guantes: dedos</string> <string name="Glove Length">Guantes: largo</string> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 5969856086..0a3fbeb603 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -1249,7 +1249,6 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].</string> <string name="Full Front">Devant touffu</string> <string name="Full Hair Sides">Côtés touffus</string> <string name="Full Sides">Côtés touffus</string> - <string name="Gender">Sexe</string> <string name="Glossy">Brillant</string> <string name="Glove Fingers">Gants avec doigts</string> <string name="Glove Length">Longueur</string> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index e12203c6b7..178bb90ca6 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -1229,7 +1229,6 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].</string> <string name="Full Front">Anteriore gonfio</string> <string name="Full Hair Sides">Lati capelli gonfi</string> <string name="Full Sides">Lati gonfi</string> - <string name="Gender">Sesso</string> <string name="Glossy">Lucido</string> <string name="Glove Fingers">Dita con guanti</string> <string name="Glove Length">Lunghezza guanti</string> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 8fe69162c5..fa6c329fe7 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -5052,9 +5052,6 @@ www.secondlife.com から最新バージョンをダウンロードしてくだ <string name="Full Sides"> 生え揃ったサイド </string> - <string name="Gender"> - 性別 - </string> <string name="Glossy"> あり </string> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index a2d386e8ac..26ec6cc9dc 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -3318,9 +3318,6 @@ Jeżeli nadal otrzymujesz ten komunikat, skontaktuj się z [SUPPORT_SITE]. <string name="Full Sides"> Gęste boki </string> - <string name="Gender"> - Płeć - </string> <string name="Glossy"> Błyszcząca </string> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 5076e21198..6db5da2e89 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -1192,7 +1192,6 @@ If you continue to receive this message, contact the [SUPPORT_SITE].</string> <string name="Full Front">Frente cheia</string> <string name="Full Hair Sides">Cabelos laterais cheios</string> <string name="Full Sides">Lados cheios</string> - <string name="Gender">Sexo</string> <string name="Glossy">Brilhante</string> <string name="Glove Fingers">Dedos da luva</string> <string name="Glove Length">Comprimento das luvas</string> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 8fc9641624..61d836a2d1 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -3479,9 +3479,6 @@ support@secondlife.com. <string name="Full Sides"> По бокам </string> - <string name="Gender"> - Пол - </string> <string name="Glossy"> Блестящие </string> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 687de84401..e709a4c5d6 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -3482,9 +3482,6 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne başvurun. <string name="Full Sides"> Saçlar Yanda </string> - <string name="Gender"> - Cinsiyet - </string> <string name="Glossy"> Parlak </string> diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index cf94391aa4..bdb16c9bf1 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -3475,9 +3475,6 @@ http://secondlife.com/support 求助解決問題。 <string name="Full Sides"> 兩側飽滿 </string> - <string name="Gender"> - 性别 - </string> <string name="Glossy"> 光亮 </string> -- cgit v1.2.3 From f45ae0def221b4e1911e83f2da528174cf1d8a0d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Apr 2024 11:09:03 -0400 Subject: Defend leap.request(), generate() from garbage collection. Earlier we had blithely designated the 'pending' list (which stores WaitForReqid objects for pending request() and generate() calls) as a weak table. But the caller of request() or generate() does not hold a reference to the WaitForReqid object. Make pending hold "strong" references. Private collections (pending, waitfors) and private scalars that are never reassigned (reply, command) need not be entries in the leap table. --- indra/newview/scripts/lua/leap.lua | 77 ++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 37 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 9da1839c68..d19273e8bc 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -40,25 +40,25 @@ local fiber = require('fiber') local ErrorQueue = require('ErrorQueue') --- local dbg = require('printf') local function dbg(...) end +-- local dbg = require('printf') local leap = {} --- _reply: string name of reply LLEventPump. Any events the viewer posts to +-- reply: string name of reply LLEventPump. Any events the viewer posts to -- this pump will be queued for get_event_next(). We usually specify it as the -- reply pump for requests to internal viewer services. --- _command: string name of command LLEventPump. post_to(_command, ...) +-- command: string name of command LLEventPump. post_to(command, ...) -- engages LLLeapListener operations such as listening on a specified other -- LLEventPump, etc. -leap._reply, leap._command = LL.get_event_pumps() +local reply, command = LL.get_event_pumps() -- Dict of features added to the LEAP protocol since baseline implementation. -- Before engaging a new feature that might break an older viewer, we can -- check for the presence of that feature key. This table is solely about the -- LEAP protocol itself, the way we communicate with the viewer. To discover -- whether a given listener exists, or supports a particular operation, use --- _command's "getAPI" operation. --- For Lua, _command's "getFeatures" operation suffices? +-- command's "getAPI" operation. +-- For Lua, command's "getFeatures" operation suffices? -- leap._features = {} -- Each outstanding request() or generate() call has a corresponding @@ -67,20 +67,25 @@ leap._reply, leap._command = LL.get_event_pumps() -- we can look up the appropriate WaitForReqid object more efficiently -- in a dict than by tossing such objects into the usual waitfors list. -- Note: the ["reqid"] must be unique, otherwise we could end up --- replacing an earlier WaitForReqid object in self.pending with a +-- replacing an earlier WaitForReqid object in pending with a -- later one. That means that no incoming event will ever be given to -- the old WaitForReqid object. Any coroutine waiting on the discarded -- WaitForReqid object would therefore wait forever. --- these are weak values tables -local weak_values = {__mode='v'} -leap._pending = setmetatable({}, weak_values) +-- pending is NOT a weak table because the caller of request() or generate() +-- never sees the WaitForReqid object. pending holds the only reference, so +-- it should NOT be garbage-collected. +pending = {} -- Our consumer will instantiate some number of WaitFor subclass objects. -- As these are traversed in descending priority order, we must keep -- them in a list. -leap._waitfors = setmetatable({}, weak_values) +-- Anyone who instantiates a WaitFor subclass object should retain a reference +-- to it. Once the consuming script drops the reference, allow Lua to +-- garbage-collect the WaitFor despite its entry in waitfors. +local weak_values = {__mode='v'} +waitfors = setmetatable({}, weak_values) -- It has been suggested that we should use UUIDs as ["reqid"] values, -- since UUIDs are guaranteed unique. However, as the "namespace" for --- ["reqid"] values is our very own _reply pump, we can get away with +-- ["reqid"] values is our very own reply pump, we can get away with -- an integer. leap._reqid = 0 -- break leap.process() loop @@ -88,12 +93,12 @@ leap._done = false -- get the name of the reply pump function leap.replypump() - return leap._reply + return reply end -- get the name of the command pump function leap.cmdpump() - return leap._command + return command end -- Fire and forget. Send the specified request LLSD, expecting no reply. @@ -102,11 +107,10 @@ end -- -- See also request(), generate(). function leap.send(pump, data, reqid) - dbg('leap.send(%s, %s, %s) entry', pump, data, reqid) local data = data if type(data) == 'table' then data = table.clone(data) - data['reply'] = leap._reply + data['reply'] = reply if reqid ~= nil then data['reqid'] = reqid end @@ -122,13 +126,14 @@ local function requestSetup(pump, data) local reqid = leap._reqid -- Instantiate a new WaitForReqid object. The priority is irrelevant -- because, unlike the WaitFor base class, WaitForReqid does not - -- self-register on our leap._waitfors list. Instead, capture the new - -- WaitForReqid object in leap._pending so dispatch() can find it. - leap._pending[reqid] = leap.WaitForReqid:new(reqid) + -- self-register on our waitfors list. Instead, capture the new + -- WaitForReqid object in pending so dispatch() can find it. + local waitfor = leap.WaitForReqid:new(reqid) + pending[reqid] = waitfor -- Pass reqid to send() to stamp it into (a copy of) the request data. dbg('requestSetup(%s, %s)', pump, data) leap.send(pump, data, reqid) - return reqid + return reqid, waitfor end -- Send the specified request LLSD, expecting exactly one reply. Block @@ -150,13 +155,12 @@ end -- -- See also send(), generate(). function leap.request(pump, data) - local reqid = requestSetup(pump, data) - local waitfor = leap._pending[reqid] + local reqid, waitfor = requestSetup(pump, data) dbg('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor)) local ok, response = pcall(waitfor.wait, waitfor) dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) -- kill off temporary WaitForReqid object, even if error - leap._pending[reqid] = nil + pending[reqid] = nil if ok then return response else @@ -178,8 +182,7 @@ function leap.generate(pump, data, checklast) -- Invent a new, unique reqid. Arrange to handle incoming events -- bearing that reqid. Stamp the outbound request with that reqid, and -- send it. - local reqid = requestSetup(pump, data) - local waitfor = leap._pending[reqid] + local reqid, waitfor = requestSetup(pump, data) local ok, response repeat ok, response = pcall(waitfor.wait, waitfor) @@ -189,7 +192,7 @@ function leap.generate(pump, data, checklast) coroutine.yield(response) until checklast and checklast(response) -- If we break the above loop, whether or not due to error, clean up. - leap._pending[reqid] = nil + pending[reqid] = nil if not ok then error(response) end @@ -197,10 +200,10 @@ end local function cleanup(message) -- we're done: clean up all pending coroutines - for i, waitfor in pairs(leap._pending) do + for i, waitfor in pairs(pending) do waitfor:close() end - for i, waitfor in pairs(leap._waitfors) do + for i, waitfor in pairs(waitfors) do waitfor:close() end end @@ -209,7 +212,7 @@ end local function unsolicited(pump, data) -- we maintain waitfors in descending priority order, so the first waitfor -- to claim this event is the one with the highest priority - for i, waitfor in pairs(leap._waitfors) do + for i, waitfor in pairs(waitfors) do dbg('unsolicited() checking %s', waitfor.name) if waitfor:handle(pump, data) then return @@ -226,7 +229,7 @@ local function dispatch(pump, data) return unsolicited(pump, data) end -- have reqid; do we have a WaitForReqid? - local waitfor = leap._pending[reqid] + local waitfor = pending[reqid] if waitfor == nil then return unsolicited(pump, data) end @@ -268,17 +271,17 @@ end -- called by WaitFor.enable() local function registerWaitFor(waitfor) - table.insert(leap._waitfors, waitfor) + table.insert(waitfors, waitfor) -- keep waitfors sorted in descending order of specified priority - table.sort(leap._waitfors, + table.sort(waitfors, function (lhs, rhs) return lhs.priority > rhs.priority end) end -- called by WaitFor.disable() local function unregisterWaitFor(waitfor) - for i, w in pairs(leap._waitfors) do + for i, w in pairs(waitfors) do if w == waitfor then - leap._waitfors[i] = nil + waitfors[i] = nil break end end @@ -389,7 +392,7 @@ function leap.WaitFor:filter(pump, data) error('You must override the WaitFor.filter() method') end --- called by unsolicited() for each WaitFor in leap._waitfors +-- called by unsolicited() for each WaitFor in waitfors function leap.WaitFor:handle(pump, data) local item = self:filter(pump, data) dbg('%s.filter() returned %s', self.name, item) @@ -423,8 +426,8 @@ leap.WaitForReqid = leap.WaitFor:new() function leap.WaitForReqid:new(reqid) -- priority is meaningless, since this object won't be added to the - -- priority-sorted ViewerClient.waitfors list. Use the reqid as the - -- debugging name string. + -- priority-sorted waitfors list. Use the reqid as the debugging name + -- string. local obj = leap.WaitFor:new(nil, 'WaitForReqid(' .. reqid .. ')') setmetatable(obj, self) self.__index = self -- cgit v1.2.3 From cc8299d153b9aa81558951cb6b1a19693fb52982 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Apr 2024 11:22:45 -0400 Subject: Streamline std::filesystem::path conversions in LLRequireResolver. Make LLRequireResolver capture std::filesystem::path instances, instead of std::strings, for the path to resolve and the source directory. Store the running script's containing directory instead of calling parent_path() over and over. Demote Lua LL.post_on() logging to DEBUG level instead of INFO. --- indra/newview/llluamanager.cpp | 29 +++++++++++------------------ indra/newview/llluamanager.h | 5 +++-- 2 files changed, 14 insertions(+), 20 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index f3a8d2c51c..9059db9967 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -122,7 +122,7 @@ lua_function(post_on, "post_on(pumpname, data): post specified data to specified std::string pumpname{ lua_tostdstring(L, 1) }; LLSD data{ lua_tollsd(L, 2) }; lua_pop(L, 2); - LL_INFOS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL; + LL_DEBUGS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL; LLEventPumps::instance().obtain(pumpname).post(data); return 0; } @@ -314,19 +314,12 @@ void LLRequireResolver::resolveRequire(lua_State *L, std::string path) } LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : - mPathToResolve(path), + mPathToResolve(std::filesystem::path(path).lexically_normal()), L(L) { - //Luau lua_Debug and lua_getinfo() are different compared to default Lua: - //see https://github.com/luau-lang/luau/blob/80928acb92d1e4b6db16bada6d21b1fb6fa66265/VM/include/lua.h - lua_Debug ar; - lua_getinfo(L, 1, "s", &ar); - mSourceChunkname = ar.source; + mSourceDir = lluau::source_path(L).parent_path(); - std::filesystem::path fs_path(mPathToResolve); - mPathToResolve = fs_path.lexically_normal().string(); - - if (fs_path.is_absolute()) + if (mPathToResolve.is_absolute()) luaL_argerrorL(L, 1, "cannot require a full path"); } @@ -358,8 +351,8 @@ private: // push the loaded module or throw a Lua error void LLRequireResolver::findModule() { - // If mPathToResolve is absolute, this replaces mSourceChunkname.parent_path. - auto absolutePath = (std::filesystem::path((mSourceChunkname)).parent_path() / mPathToResolve).u8string(); + // If mPathToResolve is absolute, this replaces mSourceDir. + auto absolutePath = (mSourceDir / mPathToResolve).u8string(); // Push _MODULES table on stack for checking and saving to the cache luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1); @@ -375,16 +368,16 @@ void LLRequireResolver::findModule() // not already cached - prep error message just in case auto fail{ - [L=L, path=mPathToResolve]() + [L=L, path=mPathToResolve.u8string()]() { luaL_error(L, "could not find require('%s')", path.data()); }}; - if (std::filesystem::path(mPathToResolve).is_absolute()) + if (mPathToResolve.is_absolute()) { // no point searching known directories for an absolute path fail(); } - std::vector<std::string> lib_paths + std::vector<std::filesystem::path> lib_paths { gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"), #ifdef LL_TEST @@ -395,10 +388,10 @@ void LLRequireResolver::findModule() for (const auto& path : lib_paths) { - std::string absolutePathOpt = (std::filesystem::path(path) / mPathToResolve).u8string(); + std::string absolutePathOpt = (path / mPathToResolve).u8string(); if (absolutePathOpt.empty()) - luaL_error(L, "error requiring module '%s'", mPathToResolve.data()); + luaL_error(L, "error requiring module '%s'", mPathToResolve.u8string().data()); if (findModuleImpl(absolutePathOpt)) return; diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index a297d14502..bd581376b4 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -29,6 +29,7 @@ #include "llcoros.h" #include "llsd.h" +#include <filesystem> #include <functional> #include <string> #include <utility> // std::pair @@ -88,8 +89,8 @@ class LLRequireResolver static void resolveRequire(lua_State *L, std::string path); private: - std::string mPathToResolve; - std::string mSourceChunkname; + std::filesystem::path mPathToResolve; + std::filesystem::path mSourceDir; LLRequireResolver(lua_State *L, const std::string& path); -- cgit v1.2.3 From 1866d1a450b7857da82ceafbd2c6581d87b7f334 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Apr 2024 11:29:29 -0400 Subject: Add startup.lua module with startup.ensure(), wait() functions. This lets a calling script verify that it's running at the right point in the viewer's life cycle. A script that wants to interact with the SL agent wouldn't work if run from the viewer's command line -- unless it calls startup.wait("STATE_STARTED"), which pauses until login is complete. Modify test_luafloater_demo.lua and test_luafloater_gesture_list.lua to find their respective floater XUI files in the same directory as themselves. Make them both capture the reqid returned by the "showLuaFloater" operation, and filter for events bearing the same reqid. This paves the way for a given script to display more than one floater concurrently. Make test_luafloater_demo.lua (which does not require in-world resources) wait until 'STATE_LOGIN_WAIT', the point at which the viewer has presented the login screen. Make test_luafloater_gesture_list.lua (which interacts with the agent) wait until 'STATE_STARTED', the point at which the viewer is fully in world. Either or both can now be launched from the viewer's command line. --- indra/newview/scripts/lua/startup.lua | 101 +++++++++++++++++++++ indra/newview/scripts/lua/test_luafloater_demo.lua | 25 +++-- .../scripts/lua/test_luafloater_gesture_list.lua | 26 ++++-- 3 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 indra/newview/scripts/lua/startup.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/startup.lua b/indra/newview/scripts/lua/startup.lua new file mode 100644 index 0000000000..4311bb9a60 --- /dev/null +++ b/indra/newview/scripts/lua/startup.lua @@ -0,0 +1,101 @@ +-- query, wait for or mandate a particular viewer startup state + +-- During startup, the viewer steps through a sequence of numbered (and named) +-- states. This can be used to detect when, for instance, the login screen is +-- displayed, or when the viewer has finished logging in and is fully +-- in-world. + +local fiber = require 'fiber' +local leap = require 'leap' +local inspect = require 'inspect' +local function dbg(...) end +-- local dbg = require 'printf' + +-- --------------------------------------------------------------------------- +-- Get the list of startup states from the viewer. +local bynum = leap.request('LLStartUp', {op='getStateTable'})['table'] + +local byname = setmetatable( + {}, + -- set metatable to throw an error if you look up invalid state name + {__index=function(t, k) + local v = t[k] + if v then + return v + end + error(string.format('startup module passed invalid state %q', k), 2) + end}) + +-- derive byname as a lookup table to find the 0-based index for a given name +for i, name in pairs(bynum) do + -- the viewer's states are 0-based, not 1-based like Lua indexes + byname[name] = i - 1 +end +-- dbg('startup states: %s', inspect(byname)) + +-- specialize a WaitFor to track the viewer's startup state +local startup_pump = 'StartupState' +local waitfor = leap.WaitFor:new(0, startup_pump) +function waitfor:filter(pump, data) + if pump == self.name then + return data + end +end + +function waitfor:process(data) + -- keep updating startup._state for interested parties + startup._state = data.str + dbg('startup updating state to %q', data.str) + -- now pass data along to base-class method to queue + leap.WaitFor.process(self, data) +end + +-- listen for StartupState events +leap.request(leap.cmdpump(), + {op='listen', source=startup_pump, listener='startup.lua', tweak=true}) +-- poke LLStartUp to make sure we get an event +leap.send('LLStartUp', {op='postStartupState'}) + +-- --------------------------------------------------------------------------- +startup = {} + +-- wait for response from postStartupState +while not startup._state do + dbg('startup.state() waiting for first StartupState event') + waitfor:wait() +end + +-- return a list of all known startup states +function startup.list() + return bynum +end + +-- report whether state with string name 'left' is before string name 'right' +function startup.before(left, right) + return byname[left] < byname[right] +end + +-- report the viewer's current startup state +function startup.state() + return startup._state +end + +-- error if script is called before specified state string name +function startup.ensure(state) + if startup.before(startup.state(), state) then + -- tell error() to pretend this error was thrown by our caller + error('must not be called before startup state ' .. state, 2) + end +end + +-- block calling fiber until viewer has reached state with specified string name +function startup.wait(state) + dbg('startup.wait(%q)', state) + while startup.before(startup.state(), state) do + local item = waitfor:wait() + dbg('startup.wait(%q) sees %s', state, item) + end +end + +return startup + diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index c375a2abc7..c2d16d4f88 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -1,10 +1,16 @@ -XML_FILE_PATH = "luafloater_demo.xml" +XML_FILE_PATH = LL.source_dir() .. "/luafloater_demo.xml" + +scriptparts = string.split(LL.source_path(), '/') +scriptname = scriptparts[#scriptparts] +print('Running ' .. scriptname) leap = require 'leap' fiber = require 'fiber' +startup = require 'startup' --event pump for sending actions to the floater -COMMAND_PUMP_NAME = "" +local COMMAND_PUMP_NAME = "" +local reqid --table of floater UI events event_list=leap.request("LLFloaterReg", {op="getFloaterEvents"}).events @@ -41,24 +47,29 @@ function handleEvents(event_data) end elseif event_data.event == _event("floater_close") then LL.print_warning("Floater was closed") - leap.done() + return false end + return true end +startup.wait('STATE_LOGIN_WAIT') local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --sign for additional events for defined control {<control_name>= {action1, action2, ...}} key.extra_events={show_time_lbl = {_event("right_mouse_down"), _event("double_click")}} -COMMAND_PUMP_NAME = leap.request("LLFloaterReg", key).command_name +local resp = leap.request("LLFloaterReg", key) +COMMAND_PUMP_NAME = resp.command_name +reqid = resp.reqid catch_events = leap.WaitFor:new(-1, "all_events") function catch_events:filter(pump, data) - return data + if data.reqid == reqid then + return data + end end function process_events(waitfor) event_data = waitfor:wait() - while event_data do - handleEvents(event_data) + while event_data and handleEvents(event_data) do event_data = waitfor:wait() end end diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index 6d4a8e0cad..a907eb2e90 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -1,11 +1,17 @@ -XML_FILE_PATH = "luafloater_gesture_list.xml" +XML_FILE_PATH = LL.source_dir() .. "/luafloater_gesture_list.xml" + +scriptparts = string.split(LL.source_path(), '/') +scriptname = scriptparts[#scriptparts] +print('Running ' .. scriptname) leap = require 'leap' fiber = require 'fiber' LLGesture = require 'LLGesture' +startup = require 'startup' --event pump for sending actions to the floater -COMMAND_PUMP_NAME = "" +local COMMAND_PUMP_NAME = "" +local reqid --table of floater UI events event_list=leap.request("LLFloaterReg", {op="getFloaterEvents"}).events @@ -22,9 +28,12 @@ end function handleEvents(event_data) if event_data.event == _event("floater_close") then - leap.done() - elseif event_data.event == _event("post_build") then + return false + end + + if event_data.event == _event("post_build") then COMMAND_PUMP_NAME = event_data.command_name + reqid = event_data.reqid gestures_uuid = LLGesture.getActiveGestures() local action_data = {} action_data.action = "add_list_element" @@ -40,8 +49,10 @@ function handleEvents(event_data) LLGesture.startGesture(event_data.value) end end + return true end +startup.wait('STATE_STARTED') local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} --receive additional events for defined control {<control_name>= {action1, action2, ...}} key.extra_events={gesture_list = {_event("double_click")}} @@ -49,13 +60,14 @@ handleEvents(leap.request("LLFloaterReg", key)) catch_events = leap.WaitFor:new(-1, "all_events") function catch_events:filter(pump, data) - return data + if data.reqid == reqid then + return data + end end function process_events(waitfor) event_data = waitfor:wait() - while event_data do - handleEvents(event_data) + while event_data and handleEvents(event_data) do event_data = waitfor:wait() end end -- cgit v1.2.3 From 7049485ebd0b997a097c12e094425d58db56e043 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Apr 2024 13:25:08 -0400 Subject: Fix std::filesystem::path - to - std::string conversions on Windows. On Windows, std::filesystem::path::value_type is wchar_t, not char -- so path::string_type is std::wstring, not std::string. So while Posix path instances implicitly convert to string, Windows path instances do not. Add explicit u8string() calls. Also add LL.abspath() Lua entry point to further facilitate finding a resource file relative to the calling Lua script. Use abspath() for both test_luafloater_demo.lua and test_luafloater_gesture_list.lua. --- indra/newview/scripts/lua/test_luafloater_demo.lua | 2 +- indra/newview/scripts/lua/test_luafloater_gesture_list.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index c2d16d4f88..ab638dcdd1 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -1,4 +1,4 @@ -XML_FILE_PATH = LL.source_dir() .. "/luafloater_demo.xml" +XML_FILE_PATH = LL.abspath("luafloater_demo.xml") scriptparts = string.split(LL.source_path(), '/') scriptname = scriptparts[#scriptparts] diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index a907eb2e90..3d9a9b0ad4 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -1,4 +1,4 @@ -XML_FILE_PATH = LL.source_dir() .. "/luafloater_gesture_list.xml" +XML_FILE_PATH = LL.abspath("luafloater_gesture_list.xml") scriptparts = string.split(LL.source_path(), '/') scriptname = scriptparts[#scriptparts] -- cgit v1.2.3 From b351888ed7d395279dfc022363e911d52ebdcc16 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 3 Apr 2024 14:26:34 +0300 Subject: Add RAII class for adding/erasing script entries; code clean up --- indra/newview/llfloaterluascripts.cpp | 7 ++----- indra/newview/llfloaterluascripts.h | 2 +- indra/newview/llluamanager.cpp | 4 +--- indra/newview/llluamanager.h | 18 +++++++++++++++++- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 87d2cf0c69..bd845a97d6 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -51,7 +51,7 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) BOOL LLFloaterLUAScripts::postBuild() { mScriptList = getChild<LLScrollListCtrl>("scripts_list"); - mScriptList->setRightMouseDownCallback(boost::bind(&LLFloaterLUAScripts::onScrollListRightClicked, this, _1, _2, _3)); + mScriptList->setRightMouseDownCallback([this](LLUICtrl *ctrl, S32 x, S32 y, MASK mask) { onScrollListRightClicked(ctrl, x, y);}); LLContextMenu *menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( "menu_lua_scripts.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); @@ -71,13 +71,11 @@ LLFloaterLUAScripts::~LLFloaterLUAScripts() menu->die(); mContextMenuHandle.markDead(); } - - delete mUpdateTimer; } void LLFloaterLUAScripts::draw() { - if (mUpdateTimer->hasExpired()) + if (mUpdateTimer->checkExpirationAndReset(REFRESH_INTERVAL)) { populateScriptList(); } @@ -103,7 +101,6 @@ void LLFloaterLUAScripts::populateScriptList() } mScriptList->setScrollPos(prev_pos); mScriptList->setSelectedByValue(prev_selected, true); - mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); } void LLFloaterLUAScripts::onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y) diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h index c8c9e7f020..548bbd10f6 100644 --- a/indra/newview/llfloaterluascripts.h +++ b/indra/newview/llfloaterluascripts.h @@ -44,7 +44,7 @@ private: void populateScriptList(); void onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y); - LLTimer* mUpdateTimer; + std::unique_ptr<LLTimer> mUpdateTimer; LLScrollListCtrl* mScriptList; std::string mTargetFolderPath; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 343c7c7459..d2b8ca3a94 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -179,8 +179,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // A script_result_fn will be called when LuaState::expr() completes. LLCoros::instance().launch(filename, [filename, result_cb, finished_cb]() { - std::string coro_name = LLCoros::getName(); - sScriptNames[coro_name] = filename; + ScriptObserver observer(LLCoros::getName(), filename); llifstream in_file; in_file.open(filename.c_str()); @@ -205,7 +204,6 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r result_cb(-1, msg); } } - sScriptNames.erase(coro_name); }); } diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 70728f958e..88467cbf84 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -40,6 +40,8 @@ class LuaState; class LLLUAmanager { + friend class ScriptObserver; + public: // Pass a callback with this signature to obtain the error message, if // any, from running a script or source string. Empty msg means success. @@ -81,7 +83,7 @@ public: static void runScriptOnLogin(); - static std::map<std::string, std::string> getScriptNames() { return sScriptNames; } + static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } private: static std::map<std::string, std::string> sScriptNames; @@ -104,4 +106,18 @@ class LLRequireResolver bool findModuleImpl(const std::string& absolutePath); void runModule(const std::string& desc, const std::string& code); }; + +// RAII class to guarantee that a script entry is erased even when coro is terminated +class ScriptObserver +{ + public: + ScriptObserver(const std::string &coro_name, const std::string &filename) : mCoroName(coro_name) + { + LLLUAmanager::sScriptNames[mCoroName] = filename; + } + ~ScriptObserver() { LLLUAmanager::sScriptNames.erase(mCoroName); } + + private: + std::string mCoroName; +}; #endif -- cgit v1.2.3 From cc8d71c18c124138e76e85e663498d2ee9776b3c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 2 Apr 2024 23:11:29 +0300 Subject: viewer#1114 Expose max impostors setting in basic graphics preferences --- indra/newview/llfloaterpreference.cpp | 44 ++++++++++++++++++++++ indra/newview/llfloaterpreference.h | 4 ++ .../llfloaterpreferencesgraphicsadvanced.cpp | 5 ++- .../newview/llfloaterpreferencesgraphicsadvanced.h | 1 + .../en/floater_preferences_graphics_advanced.xml | 2 +- .../default/xui/en/panel_preferences_graphics1.xml | 40 ++++++++++++++++++-- 6 files changed, 90 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index aa723eb3a8..a5d3a34322 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -328,6 +328,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreference::updateMaxNonImpostors, this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreference::onRenderOptionEnable, this)); mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); @@ -359,6 +360,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); + mImpostorsChangedSignal = gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreference::updateIndirectMaxNonImpostors, this, _2)); mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); @@ -528,6 +530,7 @@ LLFloaterPreference::~LLFloaterPreference() { LLConversationLog::instance().removeObserver(this); mComplexityChangedSignal.disconnect(); + mImpostorsChangedSignal.disconnect(); } void LLFloaterPreference::draw() @@ -1283,6 +1286,9 @@ void LLAvatarComplexityControls::setIndirectMaxArc() void LLFloaterPreference::refresh() { LLPanel::refresh(); + setMaxNonImpostorsText( + gSavedSettings.getU32("RenderAvatarMaxNonImpostors"), + getChild<LLTextBox>("IndirectMaxNonImpostorsText", true)); LLAvatarComplexityControls::setText( gSavedSettings.getU32("RenderAvatarMaxComplexity"), getChild<LLTextBox>("IndirectMaxComplexityText", true)); @@ -1561,6 +1567,44 @@ void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_bo } } +void LLFloaterPreference::updateMaxNonImpostors() +{ + // Called when the IndirectMaxNonImpostors control changes + // Responsible for fixing the slider label (IndirectMaxNonImpostorsText) and setting RenderAvatarMaxNonImpostors + LLSliderCtrl* ctrl = getChild<LLSliderCtrl>("IndirectMaxNonImpostors", true); + U32 value = ctrl->getValue().asInteger(); + + if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) + { + value = 0; + } + gSavedSettings.setU32("RenderAvatarMaxNonImpostors", value); + LLVOAvatar::updateImpostorRendering(value); // make it effective immediately + setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); +} + +void LLFloaterPreference::updateIndirectMaxNonImpostors(const LLSD& newvalue) +{ + U32 value = newvalue.asInteger(); + if ((value != 0) && (value != gSavedSettings.getU32("IndirectMaxNonImpostors"))) + { + gSavedSettings.setU32("IndirectMaxNonImpostors", value); + } + setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); +} + +void LLFloaterPreference::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) +{ + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%d", value)); + } +} + void LLFloaterPreference::updateMaxComplexity() { // Called when the IndirectMaxComplexity control changes diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 04ac87364d..936808d58e 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -210,6 +210,9 @@ private: void onDeleteTranscripts(); void onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response); void updateDeleteTranscriptsButton(); + void updateMaxNonImpostors(); + void updateIndirectMaxNonImpostors(const LLSD& newvalue); + void setMaxNonImpostorsText(U32 value, LLTextBox* text_box); void updateMaxComplexity(); void updateComplexityText(); static bool loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map); @@ -233,6 +236,7 @@ private: std::unique_ptr< ll::prefs::SearchData > mSearchData; bool mSearchDataDirty; + boost::signals2::connection mImpostorsChangedSignal; boost::signals2::connection mComplexityChangedSignal; void onUpdateFilterTerm( bool force = false ); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp index a91f0ec060..d59113144e 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -52,13 +52,14 @@ LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const L mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2)); mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2)); - gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors, this, _2)); + mImpostorsChangedSignal = gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors, this, _2)); } LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced() { mComplexityChangedSignal.disconnect(); mLODFactorChangedSignal.disconnect(); + mImpostorsChangedSignal.disconnect(); } BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() @@ -221,8 +222,8 @@ void LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors(const LL if ((value != 0) && (value != gSavedSettings.getU32("IndirectMaxNonImpostors"))) { gSavedSettings.setU32("IndirectMaxNonImpostors", value); - setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); } + setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); } void LLFloaterPreferenceGraphicsAdvanced::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.h b/indra/newview/llfloaterpreferencesgraphicsadvanced.h index 2c92f3dbf1..80e35368eb 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.h +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.h @@ -60,6 +60,7 @@ protected: void onBtnOK(const LLSD& userdata); void onBtnCancel(const LLSD& userdata); + boost::signals2::connection mImpostorsChangedSignal; boost::signals2::connection mComplexityChangedSignal; boost::signals2::connection mLODFactorChangedSignal; }; diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index bc237322af..d993b1f990 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -170,7 +170,7 @@ height="16" increment="1" initial_value="12" - label="Max. # of non-impostors:" + label="Max. # animated avatars:" label_width="185" layout="topleft" left="30" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 8a9d3b755e..5d1ddc2e69 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -210,26 +210,60 @@ increment="8" initial_value="160" label="Draw distance:" - label_width="90" + label_width="187" layout="topleft" left="30" min_val="64" max_val="512" name="DrawDistance" top_delta="40" - width="330" /> + width="427" /> <text type="string" length="1" follows="left|top" height="12" layout="topleft" - left_delta="330" + left_delta="427" name="DrawDistanceMeterText2" top_delta="0" width="128"> m </text> + <slider + control_name="IndirectMaxNonImpostors" + name="IndirectMaxNonImpostors" + decimal_digits="0" + increment="1" + initial_value="12" + show_text="false" + min_val="1" + max_val="66" + label="Maximum number of animated avatars:" + follows="left|top" + layout="topleft" + height="16" + label_width="240" + left="30" + top_delta="40" + width="393"> + <slider.commit_callback + function="Pref.UpdateIndirectMaxNonImpostors" + parameter="IndirectNonImpostorsText" /> + </slider> + <text + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + top_delta="0" + left_delta="397" + text_readonly_color="LabelDisabledColor" + name="IndirectMaxNonImpostorsText" + width="65"> + 0 + </text> <button height="23" -- cgit v1.2.3 From e399b02e3306a249cb161f07cac578d3f2617bab Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 3 Apr 2024 12:31:43 -0400 Subject: Introduce fsyspath subclass of std::filesystem::path. Our std::strings are UTF-8 encoded, so conversion from std::string to std::filesystem::path must use UTF-8 decoding. The native Windows std::filesystem::path constructor and assignment operator accepting std::string use "native narrow encoding," which mangles path strings containing UTF-8 encoded non-ASCII characters. fsyspath's std::string constructor and assignment operator explicitly engage std::filesystem::u8path() to handle encoding. u8path() is deprecated in C++20, but once we adapt fsyspath's conversion to C++20 conventions, consuming code need not be modified. --- indra/newview/llluamanager.cpp | 8 ++++---- indra/newview/llluamanager.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 9059db9967..82be85a153 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -28,6 +28,7 @@ #include "llviewerprecompiledheaders.h" #include "llluamanager.h" +#include "fsyspath.h" #include "llcoros.h" #include "llerror.h" #include "lleventcoro.h" @@ -37,7 +38,6 @@ #include "stringize.h" #include <boost/algorithm/string/replace.hpp> -#include <filesystem> #include "luau/luacode.h" #include "luau/lua.h" @@ -314,7 +314,7 @@ void LLRequireResolver::resolveRequire(lua_State *L, std::string path) } LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : - mPathToResolve(std::filesystem::path(path).lexically_normal()), + mPathToResolve(fsyspath(path).lexically_normal()), L(L) { mSourceDir = lluau::source_path(L).parent_path(); @@ -377,12 +377,12 @@ void LLRequireResolver::findModule() fail(); } - std::vector<std::filesystem::path> lib_paths + std::vector<fsyspath> lib_paths { gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"), #ifdef LL_TEST // Build-time tests don't have the app bundle - use source tree. - std::filesystem::path(__FILE__).parent_path() / "scripts" / "lua", + fsyspath(__FILE__).parent_path() / "scripts" / "lua", #endif }; diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index bd581376b4..3c00450179 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -27,9 +27,9 @@ #ifndef LL_LLLUAMANAGER_H #define LL_LLLUAMANAGER_H +#include "fsyspath.h" #include "llcoros.h" #include "llsd.h" -#include <filesystem> #include <functional> #include <string> #include <utility> // std::pair @@ -89,8 +89,8 @@ class LLRequireResolver static void resolveRequire(lua_State *L, std::string path); private: - std::filesystem::path mPathToResolve; - std::filesystem::path mSourceDir; + fsyspath mPathToResolve; + fsyspath mSourceDir; LLRequireResolver(lua_State *L, const std::string& path); -- cgit v1.2.3 From 0f2d261bbfa7a827290f3acb7e6f71e29eed3a1b Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Wed, 3 Apr 2024 21:24:05 +0200 Subject: Proper casing for Lualibs (or case sensitive filesystems do not agree with the filename) --- indra/newview/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b26ce7d06d..d98b45e471 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -48,7 +48,7 @@ include(VulkanGltf) include(ZLIBNG) include(URIPARSER) include(LLPrimitive) -include(lualibs) +include(Lualibs) if (NOT HAVOK_TPV) # When using HAVOK_TPV, the library is precompiled, so no need for this @@ -2379,4 +2379,3 @@ if (LL_TESTS) endif (LL_TESTS) check_message_template(${VIEWER_BINARY_NAME}) - -- cgit v1.2.3 From 57d423745fd1d3d0ea6a0c69b869a20c27e27fc5 Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn <nicky.dasmijn@posteo.nl> Date: Fri, 5 Apr 2024 19:25:02 +0200 Subject: Linux viewer (ReleaseOS) resurrection (#1099) Co-authored-by: AiraYumi <aira.youme@airanyumi.net> --- indra/newview/CMakeLists.txt | 1 - indra/newview/llappviewerlinux.cpp | 359 ++++++++++++--------- indra/newview/llappviewerlinux.h | 28 -- indra/newview/llappviewerlinux_api.h | 143 -------- indra/newview/llappviewerlinux_api.xml | 14 - indra/newview/llappviewerlinux_api_dbus.cpp | 126 -------- indra/newview/llappviewerlinux_api_dbus.h | 44 --- .../newview/llappviewerlinux_api_dbus_syms_raw.inc | 9 - indra/newview/llchathistory.cpp | 2 +- indra/newview/llconversationloglist.cpp | 7 +- indra/newview/lldirpicker.cpp | 36 +++ indra/newview/lldirpicker.h | 2 + indra/newview/llface.cpp | 1 - indra/newview/llfasttimerview.cpp | 14 +- indra/newview/llfilepicker.h | 14 + indra/newview/llfloaterregioninfo.cpp | 9 +- indra/newview/llhttpretrypolicy.cpp | 5 +- indra/newview/llinventoryfilter.cpp | 10 +- indra/newview/llinventorygallerymenu.cpp | 2 +- indra/newview/llmanip.cpp | 3 - indra/newview/llmediadataclient.cpp | 4 +- indra/newview/llpanelface.cpp | 3 +- indra/newview/llpanelface.h | 5 +- indra/newview/lltoastalertpanel.h | 10 +- indra/newview/llviewerstats.cpp | 7 + indra/newview/llviewerstatsrecorder.cpp | 22 +- indra/newview/llvoicevivox.cpp | 2 +- indra/newview/llvovolume.cpp | 3 +- indra/newview/llxmlrpctransaction.cpp | 2 +- indra/newview/viewer_manifest.py | 206 +++++++----- 30 files changed, 443 insertions(+), 650 deletions(-) delete mode 100644 indra/newview/llappviewerlinux_api.h delete mode 100644 indra/newview/llappviewerlinux_api.xml delete mode 100644 indra/newview/llappviewerlinux_api_dbus.cpp delete mode 100644 indra/newview/llappviewerlinux_api_dbus.h delete mode 100644 indra/newview/llappviewerlinux_api_dbus_syms_raw.inc (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 355f35c558..f359bebb17 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1432,7 +1432,6 @@ if (LINUX) PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" ) - LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") endif (LINUX) diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 9f58f90326..0e7610ebf3 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -40,17 +40,57 @@ #include <exception> -#if LL_DBUS_ENABLED -# include "llappviewerlinux_api_dbus.h" - -// regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h: -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#undef g_return_if_fail -#define g_return_if_fail(COND) llg_return_if_fail(COND) -// The generated API -# include "llappviewerlinux_api.h" +#include <gio/gio.h> +#include <resolv.h> + +#if (__GLIBC__*1000 + __GLIBC_MINOR__) >= 2034 +extern "C" +{ + int __res_nquery(res_state statep, + const char *dname, int qclass, int type, + unsigned char *answer, int anslen) + { + return res_nquery( statep, dname, qclass, type, answer, anslen ); + } + + int __dn_expand(const unsigned char *msg, + const unsigned char *eomorig, + const unsigned char *comp_dn, char *exp_dn, + int length) + { + return dn_expand( msg,eomorig,comp_dn,exp_dn,length); + } +} +#endif + +#if LL_SEND_CRASH_REPORTS +#include "breakpad/client/linux/handler/exception_handler.h" +#include "breakpad/common/linux/http_upload.h" +#include "lldir.h" +#include "../llcrashlogger/llcrashlogger.h" +#include "jsoncpp/reader.h" // JSON + #endif +#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" +#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" +#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" + +static const char * DBUS_SERVER = "<node name=\"/com/secondlife/ViewerAppAPI\">\n" + " <interface name=\"com.secondlife.ViewerAppAPI\">\n" + " <annotation name=\"org.freedesktop.DBus.GLib.CSymbol\" value=\"viewer_app_api\"/>\n" + " <method name=\"GoSLURL\">\n" + " <annotation name=\"org.freedesktop.DBus.GLib.CSymbol\" value=\"dispatchSLURL\"/>\n" + " <arg type=\"s\" name=\"slurl\" direction=\"in\" />\n" + " </method>\n" + " </interface>\n" + "</node>"; + +typedef struct +{ + GObject parent; +} ViewerAppAPI; + namespace { int gArgC = 0; @@ -81,6 +121,8 @@ int main( int argc, char **argv ) // install unexpected exception handler gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); + unsetenv( "LD_PRELOAD" ); // <FS:ND/> Get rid of any preloading, we do not want this to happen during startup of plugins. + bool ok = viewer_app_ptr->init(); if(!ok) { @@ -114,22 +156,75 @@ LLAppViewerLinux::~LLAppViewerLinux() { } -bool LLAppViewerLinux::init() +#if LL_SEND_CRASH_REPORTS +std::string gCrashLogger; +std::string gVersion; +std::string gBugsplatDB; +std::string gCrashBehavior; + +static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { - // g_thread_init() must be called before *any* use of glib, *and* - // before any mutexes are held, *and* some of our third-party - // libraries likes to use glib functions; in short, do this here - // really early in app startup! - if (!g_thread_supported ()) g_thread_init (NULL); + if( fork() == 0 ) + execl( gCrashLogger.c_str(), gCrashLogger.c_str(), descriptor.path(), gVersion.c_str(), gBugsplatDB.c_str(), gCrashBehavior.c_str(), nullptr ); + return succeeded; +} + +void setupBreadpad() +{ + std::string build_data_fname(gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); + gCrashLogger = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "linux-crash-logger.bin"); + + llifstream inf(build_data_fname.c_str()); + if(!inf.is_open()) + { + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; + return; + } + + Json::Reader reader; + Json::Value build_data; + if(!reader.parse(inf, build_data, false)) + { + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " + << reader.getFormatedErrorMessages() << LL_ENDL; + return; + } + + Json::Value BugSplat_DB = build_data["BugSplat DB"]; + if(!BugSplat_DB) + { + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname + << "'" << LL_ENDL; + return; + } + gVersion = STRINGIZE( + LL_VIEWER_VERSION_MAJOR << '.' << LL_VIEWER_VERSION_MINOR << '.' << LL_VIEWER_VERSION_PATCH + << '.' << LL_VIEWER_VERSION_BUILD); + gBugsplatDB = BugSplat_DB.asString(); + + LL_INFOS("BUGSPLAT") << "Initializing with crash logger: " << gCrashLogger << " database: " << gBugsplatDB << " version: " << gVersion << LL_ENDL; + google_breakpad::MinidumpDescriptor *descriptor = new google_breakpad::MinidumpDescriptor(gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "")); + google_breakpad::ExceptionHandler *eh = new google_breakpad::ExceptionHandler(*descriptor, NULL, dumpCallback, NULL, true, -1); +} +#endif + +bool LLAppViewerLinux::init() +{ bool success = LLAppViewer::init(); #if LL_SEND_CRASH_REPORTS - if (success) - { - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - } + S32 nCrashSubmitBehavior = gCrashSettings.getS32("CrashSubmitBehavior"); + + // For the first version we just consider always send and create a nice dialog for CRASH_BEHAVIOR_ASK later. + if (success && nCrashSubmitBehavior != CRASH_BEHAVIOR_NEVER_SEND ) + { + if( nCrashSubmitBehavior == CRASH_BEHAVIOR_ASK ) + gCrashBehavior = "ask"; + else + gCrashBehavior = "send"; + setupBreadpad(); + } #endif return success; @@ -143,7 +238,7 @@ bool LLAppViewerLinux::restoreErrorTrap() } ///////////////////////////////////////// -#if LL_DBUS_ENABLED +#if LL_GLIB typedef struct { @@ -153,101 +248,77 @@ typedef struct static void viewerappapi_init(ViewerAppAPI *server); static void viewerappapi_class_init(ViewerAppAPIClass *klass); -/// - -// regrettable hacks to give us better runtime compatibility with older systems in general -static GType llg_type_register_static_simple_ONCE(GType parent_type, - const gchar *type_name, - guint class_size, - GClassInitFunc class_init, - guint instance_size, - GInstanceInitFunc instance_init, - GTypeFlags flags) -{ - static GTypeInfo type_info; - memset(&type_info, 0, sizeof(type_info)); - - type_info.class_size = class_size; - type_info.class_init = class_init; - type_info.instance_size = instance_size; - type_info.instance_init = instance_init; - - return g_type_register_static(parent_type, type_name, &type_info, flags); -} -#define llg_intern_static_string(S) (S) -#define g_intern_static_string(S) llg_intern_static_string(S) -#define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) - G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT); void viewerappapi_class_init(ViewerAppAPIClass *klass) { } -static bool dbus_server_init = false; - -void viewerappapi_init(ViewerAppAPI *server) +static void dispatchSLURL(gchar const *slurl) { - // Connect to the default DBUS, register our service/API. + LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; - if (!dbus_server_init) - { - GError *error = NULL; - - server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (server->connection) - { - lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info); - - lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server)); - - DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); + std::string url = slurl; + LLMediaCtrl* web = NULL; + const bool trusted_browser = false; + LLURLDispatcher::dispatch(url, "", web, trusted_browser); +} - guint request_name_ret_unused; - // akin to org_freedesktop_DBus_request_name - if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID)) - { - // total success. - dbus_server_init = true; - } - else - { - LL_WARNS() << "Unable to register service name: " << error->message << LL_ENDL; - } - - g_object_unref(serverproxy); - } - else - { - g_warning("Unable to connect to dbus: %s", error->message); - } +static void DoMethodeCall (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + LL_INFOS() << "DBUS message " << method_name << " from: " << sender << " interface: " << interface_name << LL_ENDL; + const gchar *slurl; - if (error) - g_error_free(error); - } + g_variant_get (parameters, "(&s)", &slurl); + dispatchSLURL(slurl); } -gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error) +GDBusNodeInfo *gBusNodeInfo = nullptr; +static const GDBusInterfaceVTable interface_vtable = + { + DoMethodeCall + }; +static void busAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - bool success = false; + auto id = g_dbus_connection_register_object(connection, + VIEWERAPI_PATH, + gBusNodeInfo->interfaces[0], + &interface_vtable, + NULL, /* user_data */ + NULL, /* user_data_free_func */ + NULL); /* GError** */ + g_assert (id > 0); +} - LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; +static void nameAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ +} - std::string url = slurl; - LLMediaCtrl* web = NULL; - const bool trusted_browser = false; - if (LLURLDispatcher::dispatch(url, "", web, trusted_browser)) - { - // bring window to foreground, as it has just been "launched" from a URL - // todo: hmm, how to get there from here? - //xxx->mWindow->bringToFront(); - success = true; - } +static void nameLost(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ - *success_rtn = g_new (gboolean, 1); - (*success_rtn)[0] = (gboolean)success; +} +void viewerappapi_init(ViewerAppAPI *server) +{ + gBusNodeInfo = g_dbus_node_info_new_for_xml (DBUS_SERVER, NULL); + g_assert (gBusNodeInfo != NULL); + + g_bus_own_name(G_BUS_TYPE_SESSION, + VIEWERAPI_SERVICE, + G_BUS_NAME_OWNER_FLAGS_NONE, + busAcquired, + nameAcquired, + nameLost, + NULL, + NULL); - return TRUE; // the invokation succeeded, even if the actual dispatch didn't. } /// @@ -255,13 +326,6 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ //virtual bool LLAppViewerLinux::initSLURLHandler() { - if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) - { - return false; // failed - } - - g_type_init(); - //ViewerAppAPI *api_server = (ViewerAppAPI*) g_object_new(viewerappapi_get_type(), NULL); @@ -271,49 +335,49 @@ bool LLAppViewerLinux::initSLURLHandler() //virtual bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) { - if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) - { - return false; // failed - } + auto *pBus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, nullptr); - bool success = false; - DBusGConnection *bus; - GError *error = NULL; + if( !pBus ) + { + LL_WARNS() << "Getting dbus failed." << LL_ENDL; + return false; + } - g_type_init(); - - bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (bus) - { - gboolean rtn = FALSE; - DBusGProxy *remote_object = - lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE); + auto pProxy = g_dbus_proxy_new_sync(pBus, G_DBUS_PROXY_FLAGS_NONE, nullptr, + VIEWERAPI_SERVICE, VIEWERAPI_PATH, + VIEWERAPI_INTERFACE, nullptr, nullptr); - if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error, - G_TYPE_STRING, url.c_str(), G_TYPE_INVALID, - G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID)) - { - success = rtn; - } - else - { - LL_INFOS() << "Call-out to other instance failed (perhaps not running): " << error->message << LL_ENDL; - } + if( !pProxy ) + { + LL_WARNS() << "Cannot create new dbus proxy." << LL_ENDL; + g_object_unref( pBus ); + return false; + } - g_object_unref(G_OBJECT(remote_object)); - } - else - { - LL_WARNS() << "Couldn't connect to session bus: " << error->message << LL_ENDL; - } + auto *pArgs = g_variant_new( "(s)", url.c_str() ); + if( !pArgs ) + { + LL_WARNS() << "Cannot create new variant." << LL_ENDL; + g_object_unref( pBus ); + return false; + } - if (error) - g_error_free(error); - - return success; + auto pRes = g_dbus_proxy_call_sync(pProxy, + "GoSLURL", + pArgs, + G_DBUS_CALL_FLAGS_NONE, + -1, nullptr, nullptr); + + + + if( pRes ) + g_variant_unref( pRes ); + g_object_unref( pProxy ); + g_object_unref( pBus ); + return true; } -#else // LL_DBUS_ENABLED +#else // LL_GLIB bool LLAppViewerLinux::initSLURLHandler() { return false; // not implemented without dbus @@ -322,7 +386,7 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) { return false; // not implemented without dbus } -#endif // LL_DBUS_ENABLED +#endif // LL_GLIB void LLAppViewerLinux::initCrashReporting(bool reportFreeze) { @@ -338,15 +402,18 @@ void LLAppViewerLinux::initCrashReporting(bool reportFreeze) pid_str << LLApp::getPid(); std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); std::string appname = gDirUtilp->getExecutableFilename(); + std::string grid{ LLGridManager::getInstance()->getGridId() }; + std::string title{ LLAppViewer::instance()->getSecondLifeTitle() }; + std::string pidstr{ pid_str.str() }; // launch the actual crash logger const char * cmdargv[] = {cmd.c_str(), "-user", - (char*)LLGridManager::getInstance()->getGridId().c_str(), + grid.c_str(), "-name", - LLAppViewer::instance()->getSecondLifeTitle().c_str(), + title.c_str(), "-pid", - pid_str.str().c_str(), + pidstr.c_str(), "-dumpdir", logdir.c_str(), "-procname", diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h index 0289c43043..abe62c9289 100644 --- a/indra/newview/llappviewerlinux.h +++ b/indra/newview/llappviewerlinux.h @@ -27,17 +27,6 @@ #ifndef LL_LLAPPVIEWERLINUX_H #define LL_LLAPPVIEWERLINUX_H -extern "C" { -# include <glib.h> -} - -#if LL_DBUS_ENABLED -extern "C" { -# include <glib-object.h> -# include <dbus/dbus-glib.h> -} -#endif - #ifndef LL_LLAPPVIEWER_H #include "llappviewer.h" #endif @@ -70,21 +59,4 @@ protected: virtual bool sendURLToOtherInstance(const std::string& url); }; -#if LL_DBUS_ENABLED -typedef struct -{ - GObject parent; - DBusGConnection *connection; -} ViewerAppAPI; - -extern "C" { - gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error); -} - -#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" -#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" -#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" - -#endif // LL_DBUS_ENABLED - #endif // LL_LLAPPVIEWERLINUX_H diff --git a/indra/newview/llappviewerlinux_api.h b/indra/newview/llappviewerlinux_api.h deleted file mode 100644 index 5d5fcaa3d6..0000000000 --- a/indra/newview/llappviewerlinux_api.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ -/** - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef __dbus_glib_marshal_viewerapp_MARSHAL_H__ -#define __dbus_glib_marshal_viewerapp_MARSHAL_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_char (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* BOOLEAN:STRING,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.5XXD8T:1) */ -extern void dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); - - g_value_set_boolean (return_value, v_return); -} - -G_END_DECLS - -#endif /* __dbus_glib_marshal_viewerapp_MARSHAL_H__ */ - -#include <dbus/dbus-glib.h> -static const DBusGMethodInfo dbus_glib_viewerapp_methods[] = { - { (GCallback) viewer_app_api_GoSLURL, dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER, 0 }, -}; - -const DBusGObjectInfo dbus_glib_viewerapp_object_info = { - 0, - dbus_glib_viewerapp_methods, - 1, -"com.secondlife.ViewerAppAPI\0GoSLURL\0S\0slurl\0I\0s\0success_ret\0O\0F\0N\0b\0\0\0", -"\0", -"\0" -}; - diff --git a/indra/newview/llappviewerlinux_api.xml b/indra/newview/llappviewerlinux_api.xml deleted file mode 100644 index fac35b7adc..0000000000 --- a/indra/newview/llappviewerlinux_api.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> - -<!-- dbus-binding-tool -mode=glib-server llappviewerlinux_api.xml -prefix=viewerapp -output=llappviewerlinux_api.h --> - -<node name="/com/secondlife/ViewerAppAPI"> - <interface name="com.secondlife.ViewerAppAPI"> - <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="viewer_app_api"/> - <method name="GoSLURL"> - <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="viewer_app_api_GoSLURL"/> - <arg type="s" name="slurl" direction="in" /> - <arg type="b" name="success_ret" direction="out" /> - </method> - </interface> -</node> diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp deleted file mode 100644 index 6ac30bd9b8..0000000000 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file llappviewerlinux_api_dbus.cpp - * @brief dynamic DBus symbol-grabbing code - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if LL_DBUS_ENABLED - -#include "linden_common.h" - -extern "C" { -#include <dbus/dbus-glib.h> - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#define DEBUGMSG(...) do { LL_DEBUGS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) -#define INFOMSG(...) do { LL_INFOS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) -#define WARNMSG(...) do { LL_WARNS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) RTN (*ll##DBUSSYM)(__VA_ARGS__) = NULL -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymDBUSDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL; - -bool grab_dbus_syms(std::string dbus_dso_name) -{ - if (sSymsGrabbed) - { - // already have grabbed good syms - return TRUE; - } - - bool sym_error = false; - bool rtn = false; - apr_status_t rv; - apr_dso_handle_t *sSymDBUSDSOHandle = NULL; - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0) - - //attempt to load the shared library - apr_pool_create(&sSymDBUSDSOMemoryPool, NULL); - - if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle, - dbus_dso_name.c_str(), - sSymDBUSDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", dbus_dso_name.c_str()); - -#include "llappviewerlinux_api_dbus_syms_raw.inc" - - if ( sSymDBUSDSOHandle ) - { - sSymDBUSDSOHandleG = sSymDBUSDSOHandle; - sSymDBUSDSOHandle = NULL; - } - - rtn = !sym_error; - } - else - { - INFOMSG("Couldn't load DSO: %s", dbus_dso_name.c_str()); - rtn = false; // failure - } - - if (sym_error) - { - WARNMSG("Failed to find necessary symbols in DBUS-GLIB libraries."); - } -#undef LL_DBUS_SYM - - sSymsGrabbed = rtn; - return rtn; -} - - -void ungrab_dbus_syms() -{ - // should be safe to call regardless of whether we've - // actually grabbed syms. - - if ( sSymDBUSDSOHandleG ) - { - apr_dso_unload(sSymDBUSDSOHandleG); - sSymDBUSDSOHandleG = NULL; - } - - if ( sSymDBUSDSOMemoryPool ) - { - apr_pool_destroy(sSymDBUSDSOMemoryPool); - sSymDBUSDSOMemoryPool = NULL; - } - - // NULL-out all of the symbols we'd grabbed -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0) -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - - sSymsGrabbed = false; -} - -#endif // LL_DBUS_ENABLED diff --git a/indra/newview/llappviewerlinux_api_dbus.h b/indra/newview/llappviewerlinux_api_dbus.h deleted file mode 100644 index 3eee25b53d..0000000000 --- a/indra/newview/llappviewerlinux_api_dbus.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file llappviewerlinux_api_dbus.h - * @brief DBus-glib symbol handling - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#if LL_DBUS_ENABLED - -extern "C" { -#include <dbus/dbus-glib.h> -} - -#define DBUSGLIB_DYLIB_DEFAULT_NAME "libdbus-glib-1.so.2" - -bool grab_dbus_syms(std::string dbus_dso_name); -void ungrab_dbus_syms(); - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) extern RTN (*ll##DBUSSYM)(__VA_ARGS__) -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -#endif // LL_DBUS_ENABLED diff --git a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc b/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc deleted file mode 100644 index c0548e2fba..0000000000 --- a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc +++ /dev/null @@ -1,9 +0,0 @@ - -// required symbols to grab -LL_DBUS_SYM(true, dbus_g_bus_get, DBusGConnection*, DBusBusType, GError**); -LL_DBUS_SYM(true, dbus_g_proxy_new_for_name, DBusGProxy*, DBusGConnection*, const char *, const char*, const char*); -LL_DBUS_SYM(true, dbus_g_proxy_call, gboolean, DBusGProxy*, const char*, GError**, GType, ...); -LL_DBUS_SYM(true, dbus_g_object_type_install_info, void, GType, const DBusGObjectInfo*); -LL_DBUS_SYM(true, dbus_g_connection_register_g_object, void, DBusGConnection*, const char*, GObject*); - -// optional symbols to grab diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index b9bf432581..eddae953a7 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1190,7 +1190,7 @@ LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); if (header) header->setup(chat, style_params, args); - return header; + return header; } void LLChatHistory::onClickMoreText() diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 97b16a5e93..e027ddaeb0 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -93,9 +93,10 @@ BOOL LLConversationLogList::handleRightMouseDown(S32 x, S32 y, MASK mask) LLToggleableMenu* context_menu = mContextMenu.get(); { context_menu->buildDrawLabels(); - if (context_menu && size()) - context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, context_menu, x, y); + if (context_menu && size()) + context_menu->updateParent(LLMenuGL::sMenuContainer); + + LLMenuGL::showPopup(this, context_menu, x, y); } return handled; diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 01790ad19e..e541d2ab00 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -41,6 +41,10 @@ # include "llfilepicker.h" #endif +#ifdef LL_FLTK + #include "FL/Fl.H" + #include "FL/Fl_Native_File_Chooser.H" +#endif // // Globals // @@ -193,20 +197,28 @@ LLDirPicker::LLDirPicker() : mFileName(NULL), mLocked(false) { +#ifndef LL_FLTK mFilePicker = new LLFilePicker(); +#endif reset(); } LLDirPicker::~LLDirPicker() { +#ifndef LL_FLTK delete mFilePicker; +#endif } void LLDirPicker::reset() { +#ifndef LL_FLTK if (mFilePicker) mFilePicker->reset(); +#else + mDir = ""; +#endif } BOOL LLDirPicker::getDir(std::string* filename, bool blocking) @@ -219,6 +231,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) return FALSE; } +#ifndef LL_FLTK #if !LL_MESA_HEADLESS if (mFilePicker) @@ -237,15 +250,38 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) #endif // !LL_MESA_HEADLESS return FALSE; +#else + gViewerWindow->getWindow()->beforeDialog(); + Fl_Native_File_Chooser flDlg; + flDlg.title(LLTrans::getString("choose_the_directory").c_str()); + flDlg.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY ); + int res = flDlg.show(); + gViewerWindow->getWindow()->afterDialog(); + if( res == 0 ) + { + char const *pDir = flDlg.filename(0); + if( pDir ) + mDir = pDir; + } + else if( res == -1 ) + { + LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL; + } + return !mDir.empty(); +#endif } std::string LLDirPicker::getDirName() { +#ifndef LL_FLTK if (mFilePicker) { return mFilePicker->getFirstFile(); } return ""; +#else + return mDir; +#endif } #else // not implemented diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 52febe4523..a1571bcb16 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -80,8 +80,10 @@ private: #if LL_LINUX || LL_DARWIN // On Linux we just implement LLDirPicker on top of LLFilePicker +#ifndef LL_FLTK LLFilePicker *mFilePicker; #endif +#endif std::string* mFileName; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index c1776705f9..b6405df1ff 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -839,7 +839,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, //VECTORIZE THIS LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); - LLVector4a new_extents[2]; llassert(less_than_max_mag(face.mExtents[0])); llassert(less_than_max_mag(face.mExtents[1])); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 5b8ca6c49c..a7998f6e9e 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -947,7 +947,7 @@ void LLFastTimerView::printLineStats() { std::string legend_stat; bool first = true; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -969,7 +969,7 @@ void LLFastTimerView::printLineStats() std::string timer_stat; first = true; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -1046,7 +1046,7 @@ void LLFastTimerView::drawLineGraph() F32Seconds cur_max(0); U32 cur_max_calls = 0; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -1195,8 +1195,8 @@ void LLFastTimerView::drawLegend() S32 scroll_offset = 0; // element's y offset from top of the inner scroll's rect ft_display_idx.clear(); std::map<BlockTimerStatHandle*, S32> display_line; - for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != block_timer_tree_df_iterator_t(); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + it != LLTrace::end_block_timer_tree_df(); ++it) { BlockTimerStatHandle* idp = (*it); @@ -1311,8 +1311,8 @@ void LLFastTimerView::generateUniqueColors() F32 hue = 0.f; - for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != block_timer_tree_df_iterator_t(); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + it != LLTrace::end_block_timer_tree_df(); ++it) { BlockTimerStatHandle* idp = (*it); diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 38daff9937..5686627776 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -33,6 +33,12 @@ #ifndef LL_LLFILEPICKER_H #define LL_LLFILEPICKER_H +#if LL_FLTK + #if LL_GTK + #undef LL_GTK + #endif +#endif + #include "stdtypes.h" #if LL_DARWIN @@ -58,6 +64,7 @@ extern "C" { // mostly for Linux, possible on others #if LL_GTK # include "gtk/gtk.h" +#error "Direct use of GTK is deprecated" #endif // LL_GTK } @@ -192,6 +199,13 @@ private: // we also remember the extension of the last added file. std::string mCurrentExtension; #endif +#if LL_FLTK + enum EType + { + eSaveFile, eOpenFile, eOpenMultiple + }; + bool openFileDialog( int32_t filter, bool blocking, EType aType ); +#endif std::vector<std::string> mFiles; S32 mCurrentFile; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index d4eb40ff92..fdfc5b08cb 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -3850,15 +3850,14 @@ void LLPanelRegionEnvironment::onChkAllowOverride(bool value) mAllowOverrideRestore = mAllowOverride; mAllowOverride = value; - std::string notification("EstateParcelEnvironmentOverride"); if (LLPanelEstateInfo::isLindenEstate()) notification = "ChangeLindenEstate"; - LLSD args; - args["ESTATENAME"] = LLEstateInfoModel::instance().getName(); - LLNotification::Params params(notification); - params.substitutions(args); + LLSD args; + args["ESTATENAME"] = LLEstateInfoModel::instance().getName(); + LLNotification::Params params(notification); + params.substitutions(args); params.functor.function([this](const LLSD& notification, const LLSD& response) { confirmUpdateEstateEnvironment(notification, response); }); if (!value || LLPanelEstateInfo::isLindenEstate()) diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp index 6a2daeeb90..1f6ad85be7 100644 --- a/indra/newview/llhttpretrypolicy.cpp +++ b/indra/newview/llhttpretrypolicy.cpp @@ -91,14 +91,14 @@ void LLAdaptiveRetryPolicy::onSuccess() void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) { - F32 retry_header_time; + F32 retry_header_time{}; bool has_retry_header_time = getRetryAfter(headers,retry_header_time); onFailureCommon(status, has_retry_header_time, retry_header_time); } void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response) { - F32 retry_header_time; + F32 retry_header_time{}; const LLCore::HttpHeaders::ptr_t headers = response->getHeaders(); bool has_retry_header_time = getRetryAfter(headers,retry_header_time); onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time); @@ -184,4 +184,3 @@ bool LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(const std::string& retry_a return true; } - diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 7b4283e94d..6091488c53 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -621,13 +621,13 @@ bool LLInventoryFilter::checkAgainstSearchVisibility(const LLFolderViewModelItem if (listener->isItemInOutfits() && ((mFilterOps.mSearchVisibility & VISIBILITY_OUTFITS) == 0)) return FALSE; - if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0)) - return FALSE; + if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0)) + return FALSE; - if (!listener->isAgentInventory() && ((mFilterOps.mSearchVisibility & VISIBILITY_LIBRARY) == 0)) - return FALSE; + if (!listener->isAgentInventory() && ((mFilterOps.mSearchVisibility & VISIBILITY_LIBRARY) == 0)) + return FALSE; - return TRUE; + return TRUE; } const std::string& LLInventoryFilter::getFilterSubString(BOOL trim) const diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 5f4b816b99..bfa87a9834 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -564,7 +564,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men items.push_back(std::string("Copy Asset UUID")); items.push_back(std::string("Copy Separator")); - bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType()); + bool is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType()); if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308 || (! ( is_full_perm_item || gAgent.isGodlike()))) { diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index feb691520f..98c1019f03 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -568,9 +568,6 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const std::string gGL.scalef(inv_zoom_amt, inv_zoom_amt, inv_zoom_amt); } - LLColor4 shadow_color = LLColor4::black; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f; - if (fractional_portion != 0) { fraction_string = llformat("%c%02d%s", LLResMgr::getInstance()->getDecimalPoint(), fractional_portion, suffix.c_str()); diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index d3b981e205..b0953f929c 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -204,7 +204,7 @@ bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end()) return true; - return false; + return false; } void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) @@ -829,7 +829,7 @@ bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &ob if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end()) return true; - return false; + return false; } void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index a527ebe47f..a72d7f2773 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -5229,7 +5229,7 @@ void LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face) { - LLGLenum image_format; + LLGLenum image_format{}; struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor<LLGLenum> { LLGLenum get(LLViewerObject* object, S32 te_index) @@ -5495,4 +5495,3 @@ void LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identic } max_diff_repeats_func; identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats ); } - diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index a64b85815f..2c466d4698 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -395,7 +395,7 @@ private: ReturnType (LLMaterial::* const MaterialGetFunc)() const > static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType()) { - DataType data_value; + DataType data_value{}; struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType> { GetTEMaterialVal(DataType default_value) : _default(default_value) {} @@ -428,7 +428,7 @@ private: ReturnType (LLTextureEntry::* const TEGetFunc)() const > static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType()) { - DataType data_value; + DataType data_value {}; struct GetTEVal : public LLSelectedTEGetFunctor<DataType> { GetTEVal(DataType default_value) : _default(default_value) {} @@ -621,4 +621,3 @@ public: }; #endif - diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h index bd34e40642..9f7be28277 100644 --- a/indra/newview/lltoastalertpanel.h +++ b/indra/newview/lltoastalertpanel.h @@ -82,14 +82,10 @@ private: struct ButtonData { - ButtonData() - : mWidth(0) - {} - - LLButton* mButton; + LLButton* mButton = nullptr; std::string mURL; - U32 mURLExternal; - S32 mWidth; + U32 mURLExternal = 0; + S32 mWidth = 0; }; std::vector<ButtonData> mButtonData; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 6ac94fe4c4..c1f4f858c1 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -67,6 +67,11 @@ #include "lluiusage.h" #include "lltranslate.h" +#if LL_LINUX +#pragma GCC diagnostic ignored "-Wunused-value" // Happens due to LL_DEBUGS("LogViewerStatsPacket"); Does that even do anything? +#endif + + // "Minimal Vulkan" to get max API Version // Calls @@ -827,6 +832,8 @@ void send_viewer_stats(bool include_preferences) LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; + + // <ND> Do those lines even do anything sane in regard of debug logging? LL_DEBUGS("LogViewerStatsPacket"); std::string filename("viewer_stats_packet.xml"); llofstream of(filename.c_str()); diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 6372679a07..aa55c9791e 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -154,26 +154,26 @@ void LLViewerStatsRecorder::recordCacheFullUpdate(LLViewerRegion::eCacheUpdateRe void LLViewerStatsRecorder::writeToLog( F32 interval ) { if (!mEnableStatsLogging || !mEnableStatsRecording) - { - return; - } + { + return; + } - size_t data_size = 0; - F64 delta_time = LLFrameTimer::getTotalSeconds() - mLastSnapshotTime; + size_t data_size = 0; + F64 delta_time = LLFrameTimer::getTotalSeconds() - mLastSnapshotTime; if (delta_time < interval) return; - if (mSkipSaveIfZeros) - { + if (mSkipSaveIfZeros) + { S32 total_events = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; - if (total_events == 0) - { + if (total_events == 0) + { LL_DEBUGS("ILXZeroData") << "ILX: not saving zero data" << LL_ENDL; return; } - } + } mLastSnapshotTime = LLFrameTimer::getTotalSeconds(); LL_DEBUGS("ILX") << "ILX: " @@ -317,5 +317,3 @@ F32 LLViewerStatsRecorder::getTimeSinceStart() { return (F32) (LLFrameTimer::getTotalSeconds() - mFileOpenTime); } - - diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index bda8c35702..b422de8f9c 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5995,7 +5995,7 @@ LLVivoxVoiceClient::sessionState::~sessionState() if (mMyIterator != mSession.end()) mSession.erase(mMyIterator); - removeAllParticipants(); + removeAllParticipants(); } bool LLVivoxVoiceClient::sessionState::isCallBackPossible() diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 716a65dbcf..e5067132fd 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5765,8 +5765,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { type = LLDrawPool::POOL_GLTF_PBR; } - else - if (type != LLDrawPool::POOL_ALPHA && force_simple) + else if (type != LLDrawPool::POOL_ALPHA && force_simple) { type = LLDrawPool::POOL_SIMPLE; } diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index ba7e8d7298..c3835bd60e 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -384,7 +384,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const mCertStore = gSavedSettings.getString("CertStore"); httpOpts->setSSLVerifyPeer( vefifySSLCert ); - httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0); + httpOpts->setSSLVerifyHost( vefifySSLCert ); // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c7f32d0da9..3de57c6bf4 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1202,6 +1202,9 @@ class LinuxManifest(ViewerManifest): super(LinuxManifest, self).construct() pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') + if "package_dir" in self.args: + pkgdir = self.args['package_dir'] + relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") @@ -1220,44 +1223,121 @@ class LinuxManifest(ViewerManifest): with self.prefix(dst="bin"): self.path("secondlife-bin","do-not-directly-run-secondlife-bin") - self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") + #self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") self.path2basename("../llplugin/slplugin", "SLPlugin") #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 - with self.prefix(src="../viewer_components/manager", dst=""): - self.path("*.py") + #with self.prefix(src="../viewer_components/manager", dst=""): + # self.path("*.py") # recurses, packaged again self.path("res-sdl") + # We copy ll_icon.BMP in CMakeLists.txt to newview/res-sdl and this will let the above self.path step take care of copying + # the correct branded icon # Get the icons based on the channel type icon_path = self.icon_path() - print("DEBUG: icon_path '%s'" % icon_path) + #print("DEBUG: icon_path '%s'" % icon_path) with self.prefix(src=icon_path) : self.path("secondlife_256.png","secondlife_icon.png") with self.prefix(dst="res-sdl") : self.path("secondlife_256.BMP","ll_icon.BMP") # plugins - with self.prefix(src="../media_plugins", dst="bin/llplugin"): - self.path("gstreamer010/libmedia_plugin_gstreamer010.so", - "libmedia_plugin_gstreamer.so") - self.path2basename("libvlc", "libmedia_plugin_libvlc.so") - - with self.prefix(src=os.path.join(pkgdir, 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): - self.path( "plugins.dat" ) - self.path( "*/*.so" ) + #with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): + # self.path("gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer.so") - with self.prefix(src=os.path.join(pkgdir, 'lib' ), dst="lib"): - self.path( "libvlc*.so*" ) - # llcommon - if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"): - print("Skipping llcommon.so (assuming llcommon was linked statically)") + """ + Once we got CEF enable this + with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): + self.path("cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" ) + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"): + self.path( "libcef.so" ) + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release', 'swiftshader'), dst=os.path.join("bin", "swiftshader") ): + self.path( "*.so" ) + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release', 'swiftshader'), dst=os.path.join("lib", "swiftshader") ): + self.path( "*.so" ) + + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="bin"): + self.path( "chrome-sandbox" ) + self.path( "dullahan_host" ) + self.path( "snapshot_blob.bin" ) + self.path( "v8_context_snapshot.bin" ) + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="lib"): + self.path( "snapshot_blob.bin" ) + self.path( "v8_context_snapshot.bin" ) + + with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="bin"): + self.path( "chrome_100_percent.pak" ) + self.path( "chrome_200_percent.pak" ) + self.path( "resources.pak" ) + self.path( "icudtl.dat" ) + with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="lib"): + self.path( "chrome_100_percent.pak" ) + self.path( "chrome_200_percent.pak" ) + self.path( "resources.pak" ) + self.path( "icudtl.dat" ) + + with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('bin', 'locales')): + self.path("am.pak") + self.path("ar.pak") + self.path("bg.pak") + self.path("bn.pak") + self.path("ca.pak") + self.path("cs.pak") + self.path("da.pak") + self.path("de.pak") + self.path("el.pak") + self.path("en-GB.pak") + self.path("en-US.pak") + self.path("es-419.pak") + self.path("es.pak") + self.path("et.pak") + self.path("fa.pak") + self.path("fi.pak") + self.path("fil.pak") + self.path("fr.pak") + self.path("gu.pak") + self.path("he.pak") + self.path("hi.pak") + self.path("hr.pak") + self.path("hu.pak") + self.path("id.pak") + self.path("it.pak") + self.path("ja.pak") + self.path("kn.pak") + self.path("ko.pak") + self.path("lt.pak") + self.path("lv.pak") + self.path("ml.pak") + self.path("mr.pak") + self.path("ms.pak") + self.path("nb.pak") + self.path("nl.pak") + self.path("pl.pak") + self.path("pt-BR.pak") + self.path("pt-PT.pak") + self.path("ro.pak") + self.path("ru.pak") + self.path("sk.pak") + self.path("sl.pak") + self.path("sr.pak") + self.path("sv.pak") + self.path("sw.pak") + self.path("ta.pak") + self.path("te.pak") + self.path("th.pak") + self.path("tr.pak") + self.path("uk.pak") + self.path("vi.pak") + self.path("zh-CN.pak") + self.path("zh-TW.pak") + """ self.path("featuretable_linux.txt") self.path("cube.dae") - with self.prefix(src=pkgdir): + with self.prefix(src=pkgdir, dst="bin"): self.path("ca-bundle.crt") def package_finish(self): @@ -1294,76 +1374,53 @@ class LinuxManifest(ViewerManifest): self.run_command(["mv", tempname, realname]) def strip_binaries(self): + doStrip = False if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): - print("* Going strip-crazy on the packaged binaries, since this is a RELEASE build") + doStrip = True + # In case of flatpak flatpak-build will call strip, disable doStrip here to get a flatpak symbol package. Increases flatpak size by about 1G + if "FLATPAK_DEST" in os.environ: + doStrip = True + + if doStrip: + print("* Going strip-crazy on the packaged binaries, since this is a Release build") # makes some small assumptions about our packaged dir structure self.run_command( ["find"] + [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] + ['-type', 'f', '!', '-name', '*.py', + '!', '-name', '*.pak', + '!', '-name', '*.bin', + '!', '-name', '*.dat', + '!', '-name', '*.crt', + '!', '-name', '*.dll', + '!', '-name', '*.lib', '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';']) -class Linux_i686_Manifest(LinuxManifest): - address_size = 32 +class Linux_x86_64_Manifest(LinuxManifest): + address_size = 64 def construct(self): - super(Linux_i686_Manifest, self).construct() + super(Linux_x86_64_Manifest, self).construct() pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') + if "package_dir" in self.args: + pkgdir = self.args['package_dir'] + relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") with self.prefix(src=relpkgdir, dst="lib"): - self.path("libapr-1.so") - self.path("libapr-1.so.0") - self.path("libapr-1.so.0.4.5") - self.path("libaprutil-1.so") - self.path("libaprutil-1.so.0") - self.path("libaprutil-1.so.0.4.1") - self.path("libdb*.so") + self.path("libapr-1.so*") + self.path("libaprutil-1.so*") self.path("libexpat.so.*") - self.path("libuuid.so*") - self.path("libSDL-1.2.so.*") - self.path("libdirectfb-1.*.so.*") - self.path("libfusion-1.*.so.*") - self.path("libdirect-1.*.so.*") - self.path("libopenjp2.so*") - self.path("libdirectfb-1.4.so.5") - self.path("libfusion-1.4.so.5") - self.path("libdirect-1.4.so.5*") - self.path("libhunspell-1.3.so*") - self.path("libalut.so*") - self.path("libopenal.so*") - self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname - # KLUDGE: As of 2012-04-11, the 'fontconfig' package installs - # libfontconfig.so.1.4.4, along with symlinks libfontconfig.so.1 - # and libfontconfig.so. Before we added support for library-file - # wildcards, though, this self.path() call specifically named - # libfontconfig.so.1.4.4 WITHOUT also copying the symlinks. When I - # (nat) changed the call to self.path("libfontconfig.so.*"), we - # ended up with the libfontconfig.so.1 symlink in the target - # directory as well. But guess what! At least on Ubuntu 10.04, - # certain viewer fonts look terrible with libfontconfig.so.1 - # present in the target directory. Removing that symlink suffices - # to improve them. I suspect that means we actually do better when - # the viewer fails to find our packaged libfontconfig.so*, falling - # back on the system one instead -- but diagnosing and fixing that - # is a bit out of scope for the present project. Meanwhile, this - # particular wildcard specification gets us exactly what the - # previous call did, without having to explicitly state the - # version number. - self.path("libfontconfig.so.*.*") - - # Include libfreetype.so. but have it work as libfontconfig does. - self.path("libfreetype.so.*.*") + self.path_optional("libSDL*.so.*") - try: - self.path("libtcmalloc.so*") #formerly called google perf tools - pass - except: - print("tcmalloc files not found, skipping") - pass + self.path_optional("libjemalloc*.so") + self.path("libhunspell-1.3.so*") + self.path_optional("libalut.so*") + self.path_optional("libopenal.so*") + self.path_optional("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname if self.args['fmodstudio'] == 'ON': try: self.path("libfmod.so.11.7") @@ -1384,17 +1441,6 @@ class Linux_i686_Manifest(LinuxManifest): self.path("libvivoxsdk.so") self.strip_binaries() - - -class Linux_x86_64_Manifest(LinuxManifest): - address_size = 64 - - def construct(self): - super(Linux_x86_64_Manifest, self).construct() - - # support file for valgrind debug tool - self.path("secondlife-i686.supp") - ################################################################ if __name__ == "__main__": -- cgit v1.2.3 From 799d1d595505acaa7f05a6d92db5f8f2d258f53e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 8 Apr 2024 16:55:26 +0300 Subject: Add script termination option to 'Lua Scripts' floater --- indra/newview/llfloaterluascripts.cpp | 6 ++++++ indra/newview/llfloaterluascripts.h | 1 + indra/newview/llluamanager.cpp | 16 ++++++++++++++++ indra/newview/llluamanager.h | 5 ++++- indra/newview/skins/default/xui/en/menu_lua_scripts.xml | 8 ++++++++ 5 files changed, 35 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index bd845a97d6..8f6ccc50fa 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -45,6 +45,11 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) { gViewerWindow->getWindow()->openFolder(mTargetFolderPath); }); + mCommitCallbackRegistrar.add("Script.Terminate", [this](LLUICtrl*, const LLSD &userdata) + { + LLEventPumps::instance().obtain("LLLua").post(llsd::map("status", "close", "coro", mCoroName)); + LLLUAmanager::terminateScript(mCoroName); + }); } @@ -113,6 +118,7 @@ void LLFloaterLUAScripts::onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y) if (menu) { mTargetFolderPath = std::filesystem::path((item->getColumn(1)->getValue().asString())).parent_path().string(); + mCoroName = item->getValue().asString(); menu->show(x, y); LLMenuGL::showPopup(this, menu, x, y); } diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h index 548bbd10f6..c7c888b55a 100644 --- a/indra/newview/llfloaterluascripts.h +++ b/indra/newview/llfloaterluascripts.h @@ -47,6 +47,7 @@ private: std::unique_ptr<LLTimer> mUpdateTimer; LLScrollListCtrl* mScriptList; std::string mTargetFolderPath; + std::string mCoroName; LLHandle<LLContextMenu> mContextMenuHandle; }; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 1d55313813..35a73aaabe 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -49,6 +49,7 @@ #include <vector> std::map<std::string, std::string> LLLUAmanager::sScriptNames; +std::set<std::string> LLLUAmanager::sTerminationList; lua_function(sleep, "sleep(seconds): pause the running coroutine") { @@ -188,6 +189,21 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // A script_finished_fn is used to initialize the LuaState. // It will be called when the LuaState is destroyed. LuaState L(finished_cb); + + static int index = 0; + lua_callbacks(L)->interrupt = [](lua_State *L, int gc) + { + if (gc >= 0) + return; + + std::set<std::string> scripts = LLLUAmanager::getTerminationList(); + std::string coro = LLCoros::getName(); + if (scripts.find(coro) != scripts.end()) + { + sTerminationList.erase(coro); + lluau::error(L, "Script was terminated"); + } + }; std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); if (result_cb) diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index fe4db22fca..d671719bc4 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -85,9 +85,12 @@ public: static void runScriptOnLogin(); static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } + static std::set<std::string> getTerminationList() { return sTerminationList; } + static void terminateScript(std::string& coro_name) { sTerminationList.insert(coro_name); } private: - static std::map<std::string, std::string> sScriptNames; + static std::map<std::string, std::string> sScriptNames; + static std::set<std::string> sTerminationList; }; class LLRequireResolver diff --git a/indra/newview/skins/default/xui/en/menu_lua_scripts.xml b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml index 8f718abe17..645fee405d 100644 --- a/indra/newview/skins/default/xui/en/menu_lua_scripts.xml +++ b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml @@ -8,4 +8,12 @@ <menu_item_call.on_click function="Script.OpenFolder" /> </menu_item_call> + <menu_item_separator/> + <menu_item_call + label="Terminate script" + layout="topleft" + name="terminate"> + <menu_item_call.on_click + function="Script.Terminate" /> + </menu_item_call> </context_menu> -- cgit v1.2.3 From e79c32eee89c31e730ac0562d680e6e0ebfd4a68 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 8 Apr 2024 22:41:34 +0300 Subject: triage#163 'Create folder from selected' misbehaves in marketplace Marketplace deliberately doesn't allow creating folders and the "New folder from selected" is a way of creating a new folder then moving selected items inside, therefore shouldn't be allowed. --- indra/newview/llinventorybridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0ed89292a5..1783c4c9db 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -852,7 +852,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Copy")); } - if (isAgentInventory() && !single_folder_root) + if (isAgentInventory() && !single_folder_root && !isMarketplaceListingsFolder()) { items.push_back(std::string("New folder from selected")); items.push_back(std::string("Subfolder Separator")); -- cgit v1.2.3 From 6b4b33cc129e9482342c9280ae79c9c5ce427ef1 Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn <nicky.dasmijn@posteo.nl> Date: Mon, 8 Apr 2024 22:39:20 +0200 Subject: Linux GHA builds (#1147) * Linux GHA builds Add Ubuntu 22.04 runner and Linux dependencies Do not even try to touch ReleaseFS for Linux yet (this needs KDU, Havok, FMOD) * Lets play a game of 'guess the havok source url' * Move to linux-large runner. * ReleaseOS used OpenAL, not fmod studio (which otherwise is the default) * - Correction for Linux build dir - HAVOK / CrashReporting wrestling. HAVOK is always turned on, even for OS builds Turn this off for Linux-ReleaseOS Same with crashreporting, we need it off for now * Add missing brace * When doing a GHA build pack right into RUNNER_TEMP and then signal the created archive as our "viewer_app" * Upload Linux-ReleaseOS after build * - Need to use os.path.join and not hyst join - set_github_output_path can be called unconditionally * Remove Linux GHA build example. --- indra/newview/viewer_manifest.py | 50 +++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 19 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 3de57c6bf4..c97d421504 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -59,7 +59,7 @@ class ViewerManifest(LLManifest): # files during the build (see copy_w_viewer_manifest # and copy_l_viewer_manifest targets) return 'package' in self.args['actions'] - + def construct(self): super(ViewerManifest, self).construct() self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") @@ -87,7 +87,7 @@ class ViewerManifest(LLManifest): # ... and the entire image filters directory self.path("filters") - + # ... and the included spell checking dictionaries pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') with self.prefix(src=pkgdir): @@ -260,14 +260,14 @@ class ViewerManifest(LLManifest): def app_name_oneword(self): return ''.join(self.app_name().split()) - + def icon_path(self): return "icons/" + self.channel_type() def extract_names(self,src): """Extract contributor names from source file, returns string""" try: - with open(src, 'r') as contrib_file: + with open(src, 'r') as contrib_file: lines = contrib_file.readlines() except IOError: print("Failed to open '%s'" % src) @@ -491,7 +491,7 @@ class Windows_x86_64_Manifest(ViewerManifest): raise Exception("Directories are not supported by test_CRT_and_copy_action()") else: print("Doesn't exist:", src) - + def construct(self): super().construct() @@ -543,7 +543,7 @@ class Windows_x86_64_Manifest(ViewerManifest): self.path2basename(os.path.join(os.pardir, 'llplugin', 'slplugin', self.args['configuration']), "slplugin.exe") - + # Get shared libs from the shared libs staging directory with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', self.args['buildtype'])): @@ -582,7 +582,7 @@ class Windows_x86_64_Manifest(ViewerManifest): # Vivox libraries self.path("vivoxsdk_x64.dll") self.path("ortp_x64.dll") - + # OpenSSL self.path("libcrypto-1_1-x64.dll") self.path("libssl-1_1-x64.dll") @@ -709,7 +709,7 @@ class Windows_x86_64_Manifest(ViewerManifest): self.path("plugins/") if not self.is_packaging_viewer(): - self.package_file = "copied_deps" + self.package_file = "copied_deps" def nsi_file_commands(self, install=True): def INSTDIR(path): @@ -768,7 +768,7 @@ class Windows_x86_64_Manifest(ViewerManifest): installer_file = self.installer_base_name() + '_Setup.exe' substitution_strings['installer_file'] = installer_file - + version_vars = """ !define INSTEXE "SLVersionChecker.exe" !define VERSION "%(version_short)s" @@ -777,7 +777,7 @@ class Windows_x86_64_Manifest(ViewerManifest): !define VERSION_REGISTRY "%(version_registry)s" !define VIEWER_EXE "%(final_exe)s" """ % substitution_strings - + if self.channel_type() == 'release': substitution_strings['caption'] = CHANNEL_VENDOR_BASE else: @@ -908,7 +908,7 @@ class Darwin_x86_64_Manifest(ViewerManifest): # yields a slightly smaller binary but makes crash # logs mostly useless. This may be desirable for the # final release. Or not. - if ("package" in self.args['actions'] or + if ("package" in self.args['actions'] or "unpacked" in self.args['actions']): self.run_command( ['strip', '-S', executable]) @@ -933,7 +933,7 @@ class Darwin_x86_64_Manifest(ViewerManifest): with self.prefix(src=relpkgdir, dst=""): self.path("libndofdev.dylib") - self.path("libhunspell-*.dylib") + self.path("libhunspell-*.dylib") with self.prefix(src_dst="cursors_mac"): self.path("*.tif") @@ -1204,7 +1204,7 @@ class LinuxManifest(ViewerManifest): pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') if "package_dir" in self.args: pkgdir = self.args['package_dir'] - + relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") @@ -1343,6 +1343,9 @@ class LinuxManifest(ViewerManifest): def package_finish(self): installer_name = self.installer_base_name() + # When running as a GitHub Action job, RUNNER_TEMP is defined as the tmp dir + RUNNER_TEMP = os.getenv('RUNNER_TEMP') + self.strip_binaries() # Fix access permissions @@ -1357,21 +1360,30 @@ class LinuxManifest(ViewerManifest): # temporarily move directory tree so that it has the right # name in the tarfile realname = self.get_dst_prefix() - tempname = self.build_path_of(installer_name) - self.run_command(["mv", realname, tempname]) + versionedName = self.build_path_of(installer_name) + + tarName = versionedName + ".tar.bz2" + + # If using a github runner we divert packaging a little. Considering this wil be a VM/docker image + # we can just pack the final installer into RUNNER_TEMP and not into the usual stop we'd pick when + # not building a GHA release + if RUNNER_TEMP: + tarName = os.path.join(RUNNER_TEMP, self.package_file) + + self.run_command(["mv", realname, versionedName]) + try: # only create tarball if it's a release build. if self.args['buildtype'].lower() == 'release': - # --numeric-owner hides the username of the builder for - # security etc. self.run_command(['tar', '-C', self.get_build_prefix(), '--numeric-owner', '-cjf', - tempname + '.tar.bz2', installer_name]) + tarName, installer_name]) + self.set_github_output_path('viewer_app', tarName) else: print("Skipping %s.tar.bz2 for non-Release build (%s)" % \ (installer_name, self.args['buildtype'])) finally: - self.run_command(["mv", tempname, realname]) + self.run_command(["mv", versionedName, realname]) def strip_binaries(self): doStrip = False -- cgit v1.2.3 From 37392be4171303db08a4842b7882b4cb758a8f8d Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn <nicky.dasmijn@posteo.nl> Date: Tue, 9 Apr 2024 20:26:06 +0200 Subject: Update Linux media handling (#1146) * Enable CEF browser for Linux * Disable the update for Linux, we don't have that one right now * Update build_linux.yaml We need libpulse-dev for volume_catcher Linux * Add linux_volum_catcher* files * Enable OpenAL for Linux-ReleaseOS * Linux: Update OpenAL * Update SDL2 * Add libsndio-dev to the dependencies. * Update CEF to an official LL version * Remove dupe of emoji_shortcodes * Reording autobuild does because it can and wants to * Linux: Disable NDOF for the time being. After updating the ndof 3P needs to be rebuilt and we do not have a fresh one from LL yet. Forcefully undefine LIB_NDOF, it gets defined in the build variables no matter if it is safe to define. * Remove wrestling with mutliarch and LIBGL_DRIVERS_PATH * Remove tcmalloc snippet, tcmalloc is a very faint bad dream of the past * Putting out a warning this viewer ran on a x64 arch and then suggesting to install 32 bit compat packages makes no sense at all * CEF resources need to be in lib * It;'s okay to warn about missing plugins * Linux: CEF keyboard handling * Remove old gstreamer 0.10 implementation * Linux DSO loading always had been very peculiar due to macro magic. At least now it is peculiar shared magic with only one implementation. * Remove -fPIC. We get that one from LL_BUILD * /proc/cpuinfo is not reliable to detrmine the max CPU clock. Try to determine this by reading "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq". Only if this fails go back to /proc/cpuinfo * Cleanup * Cleanup common linker and compiler flags, make it more obvious which flags are for which OS/compiler * Switch to correct plugin file * Install libpulse-dev for volume catcher. * And the runner needs libsndio-dev as well. * check for runner.os=='linux'. matrix.os is the full name of the image (limux-large). --- indra/newview/CMakeLists.txt | 1 - indra/newview/linux_tools/wrapper.sh | 42 ------------- indra/newview/llappviewer.cpp | 3 +- indra/newview/llviewermedia.cpp | 4 -- .../skins/default/xui/en/mime_types_linux.xml | 70 +++++++++++----------- indra/newview/viewer_manifest.py | 24 +++----- 6 files changed, 45 insertions(+), 99 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f359bebb17..e6ac84d5ab 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2384,4 +2384,3 @@ if (LL_TESTS) endif (LL_TESTS) check_message_template(${VIEWER_BINARY_NAME}) - diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index eb3ead433b..7d26c81283 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -58,17 +58,6 @@ fi ## - Avoids an often-buggy X feature that doesn't really benefit us anyway. export SDL_VIDEO_X11_DGAMOUSE=0 -## - Works around a problem with misconfigured 64-bit systems not finding GL -I386_MULTIARCH="$(dpkg-architecture -ai386 -qDEB_HOST_MULTIARCH 2>/dev/null)" -MULTIARCH_ERR=$? -if [ $MULTIARCH_ERR -eq 0 ]; then - echo 'Multi-arch support detected.' - MULTIARCH_GL_DRIVERS="/usr/lib/${I386_MULTIARCH}/dri" - export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}:${MULTIARCH_GL_DRIVERS}:/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri" -else - export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}:/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri" -fi - ## - The 'scim' GTK IM module widely crashes the viewer. Avoid it. if [ "$GTK_IM_MODULE" = "scim" ]; then export GTK_IM_MODULE=xim @@ -98,25 +87,6 @@ cd "${RUN_PATH}" ## 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}" - -# if [ -n "$LL_TCMALLOC" ]; then -# tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0' -# all=1 -# for f in $tcmalloc_libs; do -# if [ ! -f $f ]; then -# all=0 -# fi -# done -# if [ $all != 1 ]; then -# echo 'Cannot use tcmalloc libraries: components missing' 1>&2 -# else -# export LD_PRELOAD=$(echo $tcmalloc_libs | tr ' ' :) -# if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then -# export HEAPCHECK=${HEAPCHECK:-normal} -# fi -# fi -#fi - export LD_LIBRARY_PATH="$PWD/lib:${LD_LIBRARY_PATH}" # Copy "$@" to ARGS array specifically to delete the --skip-gridargs switch. @@ -140,18 +110,6 @@ LL_RUN_ERR=$? if [ $LL_RUN_ERR -ne 0 ]; then # generic error running the binary echo '*** Bad shutdown ($LL_RUN_ERR). ***' - if [ "$(uname -m)" = "x86_64" ]; then - echo - cat << EOFMARKER -You are running the Second Life Viewer on a x86_64 platform. The -most common problems when launching the Viewer (particularly -'bin/do-not-directly-run-secondlife-bin: not found' and 'error while -loading shared libraries') may be solved by installing your Linux -distribution's 32-bit compatibility packages. -For example, on Ubuntu and other Debian-based Linuxes you might run: -$ sudo apt-get install ia32-libs ia32-libs-gtk ia32-libs-kde ia32-libs-sdl -EOFMARKER - fi fi echo diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a1fecdb981..4099f8bc7d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1130,7 +1130,7 @@ bool LLAppViewer::init() gGLActive = FALSE; -#if LL_RELEASE_FOR_DOWNLOAD +#if LL_RELEASE_FOR_DOWNLOAD && !LL_LINUX // Skip updater if this is a non-interactive instance if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive) { @@ -5662,4 +5662,3 @@ void LLAppViewer::metricsSend(bool enable_reporting) // resolution in time. gViewerAssetStats->restart(); } - diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 59701cc5b3..3791d1e754 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1739,9 +1739,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } else if(LLFile::stat(plugin_name, &s)) { -#if !LL_LINUX LL_WARNS_ONCE("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; -#endif } else { @@ -1795,9 +1793,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } } } -#if !LL_LINUX LL_WARNS_ONCE("Plugin") << "plugin initialization failed for mime type: " << media_type << LL_ENDL; -#endif if(gAgent.isInitialized()) { diff --git a/indra/newview/skins/default/xui/en/mime_types_linux.xml b/indra/newview/skins/default/xui/en/mime_types_linux.xml index 7188b1e699..22a0024874 100644 --- a/indra/newview/skins/default/xui/en/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en/mime_types_linux.xml @@ -7,7 +7,7 @@ none </defaultwidget> <defaultimpl> - media_plugin_webkit + media_plugin_cef </defaultimpl> <widgetset name="web"> <label name="web_label"> @@ -130,7 +130,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </scheme> <mimetype name="blank"> @@ -141,7 +141,7 @@ none </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="none/none"> @@ -152,7 +152,7 @@ none </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="audio/*"> @@ -163,7 +163,7 @@ audio </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="video/*"> @@ -174,7 +174,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="image/*"> @@ -185,7 +185,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="video/vnd.secondlife.qt.legacy"> @@ -196,7 +196,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="application/javascript"> @@ -207,7 +207,7 @@ web </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="application/ogg"> @@ -218,7 +218,7 @@ audio </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="application/pdf"> @@ -229,7 +229,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="application/postscript"> @@ -240,7 +240,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="application/rtf"> @@ -251,7 +251,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="application/smil"> @@ -262,7 +262,7 @@ movie </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="application/xhtml+xml"> @@ -273,7 +273,7 @@ web </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="application/x-director"> @@ -284,7 +284,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="audio/mid"> @@ -295,7 +295,7 @@ audio </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="audio/mpeg"> @@ -306,7 +306,7 @@ audio </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="audio/x-aiff"> @@ -317,7 +317,7 @@ audio </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="audio/x-wav"> @@ -328,7 +328,7 @@ audio </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype menu="1" name="image/bmp"> @@ -339,7 +339,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="image/gif"> @@ -350,7 +350,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="image/jpeg"> @@ -361,7 +361,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="image/png"> @@ -372,7 +372,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="image/svg+xml"> @@ -383,7 +383,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="image/tiff"> @@ -394,7 +394,7 @@ image </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="text/html"> @@ -405,7 +405,7 @@ web </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="text/plain"> @@ -416,7 +416,7 @@ text </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype name="text/xml"> @@ -427,7 +427,7 @@ text </widgettype> <impl> - media_plugin_webkit + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="video/mpeg"> @@ -438,7 +438,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="video/mp4"> @@ -449,7 +449,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype menu="1" name="video/quicktime"> @@ -460,7 +460,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="video/x-ms-asf"> @@ -471,7 +471,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype name="video/x-ms-wmv"> @@ -482,7 +482,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> <mimetype menu="1" name="video/x-msvideo"> @@ -493,7 +493,7 @@ movie </widgettype> <impl> - media_plugin_libvlc + media_plugin_gstreamer </impl> </mimetype> </mimetypes> diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c97d421504..6fae39db30 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1243,20 +1243,20 @@ class LinuxManifest(ViewerManifest): self.path("secondlife_256.BMP","ll_icon.BMP") # plugins - #with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): - # self.path("gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer.so") + with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): + self.path("gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer.so") - """ - Once we got CEF enable this with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): self.path("cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" ) with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"): self.path( "libcef.so" ) - with self.prefix(src=os.path.join(pkgdir, 'lib', 'release', 'swiftshader'), dst=os.path.join("bin", "swiftshader") ): - self.path( "*.so" ) - with self.prefix(src=os.path.join(pkgdir, 'lib', 'release', 'swiftshader'), dst=os.path.join("lib", "swiftshader") ): - self.path( "*.so" ) + + self.path( "libEGL*" ) + self.path( "libvulkan*" ) + self.path( "libvk_swiftshader*" ) + self.path( "libGLESv2*" ) + self.path( "vk_swiftshader_icd.json") with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="bin"): self.path( "chrome-sandbox" ) @@ -1267,18 +1267,13 @@ class LinuxManifest(ViewerManifest): self.path( "snapshot_blob.bin" ) self.path( "v8_context_snapshot.bin" ) - with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="bin"): - self.path( "chrome_100_percent.pak" ) - self.path( "chrome_200_percent.pak" ) - self.path( "resources.pak" ) - self.path( "icudtl.dat" ) with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="lib"): self.path( "chrome_100_percent.pak" ) self.path( "chrome_200_percent.pak" ) self.path( "resources.pak" ) self.path( "icudtl.dat" ) - with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('bin', 'locales')): + with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('lib', 'locales')): self.path("am.pak") self.path("ar.pak") self.path("bg.pak") @@ -1332,7 +1327,6 @@ class LinuxManifest(ViewerManifest): self.path("vi.pak") self.path("zh-CN.pak") self.path("zh-TW.pak") - """ self.path("featuretable_linux.txt") self.path("cube.dae") -- cgit v1.2.3 From 26ce33d8ead68c2dbcc37b2b1e040c072866fe5b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 9 Apr 2024 15:21:05 -0400 Subject: Add Lua Floater class to simplify Lua script showing floaters. Add test_luafloater_demo2.lua and test_luafloater_gesture_list2.lua examples. --- indra/newview/scripts/lua/Floater.lua | 151 +++++++++++++++++++++ indra/newview/scripts/lua/leap.lua | 7 +- .../newview/scripts/lua/test_luafloater_demo2.lua | 39 ++++++ .../scripts/lua/test_luafloater_gesture_list2.lua | 27 ++++ 4 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 indra/newview/scripts/lua/Floater.lua create mode 100644 indra/newview/scripts/lua/test_luafloater_demo2.lua create mode 100644 indra/newview/scripts/lua/test_luafloater_gesture_list2.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/Floater.lua b/indra/newview/scripts/lua/Floater.lua new file mode 100644 index 0000000000..76efd47c43 --- /dev/null +++ b/indra/newview/scripts/lua/Floater.lua @@ -0,0 +1,151 @@ +-- Floater base class + +local leap = require 'leap' +local fiber = require 'fiber' + +-- list of all the events that a LLLuaFloater might send +local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events +local event_set = {} +for _, event in pairs(event_list) do + event_set[event] = true +end + +local function _event(event_name) + if not event_set[event_name] then + error("Incorrect event name: " .. event_name, 3) + end + return event_name +end + +-- --------------------------------------------------------------------------- +local Floater = {} + +-- Pass: +-- relative file path to floater's XUI definition file +-- optional: sign up for additional events for defined control +-- {<control_name>={action1, action2, ...}} +function Floater:new(path, extra) + local obj = setmetatable({}, self) + self.__index = self + + local path_parts = string.split(path, '/') + obj.name = 'Floater ' .. path_parts[#path_parts] + + obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)} + if extra then + -- validate each of the actions for each specified control + for control, actions in pairs(extra) do + for _, action in pairs(actions) do + _event(action) + end + end + obj._command.extra_events = extra + end + + return obj +end + +function Floater:show() + local event = leap.request('LLFloaterReg', self._command) + self._pump = event.command_name + -- we use the returned reqid to claim subsequent unsolicited events + local reqid = event.reqid + + -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if + -- subclass has a post_build() method. Honor the convention that if + -- handleEvents() returns false, we're done. + if not self:handleEvents(event) then + return + end + + local waitfor = leap.WaitFor:new(-1, self.name) + function waitfor:filter(pump, data) + if data.reqid == reqid then + return data + end + end + + fiber.launch( + self.name, + function () + event = waitfor:wait() + while event and self:handleEvents(event) do + event = waitfor:wait() + end + end) +end + +function Floater:post(action) + leap.send(self._pump, action) +end + +function Floater:request(action) + return leap.request(self._pump, action) +end + +-- local inspect = require 'inspect' + +function Floater:handleEvents(event_data) + local event = event_data.event + if event_set[event] == nil then + LL.print_warning(string.format('%s received unknown event %q', self.name, event)) + end + + -- Before checking for a general (e.g.) commit() method, first look for + -- commit_ctrl_name(): in other words, concatenate the event name with the + -- ctrl_name, with an underscore between. If there exists such a specific + -- method, call that. + local handler, ret + if event_data.ctrl_name then + local specific = event .. '_' .. event_data.ctrl_name + handler = self[specific] + if handler then + ret = handler(self, event_data) + -- Avoid 'return ret or true' because we explicitly want to allow + -- the handler to return false. + if ret ~= nil then + return ret + else + return true + end + end + end + + -- No specific "event_on_ctrl()" method found; try just "event()" + handler = self[event] + if handler then + ret = handler(self, event_data) + if ret ~= nil then + return ret + end +-- else +-- print(string.format('%s ignoring event %s', self.name, inspect(event_data))) + end + + -- We check for event() method before recognizing floater_close in case + -- the consumer needs to react specially to closing the floater. Now that + -- we've checked, recognize it ourselves. Returning false terminates the + -- anonymous fiber function launched by show(). + if event == _event('floater_close') then + LL.print_warning(self.name .. ' closed') + return false + end + return true +end + +-- onCtrl() permits a different dispatch style in which the general event() +-- method explicitly calls (e.g.) +-- self:onCtrl(event_data, { +-- ctrl_name=function() +-- self:post(...) +-- end, +-- ... +-- }) +function Floater:onCtrl(event_data, ctrl_map) + local handler = ctrl_map[event_data.ctrl_name] + if handler then + handler() + end +end + +return Floater diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index d19273e8bc..ade91789f0 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -183,14 +183,15 @@ function leap.generate(pump, data, checklast) -- bearing that reqid. Stamp the outbound request with that reqid, and -- send it. local reqid, waitfor = requestSetup(pump, data) - local ok, response + local ok, response, resumed_with repeat ok, response = pcall(waitfor.wait, waitfor) if not ok then break end - coroutine.yield(response) - until checklast and checklast(response) + -- can resume(false) to terminate generate() and clean up + resumed_with = coroutine.yield(response) + until (checklast and checklast(response)) or (resumed_with == false) -- If we break the above loop, whether or not due to error, clean up. pending[reqid] = nil if not ok then diff --git a/indra/newview/scripts/lua/test_luafloater_demo2.lua b/indra/newview/scripts/lua/test_luafloater_demo2.lua new file mode 100644 index 0000000000..9e24237d28 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_demo2.lua @@ -0,0 +1,39 @@ +local Floater = require 'Floater' +local leap = require 'leap' +local startup = require 'startup' + +local flt = Floater:new( + 'luafloater_demo.xml', + {show_time_lbl = {"right_mouse_down", "double_click"}}) + +-- override base-class handleEvents() to report the event data in the floater's display field +function flt:handleEvents(event_data) + self:post({action="add_text", ctrl_name="events_editor", value = event_data}) + -- forward the call to base-class handleEvents() + return Floater.handleEvents(self, event_data) +end + +function flt:commit_disable_ctrl(event_data) + self:post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) +end + +function flt:commit_title_cmb(event_data) + self:post({action="set_title", value=event_data.value}) +end + +function flt:commit_open_btn(event_data) + floater_name = self:request({action="get_value", ctrl_name='openfloater_cmd'}).value + leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) +end + +local function getCurrentTime() + local currentTime = os.date("*t") + return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec) +end + +function flt:double_click_show_time_lbl(event_data) + self:post({action="set_value", ctrl_name="time_lbl", value=getCurrentTime()}) +end + +startup.wait('STATE_LOGIN_WAIT') +flt:show() diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua new file mode 100644 index 0000000000..d702d09c51 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua @@ -0,0 +1,27 @@ +local Floater = require 'Floater' +local LLGesture = require 'LLGesture' +local startup = require 'startup' + +local flt = Floater:new( + "luafloater_gesture_list.xml", + {gesture_list = {"double_click"}}) + +function flt:post_build(event_data) + local gestures_uuid = LLGesture.getActiveGestures() + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "gesture_list" + local gestures = {} + for uuid, info in pairs(gestures_uuid) do + table.insert(gestures, {value = uuid, columns={column = "gesture_name", value = info.name}}) + end + action_data.value = gestures + self:post(action_data) +end + +function flt:double_click_gesture_list(event_data) + LLGesture.startGesture(event_data.value) +end + +startup.wait('STATE_STARTED') +flt:show() -- cgit v1.2.3 From e6aa6d22a107161b0bf08a45e9a90e749a824d9b Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Tue, 9 Apr 2024 22:37:34 +0300 Subject: mac build fix - remove unused variable --- indra/newview/llluamanager.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 35a73aaabe..344ab1bb99 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -190,7 +190,6 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // It will be called when the LuaState is destroyed. LuaState L(finished_cb); - static int index = 0; lua_callbacks(L)->interrupt = [](lua_State *L, int gc) { if (gc >= 0) -- cgit v1.2.3 From 72730609f371ae0417a2d117fdc9d805ce8858fb Mon Sep 17 00:00:00 2001 From: Brad Linden <46733234+brad-linden@users.noreply.github.com> Date: Wed, 10 Apr 2024 09:48:03 -0700 Subject: Fix linux some shader errors when running under WSL, related to secondlife/viewer#1149 (#1170) --- .../app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl | 4 ++-- indra/newview/app_settings/shaders/class3/deferred/materialF.glsl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl index 1a85d70256..a33c4cc58b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl @@ -27,11 +27,11 @@ float random (vec2 uv) { - return 0; + return 0.; } float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source, float glossiness) { collectedColor = vec4(0); - return 0; + return 0.; } diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index ec1e49eeb4..83c3845d18 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -53,7 +53,7 @@ out vec4 frag_color; float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); #endif -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); @@ -276,10 +276,10 @@ float getShadow(vec3 pos, vec3 norm) #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) return sampleDirectionalShadow(pos, norm, vary_texcoord0.xy); #else - return 1; + return 1.; #endif #else - return 1; + return 1.; #endif } -- cgit v1.2.3 From 52f3f70ce887c0f8877de7a8439bf44a246e7f9a Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Wed, 10 Apr 2024 20:44:24 +0200 Subject: Make sure items get removed from maps before the item itself gets destroyed, Otherwise the viewer ends with a dangling pointer in the map --- indra/newview/llinventorymodel.cpp | 3 +-- indra/newview/llinventorypanel.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 05aa2e423f..ab8d085ae5 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2050,8 +2050,8 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo { LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; } + mParentChildCategoryTree.erase(id); delete cat_list; - mParentChildCategoryTree.erase(id); } addChangedMask(LLInventoryObserver::REMOVE, id); @@ -5040,4 +5040,3 @@ void LLInventoryModel::FetchItemHttpHandler::processFailure(const char * const r << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; gInventory.notifyObservers(); } - diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index ab04a8589a..ae2236da3f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -578,8 +578,8 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve if (model_item && view_item && viewmodel_item) { const LLUUID& idp = viewmodel_item->getUUID(); + removeItemID(idp); view_item->destroyView(); - removeItemID(idp); } LLInventoryObject const* objectp = mInventory->getObject(item_id); -- cgit v1.2.3 From a0f282643f26789ef7e1b624398581cceafc257c Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Thu, 11 Apr 2024 19:10:46 +0300 Subject: Restore the fix for #945 (lost during merge #1178) --- indra/newview/lloutfitslist.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 20ef1588ae..7bb9fa2eed 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -913,16 +913,8 @@ void LLOutfitListBase::onIdleRefreshList() LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter); if (cat) { - LLInventoryObject* obj = gInventory.getObject(*items_iter); - if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) - { - break; - } - cat = (LLViewerInventoryCategory*)obj; + updateChangedCategoryName(cat, cat->getName()); } - std::string name = cat->getName(); - - updateChangedCategoryName(cat, name); } sortOutfits(); -- cgit v1.2.3 From 7f021738ef2d74f78093dbe4fa37cbfa6645e05a Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Wed, 10 Apr 2024 21:02:40 +0200 Subject: Fix ASAN errors from LLVector4a::memcpyNonAliased16 Found by running with -fsanitze=thread Suggestion to avoid accessing invalid memory: In both cases memory will be allocated by can be accessed beyond bounds. In LLPolyMesh it can be off by at least one (+x%2). Though I am not even sure if even in best case it always will be a multiple of 16. In LLViewerJointMesh::updateFaceData the code tries to account for padding by, but the allocation in LLPolyMeshSharedData::allocateVertexData is done without any padding. Thus the sizes must not match. Replacing the calls with memcpy as a quick fix to see if the error goes away fixed address sanitzer complaining. It is up to debate if memcpy is a good replacement. LLVector4a::memcpyNonAliased16 was invented for performance. But on the other hand one could argue that nowadays every stdlib maintainer will very heavily optmize functions like memcpy themselves and could take advantage of CPU features the old LL implementation does not take into account. AVX comes to mind. In any case did I not measure any of this. --- indra/newview/llviewerjointmesh.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 5d46c695b7..b5ccb3591f 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -405,13 +405,19 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w F32* tc = (F32*) tex_coordsp.get(); F32* vw = (F32*) vertex_weightsp.get(); - F32* cw = (F32*) clothing_weightsp.get(); + F32* cw = (F32*) clothing_weightsp.get(); - S32 tc_size = (num_verts*2*sizeof(F32)+0xF) & ~0xF; - LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), tc_size); - S32 vw_size = (num_verts*sizeof(F32)+0xF) & ~0xF; - LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), vw_size); - LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4*sizeof(F32)); + //S32 tc_size = (num_verts*2*sizeof(F32)+0xF) & ~0xF; + //LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), tc_size); + //S32 vw_size = (num_verts*sizeof(F32)+0xF) & ~0xF; + //LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), vw_size); + + // Both allocated in LLPolyMeshSharedData::allocateVertexData(unsigned int) + + memcpy(tc, mMesh->getTexCoords(), num_verts*2*sizeof(F32) ); + memcpy(vw, mMesh->getWeights(), num_verts*sizeof(F32) ); + + LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4*sizeof(F32)); } const U32 idx_count = mMesh->getNumFaces()*3; -- cgit v1.2.3 From 396ae60e1528515d0cbdfc4290b24ccb172998c8 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 12 Apr 2024 19:28:29 +0300 Subject: 'Lua Scripts' floater clean up --- indra/newview/llfloaterluascripts.cpp | 16 +++++++++++----- indra/newview/llfloaterluascripts.h | 2 -- indra/newview/llluamanager.cpp | 8 ++++---- 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 8f6ccc50fa..30353a7210 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -43,12 +43,20 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) { mCommitCallbackRegistrar.add("Script.OpenFolder", [this](LLUICtrl*, const LLSD &userdata) { - gViewerWindow->getWindow()->openFolder(mTargetFolderPath); + if (mScriptList->hasSelectedItem()) + { + std::string target_folder_path = std::filesystem::path((mScriptList->getFirstSelected()->getColumn(1)->getValue().asString())).parent_path().string(); + gViewerWindow->getWindow()->openFolder(target_folder_path); + } }); mCommitCallbackRegistrar.add("Script.Terminate", [this](LLUICtrl*, const LLSD &userdata) { - LLEventPumps::instance().obtain("LLLua").post(llsd::map("status", "close", "coro", mCoroName)); - LLLUAmanager::terminateScript(mCoroName); + if (mScriptList->hasSelectedItem()) + { + std::string coro_name = mScriptList->getSelectedValue(); + LLEventPumps::instance().obtain("LLLua").post(llsd::map("status", "close", "coro", coro_name)); + LLLUAmanager::terminateScript(coro_name); + } }); } @@ -117,8 +125,6 @@ void LLFloaterLUAScripts::onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y) auto menu = mContextMenuHandle.get(); if (menu) { - mTargetFolderPath = std::filesystem::path((item->getColumn(1)->getValue().asString())).parent_path().string(); - mCoroName = item->getValue().asString(); menu->show(x, y); LLMenuGL::showPopup(this, menu, x, y); } diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h index c7c888b55a..932c5c78dd 100644 --- a/indra/newview/llfloaterluascripts.h +++ b/indra/newview/llfloaterluascripts.h @@ -46,8 +46,6 @@ private: std::unique_ptr<LLTimer> mUpdateTimer; LLScrollListCtrl* mScriptList; - std::string mTargetFolderPath; - std::string mCoroName; LLHandle<LLContextMenu> mContextMenuHandle; }; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 344ab1bb99..853ed5a634 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -192,14 +192,14 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r lua_callbacks(L)->interrupt = [](lua_State *L, int gc) { + // skip if we're interrupting only for garbage collection if (gc >= 0) return; - std::set<std::string> scripts = LLLUAmanager::getTerminationList(); - std::string coro = LLCoros::getName(); - if (scripts.find(coro) != scripts.end()) + auto it = sTerminationList.find(LLCoros::getName()); + if (it != sTerminationList.end()) { - sTerminationList.erase(coro); + sTerminationList.erase(it); lluau::error(L, "Script was terminated"); } }; -- cgit v1.2.3 From 9356b3f9ae553c27018eb70a5a0780d21f38786c Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Sat, 13 Apr 2024 21:54:17 +0200 Subject: Inject XZ_DEFAULTS=-T0 into the environment. This will speed up archive generation. --- indra/newview/viewer_manifest.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 46d5c0a3ce..103dff3621 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -65,6 +65,8 @@ class ViewerManifest(LLManifest): self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") self.path(src="../../etc/message.xml", dst="app_settings/message.xml") + os.environ["XZ_DEFAULTS"] = "-T0" + if self.is_packaging_viewer(): with self.prefix(src_dst="app_settings"): self.exclude("logcontrol.xml") -- cgit v1.2.3 From 2d4de107f8fc3714f75f73fc9293c87eaf0e5acb Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn <nicky.dasmijn@posteo.nl> Date: Sun, 14 Apr 2024 15:14:23 +0200 Subject: Feature/linux gtk removal (#1225) * GTK remnants removal Remove old GTK code and wire up some missing fltk logic in llfilepicker This will leave linux_crash_logger as an empy stub which could be used as a skeleton in case crash logging gets implemented. Otherwise linux_crash_logger and what is left of it in some cmake files can be deleted. * Update SDL2 to latest version. This revealed openal has also a dependebcy on sndio. Consequently the dependency was moved to OPENMAL.cmake and canot be dropped. * Handle missing filetypes: FFSAVE_GLTF,FFLOAD_GLTF, FFLOAD_MATERIAL, FFLOAD_MATERIAL_TEXTURE --- indra/newview/llappviewer.cpp | 24 +- indra/newview/lldirpicker.cpp | 43 +-- indra/newview/llfilepicker.cpp | 711 +++++++++++++---------------------------- indra/newview/llfilepicker.h | 51 +-- 4 files changed, 259 insertions(+), 570 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index eb1110a457..21eb41e2b7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -108,7 +108,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llperfstats.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -264,10 +264,6 @@ using namespace LL; // define a self-registering event API object #include "llappviewerlistener.h" -#if LL_LINUX && LL_GTK -#include "glib.h" -#endif // (LL_LINUX) && LL_GTK - #if LL_MSVC // disable boost::lexical_cast warning #pragma warning (disable:4702) @@ -564,7 +560,7 @@ static void settings_to_globals() gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale")); - + #if LL_DARWIN LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL"); gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); @@ -1344,7 +1340,7 @@ bool LLAppViewer::frame() } } else - { + { try { ret = doFrame(); @@ -1755,7 +1751,7 @@ bool LLAppViewer::cleanup() LLViewerCamera::deleteSingleton(); LL_INFOS() << "Viewer disconnected" << LL_ENDL; - + if (gKeyboard) { gKeyboard->resetKeys(); @@ -2214,7 +2210,7 @@ bool LLAppViewer::initThreads() } // The only configurable thread count right now is ImageDecode - // The viewer typically starts around 8 threads not including image decode, + // The viewer typically starts around 8 threads not including image decode, // so try to leave at least one core free S32 image_decode_count = llclamp(cores - 9, 1, 8); threadCounts["ImageDecode"] = image_decode_count; @@ -2290,7 +2286,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() if (mSecondInstance) { LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); - + LLUUID uid; uid.generate(); LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); @@ -4211,8 +4207,8 @@ bool LLAppViewer::initCache() const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); const F64 texture_cache_percent = 100.0 - disk_cache_percent; - // note that the maximum size of this cache is defined as a percentage of the - // total cache size - the 'CacheSize' pref - for all caches. + // note that the maximum size of this cache is defined as a percentage of the + // total cache size - the 'CacheSize' pref - for all caches. const uintmax_t disk_cache_size = uintmax_t(cache_total_size * disk_cache_percent / 100); const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); @@ -4226,7 +4222,7 @@ bool LLAppViewer::initCache() gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); //texture cache version was bumped up in Simple Cache Viewer, and at this point old vfs files are not needed - remove_vfs_files = true; + remove_vfs_files = true; } } @@ -4283,7 +4279,7 @@ bool LLAppViewer::initCache() { LLDiskCache::getInstance()->removeOldVFSFiles(); } - + if (mPurgeCache) { LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index e541d2ab00..d1c251bfc1 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldirpicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,7 +59,7 @@ LLDirPicker LLDirPicker::sInstance; // Implementation // -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLDirPicker::check_local_file_access_enabled() { @@ -111,7 +111,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) BOOL success = FALSE; - + if (blocking) { // Modal, so pause agent @@ -182,7 +182,7 @@ void LLDirPicker::reset() BOOL LLDirPicker::getDir(std::string* filename, bool blocking) { LLFilePicker::ELoadFilter filter=LLFilePicker::FFLOAD_DIRECTORY; - + return mFilePicker->getOpenFile(filter, true); } @@ -231,26 +231,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) return FALSE; } -#ifndef LL_FLTK -#if !LL_MESA_HEADLESS - - if (mFilePicker) - { - GtkWindow* picker = mFilePicker->buildFilePicker(false, true, - "dirpicker"); - - if (picker) - { - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - return (!mFilePicker->getFirstFile().empty()); - } - } -#endif // !LL_MESA_HEADLESS - - return FALSE; -#else +#ifdef LL_FLTK gViewerWindow->getWindow()->beforeDialog(); Fl_Native_File_Chooser flDlg; flDlg.title(LLTrans::getString("choose_the_directory").c_str()); @@ -286,7 +267,7 @@ std::string LLDirPicker::getDirName() #else // not implemented -LLDirPicker::LLDirPicker() +LLDirPicker::LLDirPicker() { reset(); } @@ -325,7 +306,7 @@ void LLDirPickerThread::getFile() #endif } -//virtual +//virtual void LLDirPickerThread::run() { #if LL_WINDOWS @@ -339,7 +320,7 @@ void LLDirPickerThread::run() if (picker.getDir(&mProposedName, blocking)) { mResponses.push_back(picker.getDirName()); - } + } { LLMutexLock lock(sMutex); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 7ca212e062..3704a5253c 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,6 +40,11 @@ #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers #endif // LL_SDL +#ifdef LL_FLTK + #include "FL/Fl.H" + #include "FL/Fl_Native_File_Chooser.H" +#endif + #if LL_LINUX #include "llhttpconstants.h" // file picker uses some of thes constants on Linux #endif @@ -112,7 +117,7 @@ LLFilePicker::~LLFilePicker() // nothing } -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLFilePicker::check_local_file_access_enabled() { @@ -267,7 +272,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) mOFN.nFilterIndex = 1; setupFilter(filter); - + if (blocking) { // Modal, so pause agent @@ -275,7 +280,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) } reset(); - + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! success = GetOpenFileName(&mOFN); if (success) @@ -290,7 +295,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) // Account for the fact that the app has been stalled. LLFrameTimer::updateFrameTime(); } - + return success; } @@ -476,7 +481,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, L"Targa Images (*.tga)\0*.tga\0" \ L"\0"; break; - + case FFSAVE_JPEG: if (filename.empty()) { @@ -569,7 +574,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, return FALSE; } - + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; @@ -696,11 +701,11 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) { return false; } - + gViewerWindow->getWindow()->beforeDialog(); - + std::unique_ptr<std::vector<std::string>> allowed_types = navOpenFilterProc(filter); - + std::unique_ptr<std::vector<std::string>> filev = doLoadDialog(allowed_types.get(), mPickOptions); @@ -712,7 +717,7 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) mFiles.insert(mFiles.end(), filev->begin(), filev->end()); return true; } - + return false; } @@ -725,14 +730,14 @@ bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, { return false; } - + std::unique_ptr<std::vector<std::string>> allowed_types=navOpenFilterProc(filter); - + doLoadDialogModeless(allowed_types.get(), mPickOptions, callback, userdata); - + return true; } @@ -786,13 +791,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "\?\?\?\?"; extension = "glb"; break; - + case LLFilePicker::FFSAVE_XML: type = "\?\?\?\?"; creator = "\?\?\?\?"; extension = "xml"; break; - + case LLFilePicker::FFSAVE_RAW: type = "\?\?\?\?"; creator = "\?\?\?\?"; @@ -804,13 +809,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "prvw"; extension = "j2c"; break; - + case LLFilePicker::FFSAVE_SCRIPT: type = "LSL "; creator = "\?\?\?\?"; extension = "lsl"; break; - + case LLFilePicker::FFSAVE_ALL: default: type = "\?\?\?\?"; @@ -824,16 +829,16 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; - + gViewerWindow->getWindow()->beforeDialog(); // Run the dialog - std::unique_ptr<std::string> filev = doSaveDialog(&namestring, + std::unique_ptr<std::string> filev = doSaveDialog(&namestring, &type, &creator, &extension, @@ -846,7 +851,7 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena mFiles.push_back(*filev); return true; } - + return false; } @@ -857,9 +862,9 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; @@ -888,11 +893,11 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - - if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. + + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY ); @@ -903,7 +908,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { mPickOptions |= F_NAV_SUPPORT; } - + if (blocking) // always true for linux/mac { // Modal, so pause agent @@ -912,7 +917,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) success = doNavChooseDialog(filter); - + if (success) { if (!getFileCount()) @@ -944,10 +949,10 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { @@ -973,11 +978,11 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { return FALSE; } - + BOOL success = FALSE; reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1023,7 +1028,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, } reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1045,7 +1050,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, } reset(); - + mPickOptions &= ~F_MULTIPLE; if (blocking) @@ -1079,7 +1084,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, { if( mLocked ) return false; - + // if local file browsing is turned off, return without opening dialog if ( check_local_file_access_enabled() == false ) { @@ -1087,7 +1092,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; return doNavSaveDialogModeless(filter, filename, callback, userdata); @@ -1096,488 +1101,228 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, #elif LL_LINUX -# if LL_GTK - -// static -void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) -{ - // We need to run g_filename_to_utf8 in the user's locale - std::string saved_locale(setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, ""); - - LLFilePicker* picker = (LLFilePicker*) user_data; - GError *error = NULL; - gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, - -1, NULL, NULL, &error); - if (error) - { - // *FIXME. - // This condition should really be notified to the user, e.g. - // through a message box. Just logging it is inappropriate. - - // g_filename_display_name is ideal, but >= glib 2.6, so: - // a hand-rolled hacky makeASCII which disallows control chars - std::string display_name; - for (const gchar *str = (const gchar *)data; *str; str++) - { - display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); - } - LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; - } - - if (filename_utf8) - { - picker->mFiles.push_back(std::string(filename_utf8)); - LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; - g_free(filename_utf8); - } +#if LL_FLTK - setlocale(LC_ALL, saved_locale.c_str()); -} - -// static -void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) -{ - LLFilePicker* picker = (LLFilePicker*)user_data; - - LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); - g_slist_foreach(file_list, (GFunc)g_free, NULL); - g_slist_free (file_list); - } - - // let's save the extension of the last added file(considering current filter) - GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); - if(gfilter) - { - std::string filter = gtk_file_filter_get_name(gfilter); - - if(filter == LLTrans::getString("png_image_files")) - { - picker->mCurrentExtension = ".png"; - } - else if(filter == LLTrans::getString("targa_image_files")) - { - picker->mCurrentExtension = ".tga"; - } - } - - // set the default path for this usage context. - const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); - if (cur_folder != NULL) - { - picker->mContextToPathMap[picker->mCurContextName] = cur_folder; - } - - gtk_widget_destroy(widget); - gtk_main_quit(); -} - - -GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) -{ -#ifndef LL_MESA_HEADLESS - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - GtkFileChooserAction pickertype = - is_save? - (is_folder? - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : - GTK_FILE_CHOOSER_ACTION_SAVE) : - (is_folder? - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : - GTK_FILE_CHOOSER_ACTION_OPEN); - - win = gtk_file_chooser_dialog_new(NULL, NULL, - pickertype, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - is_folder ? - GTK_STOCK_APPLY : - (is_save ? - GTK_STOCK_SAVE : - GTK_STOCK_OPEN), - GTK_RESPONSE_ACCEPT, - (gchar *)NULL); - mCurContextName = context; - - // get the default path for this usage context if it's been - // seen before. - std::map<std::string,std::string>::iterator - this_path = mContextToPathMap.find(context); - if (this_path != mContextToPathMap.end()) - { - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(win), - this_path->second.c_str()); - } - -# if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK raw X11 window, which should try - // to keep it on top etc. - Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); - if (None != XWindowID) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } - else - { - LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; - } -# endif //LL_X11 - - g_signal_connect (GTK_FILE_CHOOSER(win), - "response", - G_CALLBACK(LLFilePicker::chooser_responder), - this); - - gtk_window_set_modal(GTK_WINDOW(win), TRUE); - - /* GTK 2.6: if (is_folder) - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), - TRUE); */ - - return GTK_WINDOW(win); - } - else - { - return NULL; - } -#else - return NULL; -#endif //LL_MESA_HEADLESS -} - -static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, - GtkWindow *picker, - std::string filtername) -{ - gtk_file_filter_set_name(gfilter, filtername.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter); - GtkFileFilter *allfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(allfilter, "*"); - gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); -} - -static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, - std::string pattern, - std::string filtername) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, pattern.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, - std::string mime, - std::string filtername) +BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_mime_type(gfilter, mime.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; } -static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, + void (*callback)(bool, std::vector<std::string> &, void*), + void *userdata) { - return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", - LLTrans::getString("sound_files") + " (*.wav)"); + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; } -static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, + void (*callback)(bool, std::vector<std::string> &, void*), + void *userdata ) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.bvh"); - gtk_file_filter_add_pattern(gfilter, "*.anim"); - std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; } -static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", - LLTrans::getString("xml_files") + " (*.xml)"); -} -static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", - LLTrans::getString("scene_files") + " (*.dae)"); -} -static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("script_files") + " (*.lsl)"); + return openFileDialog( filter, blocking, eSaveFile ); } -static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); + return openFileDialog( filter, blocking, eOpenFile ); } -static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - GtkFileFilter *gfilter_tga = gtk_file_filter_new(); - GtkFileFilter *gfilter_png = gtk_file_filter_new(); - - gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); - gtk_file_filter_add_mime_type(gfilter_png, "image/png"); - std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; - gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); - gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); - - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_png); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_tga); - return caption; + return openFileDialog( filter, blocking, eOpenMultiple ); } -BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) +bool LLFilePicker::openFileDialog( int32_t filter, bool blocking, EType aType ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - + return false; gViewerWindow->getWindow()->beforeDialog(); - reset(); - - GtkWindow* picker = buildFilePicker(true, false, "savefile"); - - if (picker) + Fl_Native_File_Chooser::Type flType = Fl_Native_File_Chooser::BROWSE_FILE; + if( aType == eOpenMultiple ) + flType = Fl_Native_File_Chooser::BROWSE_MULTI_FILE; + else if( aType == eSaveFile ) + flType = Fl_Native_File_Chooser::BROWSE_SAVE_FILE; + Fl_Native_File_Chooser flDlg; + std::string file_dialog_title; + std::string file_dialog_filter; + if (aType == EType::eSaveFile) { - std::string suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) + std::string file_type("all_files"); + switch ((ESaveFilter) filter) { - case FFSAVE_WAV: - caption += add_wav_filter_to_gtkchooser(picker); - suggest_ext = ".wav"; - break; - case FFSAVE_TGA: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); - suggest_ext = ".tga"; - break; - case FFSAVE_BMP: - caption += add_simple_mime_filter_to_gtkchooser - (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); - suggest_ext = ".bmp"; - break; - case FFSAVE_PNG: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); - suggest_ext = ".png"; - break; - case FFSAVE_TGAPNG: - caption += add_save_texture_filter_to_gtkchooser(picker); - suggest_ext = ".png"; - break; - case FFSAVE_AVI: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "video/x-msvideo", - LLTrans::getString("avi_movie_file") + " (*.avi)"); - suggest_ext = ".avi"; - break; - case FFSAVE_ANIM: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); - suggest_ext = ".xaf"; - break; - case FFSAVE_XML: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); - suggest_ext = ".xml"; - break; - case FFSAVE_RAW: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); - suggest_ext = ".raw"; - break; - case FFSAVE_J2C: - // *TODO: Should this be 'image/j2c' ? - caption += add_simple_mime_filter_to_gtkchooser - (picker, "images/jp2", - LLTrans::getString("compressed_image_files") + " (*.j2c)"); - suggest_ext = ".j2c"; - break; - case FFSAVE_SCRIPT: - caption += add_script_filter_to_gtkchooser(picker); - suggest_ext = ".lsl"; - break; - default:; - break; + case FFSAVE_ALL: + break; + case FFSAVE_TGA: + file_type = "targa_image_files"; + file_dialog_filter = "*.tga"; + break; + case FFSAVE_BMP: + file_type = "bitmap_image_files"; + file_dialog_filter = "*.bmp"; + break; + case FFSAVE_AVI: + file_type = "avi_movie_file"; + file_dialog_filter = "*.avi"; + break; + case FFSAVE_ANIM: + file_type = "xaf_animation_file"; + file_dialog_filter = "*.xaf"; + break; + case FFSAVE_XML: + file_type = "xml_file"; + file_dialog_filter = "*.xml"; + break; + case FFSAVE_COLLADA: + file_type = "collada_files"; + file_dialog_filter = "*.dae"; + break; + case FFSAVE_RAW: + file_type = "raw_file"; + file_dialog_filter = "*.raw"; + break; + case FFSAVE_J2C: + file_type = "compressed_image_files"; + file_dialog_filter = "*.j2c"; + break; + case FFSAVE_PNG: + file_type = "png_image_files"; + file_dialog_filter = "*.png"; + break; + case FFSAVE_JPEG: + file_type = "jpeg_image_files"; + file_dialog_filter = "*.{jpg,jpeg}"; + break; + case FFSAVE_SCRIPT: + file_type = "script_files"; + file_dialog_filter = "*.lsl"; + break; + case FFSAVE_TGAPNG: + file_type = "save_texture_image_files"; + file_dialog_filter = "*.{tga,png}"; + break; + case FFSAVE_WAV: + file_type = "sound_files"; + file_dialog_filter = "*.wav"; + break; + case FFSAVE_GLTF: + file_type = "gltf_asset_file"; + file_dialog_filter = "*.{gltf,glb}"; + break; } - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - if (filename.empty()) + file_dialog_title = LLTrans::getString("save_file_verb") + " " + LLTrans::getString(file_type); + file_dialog_filter = LLTrans::getString(file_type) + " \t" + file_dialog_filter; + } + else + { + std::string file_type("all_files"); + switch ((ELoadFilter) filter) { - suggest_name += suggest_ext; + case FFLOAD_ALL: + break; + case FFLOAD_WAV: + file_type = "sound_files"; + file_dialog_filter = "*.wav"; + break; + case FFLOAD_IMAGE: + file_type = "image_files"; + file_dialog_filter = "*.{tga,bmp,jpg,jpeg,png}"; + break; + case FFLOAD_ANIM: + file_type = "animation_files"; + file_dialog_filter = "*.{bvh,anim}"; + break; + case FFLOAD_XML: + file_type = "xml_file"; + file_dialog_filter = "*.xml"; + break; + case FFLOAD_SLOBJECT: + file_type = "xml_file"; + file_dialog_filter = "*.slobject"; + break; + case FFLOAD_RAW: + file_type = "raw_file"; + file_dialog_filter = "*.raw"; + break; + case FFLOAD_MODEL: + case FFLOAD_COLLADA: + file_type = "collada_files"; + file_dialog_filter = "*.dae"; + break; + case FFLOAD_SCRIPT: + file_type = "script_files"; + file_dialog_filter = "*.lsl"; + break; + case FFLOAD_DICTIONARY: + file_type = "dictionary_files"; + file_dialog_filter = "*.{dic,xcu}"; + break; + case FFLOAD_DIRECTORY: + file_type = "choose_the_directory"; + break; + case FFLOAD_EXE: + file_type = "executable_files"; + break; + case FFLOAD_GLTF: + case FFLOAD_MATERIAL: + file_type = "gltf_asset_file"; + file_dialog_filter = "*.{gltg,glb}"; + break; + case FFLOAD_MATERIAL_TEXTURE: + file_dialog_filter = "*.{gltf,glb,tga,bmp,jpg,jpeg,png}"; + file_type = "image_files"; - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), - suggest_name.c_str()); } - else + if (aType == EType::eOpenMultiple) { - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), filename.c_str()); + file_dialog_title = LLTrans::getString("load_files"); } - - gtk_widget_show_all(GTK_WIDGET(picker)); - - gtk_main(); - - rtn = (getFileCount() == 1); - - if(rtn && filter == FFSAVE_TGAPNG) + else { - std::string selected_file = mFiles.back(); - mFiles.pop_back(); - mFiles.push_back(selected_file + mCurrentExtension); + file_dialog_title = LLTrans::getString("load_file_verb") + " " + LLTrans::getString(file_type); + file_dialog_filter = LLTrans::getString(file_type) + " \t" + file_dialog_filter; } } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; -} - -BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) -{ - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) + flDlg.title(file_dialog_title.c_str()); + flDlg.type(flType); + if (!file_dialog_filter.empty()) { - return FALSE; + flDlg.filter(file_dialog_filter.c_str()); } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) + int res = flDlg.show(); + gViewerWindow->getWindow()->afterDialog(); + if( res == 0 ) { - std::string caption = LLTrans::getString("load_file_verb") + " "; - std::string filtername = ""; - switch (filter) + int32_t count = flDlg.count(); + if( count < 0 ) + count = 0; + for( int32_t i = 0; i < count; ++i ) { - case FFLOAD_WAV: - filtername = add_wav_filter_to_gtkchooser(picker); - break; - case FFLOAD_ANIM: - filtername = add_anim_filter_to_gtkchooser(picker); - break; - case FFLOAD_XML: - filtername = add_xml_filter_to_gtkchooser(picker); - break; - case FFLOAD_GLTF: - filtername = dead_code_should_blow_up_here(picker); - break; - case FFLOAD_COLLADA: - filtername = add_collada_filter_to_gtkchooser(picker); - break; - case FFLOAD_IMAGE: - filtername = add_imageload_filter_to_gtkchooser(picker); - break; - case FFLOAD_SCRIPT: - filtername = add_script_filter_to_gtkchooser(picker); - break; - case FFLOAD_DICTIONARY: - filtername = add_dictionary_filter_to_gtkchooser(picker); - break; - default:; - break; + char const *pFile = flDlg.filename(i); + if( pFile && strlen(pFile) > 0 ) + mFiles.push_back( pFile ); } - - caption += filtername; - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; -} - -BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) -{ - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) + else if( res == -1 ) { - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), - TRUE); - - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - rtn = !mFiles.empty(); + LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL; } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + return mFiles.empty()?FALSE:TRUE; } - -# else // LL_GTK - +#else // Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with // static results, when we don't have a real filepicker. @@ -1591,7 +1336,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, } reset(); - + LL_INFOS() << "getSaveFile suggested filename is [" << filename << "]" << LL_ENDL; if (!filename.empty()) @@ -1621,7 +1366,7 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) } reset(); - + // HACK: Static filenames for 'open' until we implement filepicker std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; switch (filter) @@ -1665,13 +1410,13 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, return FALSE; } -#endif // LL_GTK +#endif // LL_FLTK #else // not implemented BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) { - reset(); + reset(); return FALSE; } diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 5686627776..5ac473755e 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.h * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,12 +33,6 @@ #ifndef LL_LLFILEPICKER_H #define LL_LLFILEPICKER_H -#if LL_FLTK - #if LL_GTK - #undef LL_GTK - #endif -#endif - #include "stdtypes.h" #if LL_DARWIN @@ -60,20 +54,8 @@ #include <commdlg.h> #endif -extern "C" { -// mostly for Linux, possible on others -#if LL_GTK -# include "gtk/gtk.h" -#error "Direct use of GTK is deprecated" -#endif // LL_GTK -} - class LLFilePicker { -#ifdef LL_GTK - friend class LLDirPicker; - friend void chooser_responder(GtkWidget *, gint, gpointer); -#endif // LL_GTK public: // calling this before main() is undefined static LLFilePicker& instance( void ) { return sInstance; } @@ -150,7 +132,7 @@ public: S32 getFileCount() const { return (S32)mFiles.size(); } // see lldir.h : getBaseFileName and getDirName to extract base or directory names - + // clear any lists of buffers or whatever, and make sure the file // picker isn't locked. void reset(); @@ -163,10 +145,10 @@ private: FILENAME_BUFFER_SIZE = 65000 }; - // utility function to check if access to local file system via file browser + // utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool check_local_file_access_enabled(); - + #if LL_WINDOWS OPENFILENAMEW mOFN; // for open and save dialogs WCHAR mFilesW[FILENAME_BUFFER_SIZE]; @@ -177,7 +159,7 @@ private: #if LL_DARWIN S32 mPickOptions; std::vector<std::string> mFileVector; - + bool doNavChooseDialog(ELoadFilter filter); bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector<std::string>&, void*), @@ -190,15 +172,6 @@ private: void *userdata); #endif -#if LL_GTK - static void add_to_selectedfiles(gpointer data, gpointer user_data); - static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); - // we remember the last path that was accessed for a particular usage - std::map <std::string, std::string> mContextToPathMap; - std::string mCurContextName; - // we also remember the extension of the last added file. - std::string mCurrentExtension; -#endif #if LL_FLTK enum EType { @@ -212,12 +185,6 @@ private: bool mLocked; static LLFilePicker sInstance; - -protected: -#if LL_GTK - GtkWindow* buildFilePicker(bool is_save, bool is_folder, - std::string context = "generic"); -#endif public: // don't call these directly please. -- cgit v1.2.3 From 295cff0fb5370f75749adf41a6c2d26c3431414c Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Mon, 15 Apr 2024 11:05:56 +0200 Subject: Fix broken shaders due to 72730609f371ae0417a2d117fdc9d805ce8858fb --- indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl | 2 +- .../newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl | 2 +- .../newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl | 2 +- .../newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl | 2 +- indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index acd32a81b3..0f9bd131fd 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -78,7 +78,7 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); float getAmbientClamp(); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance) diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl index 52e71edcac..35848ff4cd 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl @@ -55,7 +55,7 @@ vec4 sampleReflectionProbesDebug(vec3 pos) return vec4(0, 0, 0, 0); } -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear) { ambenv = vec3(reflection_probe_ambiance * 0.25); diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index 8430cca325..ab43262c0e 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -48,7 +48,7 @@ vec3 linear_to_srgb(vec3 c); vec3 srgb_to_linear(vec3 c); // reflection probe interface -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index 906e66ecc8..d19ec89cbc 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -785,7 +785,7 @@ vec4 sampleReflectionProbesDebug(vec3 pos) return col; } -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit) { float reflection_lods = max_probe_lod; diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 5e8fe9301a..f4a1df9c2c 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -70,7 +70,7 @@ vec3 scaleSoftClipFragLinear(vec3 l); // reflection probe interface void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); -- cgit v1.2.3 From 8f0c41c2e5d5c66df5e975b743140112494c4a7a Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn <nicky.dasmijn@posteo.nl> Date: Mon, 15 Apr 2024 22:59:16 +0200 Subject: Chore/pragma gcc cleansweep (#1226) * Remove all GCC warning suppression pragmas. * For Linux just just raise(SIGSEGV) as the crash driver. This has a much higher chance of the compiler understanding out intent and figuring out we end the program here. * Remove -Wno-stringop-overflow and -Wno-stringop-truncation from GCC_WARNINGS. After calling raise(SIGSEGV) as the crash driver I saw no issue with those warnings anymore After removing thoses GCC pragmas there is also no need for clang -Wno-unknown-warning-option anymore. * Remove CMakePresets from this PR. * Remove Lindens from comments :) --- indra/newview/llface.cpp | 312 ++++++++++++++++++++-------------------- indra/newview/llviewerstats.cpp | 93 ++++++------ 2 files changed, 197 insertions(+), 208 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index b6405df1ff..698ba0c01e 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llface.cpp * @brief LLFace class implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,12 +57,6 @@ #include "llsculptidsize.h" #include "llmeshrepository.h" -#if LL_LINUX -// Work-around spurious used before init warning on Vector4a -// -#pragma GCC diagnostic ignored "-Wuninitialized" -#endif - #define LL_MAX_INDICES_COUNT 1000000 static LLStaticHashedString sTextureIndexIn("texture_index_in"); @@ -87,7 +81,7 @@ The resulting texture coordinate <u,v> is: */ void planarProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a ¢er, const LLVector4a& vec) -{ +{ LLVector4a binormal; F32 d = normal[0]; @@ -146,7 +140,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) //special value to indicate uninitialized position mIndicesIndex = 0xFFFFFFFF; - + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { mIndexInTex[i] = 0; @@ -188,7 +182,7 @@ void LLFace::destroy() mTexture[i] = NULL; } } - + if (isState(LLFace::PARTICLE)) { clearState(LLFace::PARTICLE); @@ -215,7 +209,7 @@ void LLFace::destroy() } } } - + setDrawInfo(NULL); mDrawablep = NULL; @@ -262,11 +256,11 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) } mDrawPoolp = new_pool; } - + setTexture(texturep) ; } -void LLFace::setTexture(U32 ch, LLViewerTexture* tex) +void LLFace::setTexture(U32 ch, LLViewerTexture* tex) { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); @@ -278,8 +272,8 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) if(mTexture[ch].notNull()) { mTexture[ch]->removeFace(ch, this) ; - } - + } + if(tex) { tex->addFace(ch, this) ; @@ -288,7 +282,7 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) mTexture[ch] = tex ; } -void LLFace::setTexture(LLViewerTexture* tex) +void LLFace::setTexture(LLViewerTexture* tex) { setDiffuseMap(tex); } @@ -362,7 +356,7 @@ void LLFace::switchTexture(U32 ch, LLViewerTexture* new_texture) getViewerObject()->changeTEImage(mTEOffset, new_texture) ; } - setTexture(ch, new_texture) ; + setTexture(ch, new_texture) ; dirtyTexture(); } @@ -396,7 +390,7 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) //allocate vertices in blocks of 4 for alignment num_vertices = (num_vertices + 0x3) & ~0x3; } - + if (mGeomCount != num_vertices || mIndicesCount != num_indices) { @@ -408,11 +402,11 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) llassert(verify()); } -void LLFace::setGeomIndex(U16 idx) -{ +void LLFace::setGeomIndex(U16 idx) +{ if (mGeomIndex != idx) { - mGeomIndex = idx; + mGeomIndex = idx; mVertexBuffer = NULL; } } @@ -437,15 +431,15 @@ void LLFace::setTextureIndex(U8 index) } } -void LLFace::setIndicesIndex(S32 idx) -{ +void LLFace::setIndicesIndex(S32 idx) +{ if (mIndicesIndex != idx) { - mIndicesIndex = idx; + mIndicesIndex = idx; mVertexBuffer = NULL; } } - + //============================================================================ U16 LLFace::getGeometryAvatar( @@ -484,7 +478,7 @@ U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount); } - + return mGeomIndex; } @@ -511,7 +505,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) mDrawablep->getSpatialGroup()->rebuildGeom(); mDrawablep->getSpatialGroup()->rebuildMesh(); - + if(mVertexBuffer.isNull()) { return; @@ -520,7 +514,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) if (mGeomCount > 0 && mIndicesCount > 0) { gGL.getTexUnit(0)->bind(imagep); - + gGL.pushMatrix(); if (mDrawablep->isActive()) { @@ -532,7 +526,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) } gGL.diffuseColor4fv(color.mV); - + if (mDrawablep->isState(LLDrawable::RIGGED)) { #if 0 // TODO -- there is no way this won't destroy our GL machine as implemented, rewrite it to not rely on software skinning @@ -730,7 +724,7 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of F32 t = tex_coord.mV[1]; // Texture transforms are done about the center of the face. - s -= 0.5; + s -= 0.5; t -= 0.5; // Handle rotation @@ -743,7 +737,7 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of t *= magT; // Then offset - s += offS + 0.5f; + s += offS + 0.5f; t += offT + 0.5f; tex_coord.mV[0] = s; @@ -751,17 +745,17 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of } // Transform the texture coordinates for this face. -static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) +static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) { //tex coord is two coords, <s0, t0, s1, t1> LLVector4a st; // Texture transforms are done about the center of the face. st.setAdd(tex_coord, trans); - + // Handle rotation LLVector4a rot_st; - + // <s0 * cosAng, s0*-sinAng, s1*cosAng, s1*-sinAng> LLVector4a s0; s0.splat(st, 0); @@ -770,9 +764,9 @@ static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVect LLVector4a ss; ss.setSelectWithMask(mask, s1, s0); - LLVector4a a; + LLVector4a a; a.setMul(rot0, ss); - + // <t0*sinAng, t0*cosAng, t1*sinAng, t1*cosAng> LLVector4a t0; t0.splat(st, 1); @@ -783,7 +777,7 @@ static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVect LLVector4a b; b.setMul(rot1, tt); - + st.setAdd(a,b); // Then scale @@ -803,7 +797,7 @@ bool less_than_max_mag(const LLVector4a& vec) val.setAbs(vec); S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7; - + return lt == 0x7; } @@ -822,20 +816,20 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, } const LLVolumeFace &face = volume.getVolumeFace(f); - - LL_DEBUGS("RiggedBox") << "updating extents for face " << f - << " starting extents " << mExtents[0] << ", " << mExtents[1] - << " starting vf extents " << face.mExtents[0] << ", " << face.mExtents[1] + + LL_DEBUGS("RiggedBox") << "updating extents for face " << f + << " starting extents " << mExtents[0] << ", " << mExtents[1] + << " starting vf extents " << face.mExtents[0] << ", " << face.mExtents[1] << " num verts " << face.mNumVertices << LL_ENDL; // MAINT-8264 - stray vertices, especially in low LODs, cause bounding box errors. - if (face.mNumVertices < 3) + if (face.mNumVertices < 3) { - LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices " + LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices " << face.mNumVertices << " " << face.mNumIndices << " " << face.mWeights << LL_ENDL; return FALSE; } - + //VECTORIZE THIS LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); @@ -845,7 +839,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, matMulBoundBox(mat_vert, face.mExtents, mExtents); - LL_DEBUGS("RiggedBox") << "updated extents for face " << f + LL_DEBUGS("RiggedBox") << "updated extents for face " << f << " bbox gave extents " << mExtents[0] << ", " << mExtents[1] << LL_ENDL; if (!mDrawablep->isActive()) @@ -854,11 +848,11 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); mExtents[0].add(offset); mExtents[1].add(offset); - LL_DEBUGS("RiggedBox") << "updating extents for face " << f + LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " not active, added offset " << offset << LL_ENDL; } - LL_DEBUGS("RiggedBox") << "updated extents for face " << f + LL_DEBUGS("RiggedBox") << "updated extents for face " << f << " to " << mExtents[0] << ", " << mExtents[1] << LL_ENDL; LLVector4a t; t.setAdd(mExtents[0],mExtents[1]); @@ -885,7 +879,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal) { LLVector2 tc = surface_coord; - + const LLTextureEntry *tep = getTextureEntry(); if (tep == NULL) @@ -900,28 +894,28 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& po if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter); - + LLVector4a volume_position; LLVector3 v_position(position.getF32ptr()); volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(v_position).mV); - + if (!mDrawablep->getVOVolume()->isVolumeGlobal()) { LLVector4a scale; scale.load3(mVObjp->getScale().mV); volume_position.mul(scale); } - + LLVector4a volume_normal; LLVector3 v_normal(normal.getF32ptr()); volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(v_normal).mV); volume_normal.normalize3fast(); - + if (texgen == LLTextureEntry::TEX_GEN_PLANAR) { planarProjection(tc, volume_normal, center, volume_position); - } + } } if (mTextureMatrix) // if we have a texture matrix, use it @@ -930,14 +924,14 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& po tc3 = tc3 * *mTextureMatrix; tc = LLVector2(tc3); } - + else // otherwise use the texture entry parameters { xform(tc, cos(tep->getRotation()), sin(tep->getRotation()), tep->mOffsetS, tep->mOffsetT, tep->mScaleS, tep->mScaleT); } - + return tc; } @@ -978,7 +972,7 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po } // Returns the necessary texture transform to align this face's TE to align_to's TE -bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offset, +bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offset, LLVector2* res_st_scale, F32* res_st_rot, LLRender::eTexIndex map) const { if (!align_to) @@ -1101,13 +1095,13 @@ bool LLFace::canRenderAsMask() return false; } - + LLMaterial* mat = te->getMaterialParams(); if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) { return false; } - + if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha (te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive) @@ -1171,7 +1165,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, const LLVolumeFace &vf = volume.getVolumeFace(face_index); S32 num_vertices = (S32)vf.mNumVertices; S32 num_indices = (S32) vf.mNumIndices; - + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) { updateRebuildFlags(); @@ -1217,7 +1211,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLStrider<LLVector4> wght; BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); - + BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); LLVector3 scale; if (global_volume) @@ -1228,7 +1222,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { scale = mVObjp->getScale(); } - + bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); bool rebuild_emissive = rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); @@ -1244,7 +1238,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, BOOL is_global = is_static; LLVector3 center_sum(0.f, 0.f, 0.f); - + if (is_global) { setState(GLOBAL); @@ -1263,13 +1257,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color) { //decide if shiny goes in alpha channel of color - if (tep && + if (tep && !isInAlphaPool()) // <--- alpha channel MUST contain transparency, not shiny { LLMaterial* mat = tep->getMaterialParams().get(); - + bool shiny_in_alpha = false; - + //store shiny in alpha if we don't have a specular map if (!mat || mat->getSpecularID().isNull()) { @@ -1285,7 +1279,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, 0.5f, 0.75f }; - + llassert(tep->getShiny() <= 3); color.mV[3] = U8 (SHININESS_TO_ALPHA[tep->getShiny()] * 255); } @@ -1303,7 +1297,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, __m128i offset = _mm_set1_epi16(index_offset); S32 end = num_indices/8; - + for (S32 i = 0; i < end; i++) { __m128i res = _mm_add_epi16(src[i], offset); @@ -1320,7 +1314,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } } - + LLMaterial* mat = tep->getMaterialParams().get(); LLGLTFMaterial* gltf_mat = tep->getGLTFRenderMaterial(); @@ -1390,7 +1384,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } } - + const LLMeshSkinInfo* skin = nullptr; LLMatrix4a mat_vert; LLMatrix4a mat_normal; @@ -1438,7 +1432,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord"); - + //bump setup LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); @@ -1449,11 +1443,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); } - + if (bump_code) { mVObjp->getVolume()->genTangents(face_index); - F32 offset_multiple; + F32 offset_multiple; switch( bump_code ) { case BE_NO_BUMP: @@ -1488,7 +1482,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, tep->getScale( &s_scale, &t_scale ); } // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when + // that emboss mapping always shows up on the upward faces of cubes when // it's noon (since a lot of builders build with the sun forced to noon). LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; LLVector3 moon_ray = gSky.mVOSkyp->getMoon().getDirection(); @@ -1505,10 +1499,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } U8 tex_mode = 0; - + bool tex_anim = false; - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; tex_mode = vobj->mTexAnimMode; if (vobj->mTextureAnimp) @@ -1549,7 +1543,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, do_bump = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1) || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2); } - + // For GLTF materials: Transforms will be applied later bool do_tex_mat = tex_mode && mTextureMatrix && !gltf_mat; @@ -1597,7 +1591,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, U32 count = num_vertices/2 + num_vertices%2; for (S32 i = 0; i < count; i++) - { + { LLVector4a res = *src++; xform4a(res, trans, mask, rot0, rot1, offset, scale); res.store4a(dst); @@ -1608,14 +1602,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, else { //do tex mat, no texgen, no bump for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); - + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; - *tex_coords0++ = tc; + *tex_coords0++ = tc; } } } @@ -1625,50 +1619,50 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; + LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); - + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; - - *tex_coords0++ = tc; + + *tex_coords0++ = tc; } } else if (xforms != XFORM_NONE) { for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; + LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); - + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords0++ = tc; + *tex_coords0++ = tc; } } else { for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; + LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); - *tex_coords0++ = tc; + *tex_coords0++ = tc; } } } @@ -1678,7 +1672,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default"); std::vector<LLVector2> bump_tc; - + if (mat && !mat->getNormalID().isNull()) { //writing out normal and specular texture coordinates, not bump offsets do_bump = false; @@ -1691,9 +1685,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, S32 xform_channel = XFORM_NONE; switch (ch) { - case 0: + case 0: xform_channel = XFORM_BLINNPHONG_COLOR; - mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount); + mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount); break; case 1: xform_channel = XFORM_BLINNPHONG_NORMAL; @@ -1738,26 +1732,26 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, break; } const bool do_xform = (xforms & xform_channel) != XFORM_NONE; - + for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); - + LLVector4a& norm = vf.mNormals[i]; - + LLVector4a& center = *(vf.mCenter); - + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a vec = vf.mPositions[i]; - + vec.mul(scalea); if (texgen == LLTextureEntry::TEX_GEN_PLANAR) { planarProjection(tc, norm, center, vec); - } + } } if (tex_mode && mTextureMatrix) @@ -1783,7 +1777,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if ((!mat && !gltf_mat) && do_bump) { mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount); - + mVObjp->getVolume()->genTangents(face_index); for (S32 i = 0; i < num_vertices; i++) @@ -1800,7 +1794,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, tangent_to_object.rotate(binormal_dir, t); LLVector4a binormal; mat_normal.rotate(t, binormal); - + //VECTORIZE THIS if (mDrawablep->isActive()) { @@ -1814,7 +1808,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector2 tc = bump_tc[i]; tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); - + *tex_coords1++ = tc; } } @@ -1824,23 +1818,23 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_pos) { LLVector4a* src = vf.mPositions; - + //_mm_prefetch((char*)src, _MM_HINT_T0); LLVector4a* end = src+num_vertices; //LLVector4a* end_64 = end-4; llassert(num_vertices > 0); - + mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount); - - + + F32* dst = (F32*) vert.get(); F32* end_f32 = dst+mGeomCount*4; //_mm_prefetch((char*)dst, _MM_HINT_NTA); //_mm_prefetch((char*)src, _MM_HINT_NTA); - + //_mm_prefetch((char*)dst, _MM_HINT_NTA); @@ -1853,26 +1847,26 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, F32 val = 0.f; S32* vp = (S32*) &val; *vp = index; - + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); LLVector4Logical mask; mask.clear(); mask.setElement<3>(); - + texIdx.set(0,0,0,val); LLVector4a tmp; - + while (src < end) - { + { mat_vert.affineTransform(*src++, res0); tmp.setSelectWithMask(mask, texIdx, res0); tmp.store4a((F32*) dst); dst += 4; } - + while (dst < end_f32) { res0.store4a((F32*) dst); @@ -1888,24 +1882,24 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, F32* normals = (F32*) norm.get(); LLVector4a* src = vf.mNormals; LLVector4a* end = src+num_vertices; - + while (src < end) - { + { LLVector4a normal; mat_normal.rotate(*src++, normal); normal.store4a(normals); normals += 4; } } - + if (rebuild_tangent) { LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent"); mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount); F32* tangents = (F32*) tangent.get(); - + mVObjp->getVolume()->genTangents(face_index); - + LLVector4Logical mask; mask.clear(); mask.setElement<3>(); @@ -1919,12 +1913,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mat_normal.rotate(*src, tangent_out); tangent_out.setSelectWithMask(mask, *src, tangent_out); tangent_out.store4a(tangents); - + src++; tangents += 4; } } - + if (rebuild_weights && vf.mWeights) { LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight"); @@ -1942,7 +1936,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, U32 vec[4]; vec[0] = vec[1] = vec[2] = vec[3] = color.asRGBA(); - + src.loadua((F32*) vec); F32* dst = (F32*) colors.get(); @@ -1953,7 +1947,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } for (S32 i = 0; i < num_vecs; i++) - { + { src.store4a(dst); dst += 4; } @@ -1969,14 +1963,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a src; - + LLColor4U glow4u = LLColor4U(0,0,0,glow); U32 glow32 = glow4u.asRGBA(); U32 vec[4]; vec[0] = vec[1] = vec[2] = vec[3] = glow32; - + src.loadua((F32*) vec); F32* dst = (F32*) emissive.get(); @@ -1987,7 +1981,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } for (S32 i = 0; i < num_vecs; i++) - { + { src.store4a(dst); dst += 4; } @@ -2000,7 +1994,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mTexExtents[1].setVec(1,1); xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); - + F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; mTexExtents[0][0] *= es ; @@ -2023,13 +2017,13 @@ void LLFace::renderIndexed() } //check if the face has a media -BOOL LLFace::hasMedia() const +BOOL LLFace::hasMedia() const { if(mHasMedia) { return TRUE ; } - if(mTexture[LLRender::DIFFUSE_MAP].notNull()) + if(mTexture[LLRender::DIFFUSE_MAP].notNull()) { return mTexture[LLRender::DIFFUSE_MAP]->hasParcelMedia() ; //if has a parcel media } @@ -2050,7 +2044,7 @@ F32 LLFace::getTextureVirtualSize() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; F32 radius; - F32 cos_angle_to_view_dir; + F32 cos_angle_to_view_dir; BOOL in_frustum = calcPixelArea(cos_angle_to_view_dir, radius); if (mPixelArea < F_ALMOST_ZERO || !in_frustum) @@ -2085,9 +2079,9 @@ F32 LLFace::getTextureVirtualSize() if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping. { if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->isLargeImage()) - { + { face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius ); - } + } } setVirtualSize(face_area) ; @@ -2135,7 +2129,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) LLVector4a t; t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); - + F32 dist = lookAt.getLength3().getF32(); dist = llmax(dist-size.getLength3().getF32(), 0.001f); //ramp down distance for nearby objects @@ -2146,7 +2140,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) dist *= 16.f; } - lookAt.normalize3fast() ; + lookAt.normalize3fast() ; //get area of circle around node F32 app_angle = atanf((F32) sqrt(size_squared) / dist); @@ -2156,10 +2150,10 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); - //if has media, check if the face is out of the view frustum. + //if has media, check if the face is out of the view frustum. if(hasMedia()) { - if(!camera->AABBInFrustum(center, size)) + if(!camera->AABBInFrustum(center, size)) { mImportanceToCamera = 0.f ; return false ; @@ -2169,7 +2163,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) cos_angle_to_view_dir = 1.0f ; } else - { + { LLVector4a d; d.setSub(lookAt, x_axis); @@ -2186,7 +2180,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) mImportanceToCamera = 1.0f ; } else - { + { mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ; } @@ -2207,10 +2201,10 @@ F32 LLFace::adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius //F32 radius_square = radius * radius ; //F32 d_square = d * d ; //F32 screen_radius_square = screen_radius * screen_radius ; - //face_area = + //face_area = // radius_square * acosf((d_square + radius_square - screen_radius_square)/(2 * d * radius)) + // screen_radius_square * acosf((d_square + screen_radius_square - radius_square)/(2 * d * screen_radius)) - - // 0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ; + // 0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ; //---------------------------------------------- //the above calculation is too expensive @@ -2228,13 +2222,13 @@ const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL][2] = // const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[FACE_IMPORTANCE_LEVEL][2] = //{cos(angle), importance_weight} {{0.985f /*cos(10 degrees)*/, 1.0f}, {0.94f /*cos(20 degrees)*/, 0.8f}, {0.866f /*cos(30 degrees)*/, 0.64f}, {0.0f, 0.36f}} ; -//static +//static F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) { F32 importance = 0.f ; - - if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() && - dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0]) + + if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() && + dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0]) { LLViewerCamera* camera = LLViewerCamera::getInstance(); F32 camera_moving_speed = camera->getAverageSpeed() ; @@ -2245,12 +2239,12 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) //if camera moves or rotates too fast, ignore the importance factor return 0.f ; } - + S32 i = 0 ; for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i); i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ; F32 dist_factor = FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][1] ; - + for(i = 0; i < FACE_IMPORTANCE_LEVEL && cos_angle_to_view_dir < FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][0] ; ++i) ; i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ; importance = dist_factor * FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][1] ; @@ -2259,7 +2253,7 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) return importance ; } -//static +//static F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area) { if(pixel_area > LLViewerTexture::sMaxSmallImageSize) @@ -2274,7 +2268,7 @@ F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area) if(importance < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res. { pixel_area = LLViewerTexture::sMinLargeImageSize ; - } + } } } @@ -2289,7 +2283,7 @@ BOOL LLFace::verify(const U32* indices_array) const { //no vertex buffer, face is implicitly valid return TRUE; } - + // First, check whether the face data fits within the pool's range. if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) { @@ -2298,18 +2292,18 @@ BOOL LLFace::verify(const U32* indices_array) const } S32 indices_count = (S32)getIndicesCount(); - + if (!indices_count) { return TRUE; } - + if (indices_count > LL_MAX_INDICES_COUNT) { ok = FALSE; LL_INFOS() << "Face has bogus indices count" << LL_ENDL; } - + if (mIndicesIndex + mIndicesCount > mVertexBuffer->getNumIndices()) { ok = FALSE; @@ -2368,7 +2362,7 @@ S32 LLFace::getColors(LLStrider<LLColor4U> &colors) { return -1; } - + // llassert(mGeomIndex >= 0); mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount); return mGeomIndex; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index c1f4f858c1..9d4022fda1 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerstats.cpp * @brief LLViewerStats class implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,10 +36,10 @@ #include "llappviewer.h" -#include "pipeline.h" -#include "lltexturefetch.h" -#include "llviewerobjectlist.h" -#include "llviewertexturelist.h" +#include "pipeline.h" +#include "lltexturefetch.h" +#include "llviewerobjectlist.h" +#include "llviewertexturelist.h" #include "lltexlayer.h" #include "lltexlayerparams.h" #include "llsurface.h" @@ -67,11 +67,6 @@ #include "lluiusage.h" #include "lltranslate.h" -#if LL_LINUX -#pragma GCC diagnostic ignored "-Wunused-value" // Happens due to LL_DEBUGS("LogViewerStatsPacket"); Does that even do anything? -#endif - - // "Minimal Vulkan" to get max API Version // Calls @@ -147,13 +142,13 @@ LLTrace::CountStatHandle<> FPS("FPS", "Frames rendered"), TEX_REBAKES("texrebakes", "Number of times avatar textures have been forced to rebake"), NUM_NEW_OBJECTS("numnewobjectsstat", "Number of objects in scene that were not previously in cache"); -LLTrace::CountStatHandle<LLUnit<F64, LLUnits::Kilotriangles> > +LLTrace::CountStatHandle<LLUnit<F64, LLUnits::Kilotriangles> > TRIANGLES_DRAWN("trianglesdrawnstat"); LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Kilotriangles> > TRIANGLES_DRAWN_PER_FRAME("trianglesdrawnperframestat"); -LLTrace::CountStatHandle<F64Kilobytes > +LLTrace::CountStatHandle<F64Kilobytes > ACTIVE_MESSAGE_DATA_RECEIVED("activemessagedatareceived", "Message system data received on all active regions"), LAYERS_NETWORK_DATA_RECEIVED("layersdatareceived", "Network data received for layer data (terrain)"), OBJECT_NETWORK_DATA_RECEIVED("objectdatareceived", "Network data received for objects"), @@ -162,7 +157,7 @@ LLTrace::CountStatHandle<F64Kilobytes > MESSAGE_SYSTEM_DATA_IN("messagedatain", "Incoming message system network data"), MESSAGE_SYSTEM_DATA_OUT("messagedataout", "Outgoing message system network data"); -LLTrace::CountStatHandle<F64Seconds > +LLTrace::CountStatHandle<F64Seconds > SIM_20_FPS_TIME("sim20fpstime", "Seconds with sim FPS below 20"), SIM_PHYSICS_20_FPS_TIME("simphysics20fpstime", "Seconds with physics FPS below 20"), LOSS_5_PERCENT_TIME("loss5percenttime", "Seconds with packet loss > 5%"); @@ -186,7 +181,7 @@ SimMeasurement<> SIM_TIME_DILATION("simtimedilation", "Simulator time scale", SIM_PHYSICS_PINNED_TASKS("physicspinnedtasks", "", LL_SIM_STAT_PHYSICS_PINNED_TASKS), SIM_PHYSICS_LOD_TASKS("physicslodtasks", "", LL_SIM_STAT_PHYSICS_LOD_TASKS); -SimMeasurement<LLUnit<F64, LLUnits::Percent> > +SimMeasurement<LLUnit<F64, LLUnits::Percent> > SIM_PERCENTAGE_SCRIPTS_RUN("simpctscriptsrun", "", LL_SIM_STAT_PCTSCRIPTSRUN), SIM_SKIPPED_CHARACTERS_PERCENTAGE("simsimpctsteppedcharacters", "", LL_SIM_STAT_PCTSTEPPEDCHARACTERS); @@ -203,17 +198,17 @@ LLTrace::SampleStatHandle<> FPS_SAMPLE("fpssample"), WINDOW_WIDTH("windowwidth", "Window width"), WINDOW_HEIGHT("windowheight", "Window height"); -LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > PACKETS_LOST_PERCENT("packetslostpercentstat"); -static LLTrace::SampleStatHandle<bool> +static LLTrace::SampleStatHandle<bool> CHAT_BUBBLES("chatbubbles", "Chat Bubbles Enabled"); LLTrace::SampleStatHandle<F64Megabytes > FORMATTED_MEM("formattedmemstat"); LLTrace::SampleStatHandle<F64Kilobytes > DELTA_BANDWIDTH("deltabandwidth", "Increase/Decrease in bandwidth based on packet loss"), MAX_BANDWIDTH("maxbandwidth", "Max bandwidth setting"); - + SimMeasurement<F64Milliseconds > SIM_FRAME_TIME("simframemsec", "", LL_SIM_STAT_FRAMEMS), SIM_NET_TIME("simnetmsec", "", LL_SIM_STAT_NETMS), SIM_OTHER_TIME("simsimothermsec", "", LL_SIM_STAT_SIMOTHERMS), @@ -228,7 +223,7 @@ SimMeasurement<F64Milliseconds > SIM_FRAME_TIME("simframemsec", "", LL_SIM_STAT_ SIM_SPARE_TIME("simsparemsec", "", LL_SIM_STAT_SIMSPARETIME), SIM_SLEEP_TIME("simsleepmsec", "", LL_SIM_STAT_SIMSLEEPTIME), SIM_PUMP_IO_TIME("simpumpiomsec", "", LL_SIM_STAT_IOPUMPTIME); - + SimMeasurement<F64Kilobytes > SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_SIM_STAT_TOTAL_UNACKED_BYTES); SimMeasurement<F64Megabytes > SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY); @@ -240,7 +235,7 @@ LLTrace::SampleStatHandle<F64Milliseconds > FRAMETIME_JITTER("frametimejitter", LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); LLTrace::EventStatHandle<> LOADING_WEARABLES_LONG_DELAY("loadingwearableslongdelay", "Wearables took too long to load"); - + LLTrace::EventStatHandle<F64Milliseconds > REGION_CROSSING_TIME("regioncrossingtime", "CROSSING_AVG"), FRAME_STACKTIME("framestacktime", "FRAME_SECS"), UPDATE_STACKTIME("updatestacktime", "UPDATE_SECS"), @@ -248,7 +243,7 @@ LLTrace::EventStatHandle<F64Milliseconds > REGION_CROSSING_TIME("regioncrossingt IMAGE_STACKTIME("imagestacktime", "IMAGE_SECS"), REBUILD_STACKTIME("rebuildstacktime", "REBUILD_SECS"), RENDER_STACKTIME("renderstacktime", "RENDER_SECS"); - + LLTrace::EventStatHandle<F64Seconds > AVATAR_EDIT_TIME("avataredittime", "Seconds in Edit Appearance"), TOOLBOX_TIME("toolboxtime", "Seconds using Toolbox"), MOUSELOOK_TIME("mouselooktime", "Seconds in Mouselook"), @@ -268,7 +263,7 @@ LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > SWAP_FRAME_PCT("swap_ LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > IDLE_FRAME_PCT("idle_frame_pct"); } -LLViewerStats::LLViewerStats() +LLViewerStats::LLViewerStats() : mLastTimeDiff(0.0) { getRecording().start(); @@ -288,20 +283,20 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) { add(LLStatViewer::LOSS_5_PERCENT_TIME, time_diff); } - + F32 sim_fps = getRecording().getLastValue(LLStatViewer::SIM_FPS); if (0.f < sim_fps && sim_fps < 20.f) { add(LLStatViewer::SIM_20_FPS_TIME, time_diff); } - + F32 sim_physics_fps = getRecording().getLastValue(LLStatViewer::SIM_PHYSICS_FPS); if (0.f < sim_physics_fps && sim_physics_fps < 20.f) { add(LLStatViewer::SIM_PHYSICS_20_FPS_TIME, time_diff); } - + if (time_diff >= (F64Seconds)0.5) { record(LLStatViewer::FPS_2_TIME, time_diff); @@ -325,7 +320,7 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) // old stats that were never really used F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff)); sample(LLStatViewer::FRAMETIME_JITTER, jit); - + F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount; sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff)); @@ -334,39 +329,39 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) sample(LLStatViewer::DELTA_BANDWIDTH, F64Bits(delta_bandwidth)); sample(LLStatViewer::MAX_BANDWIDTH, F64Bits(max_bandwidth)); } - + mLastTimeDiff = time_diff; } void LLViewerStats::addToMessage(LLSD &body) { LLSD &misc = body["misc"]; - + misc["Version"] = TRUE; //TODO RN: get last value, not mean misc["Vertex Buffers Enabled"] = getRecording().getMean(LLStatViewer::ENABLE_VBO); - + body["AgentPositionSnaps"] = getRecording().getSum(LLStatViewer::AGENT_POSITION_SNAP).value(); //mAgentPositionSnaps.asLLSD(); - LL_INFOS() << "STAT: AgentPositionSnaps: Mean = " << getRecording().getMean(LLStatViewer::AGENT_POSITION_SNAP).value() << "; StdDev = " << getRecording().getStandardDeviation(LLStatViewer::AGENT_POSITION_SNAP).value() + LL_INFOS() << "STAT: AgentPositionSnaps: Mean = " << getRecording().getMean(LLStatViewer::AGENT_POSITION_SNAP).value() << "; StdDev = " << getRecording().getStandardDeviation(LLStatViewer::AGENT_POSITION_SNAP).value() << "; Count = " << getRecording().getSampleCount(LLStatViewer::AGENT_POSITION_SNAP) << LL_ENDL; } // *NOTE:Mani The following methods used to exist in viewer.cpp // Moving them here, but not merging them into LLViewerStats yet. -U32 gTotalLandIn = 0, +U32 gTotalLandIn = 0, gTotalLandOut = 0, - gTotalWaterIn = 0, + gTotalWaterIn = 0, gTotalWaterOut = 0; -F32 gAveLandCompression = 0.f, +F32 gAveLandCompression = 0.f, gAveWaterCompression = 0.f, gBestLandCompression = 1.f, gBestWaterCompression = 1.f, - gWorstLandCompression = 0.f, + gWorstLandCompression = 0.f, gWorstWaterCompression = 0.f; -U32Bytes gTotalWorldData, - gTotalObjectData, +U32Bytes gTotalWorldData, + gTotalObjectData, gTotalTextureData; U32 gSimPingCount = 0; U32Bits gObjectData; @@ -447,7 +442,7 @@ void update_statistics() world->updateNetStats(); world->requestCacheMisses(); } - + // Reset all of these values. gVLManager.resetBitCounts(); gObjectData = (U32Bytes)0; @@ -481,7 +476,7 @@ void update_statistics() // auto tot_avatar_render_time_raw = tot_avatar_time_raw - tot_av_idle_time_raw; // the time spent this frame on the "display()" call. Treated as "tot time rendering" auto tot_render_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_DISPLAY); - // sleep time is basically forced sleep when window out of focus + // sleep time is basically forced sleep when window out of focus auto tot_sleep_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SLEEP); // time spent on UI auto tot_ui_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_UI); @@ -577,11 +572,11 @@ void send_viewer_stats(bool include_preferences) LL_WARNS() << "Could not get ViewerStats capability" << LL_ENDL; return; } - + LLViewerStats::instance().getRecording().pause(); LLSD &agent = body["agent"]; - + time_t ltime; time(<ime); F32 run_time = F32(LLFrameTimer::getElapsedSeconds()); @@ -607,7 +602,7 @@ void send_viewer_stats(bool include_preferences) agent["version"] = LLVersionInfo::instance().getChannelAndVersion(); std::string language = LLUI::getLanguage(); agent["language"] = language; - + agent["sim_fps"] = ((F32) gFrameCount - gSimFrames) / (F32) (gRenderStartTime.getElapsedTimeF32() - gSimLastTime); @@ -622,7 +617,7 @@ void send_viewer_stats(bool include_preferences) agent["translation"] = LLTranslate::instance().asLLSD(); LLSD &system = body["system"]; - + system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB().value(); system["os"] = LLOSInfo::instance().getOSStringSimple(); system["cpu"] = gSysCPU.getCPUString(); @@ -673,7 +668,7 @@ void send_viewer_stats(bool include_preferences) { shader_level = 2; } - + system["shader_level"] = shader_level; @@ -692,9 +687,9 @@ void send_viewer_stats(bool include_preferences) in["compressed_packets"] = (S32) gMessageSystem->mCompressedPacketsIn; in["savings"] = (gMessageSystem->mUncompressedBytesIn - gMessageSystem->mCompressedBytesIn) / 1024.0; - + LLSD &out = body["stats"]["net"]["out"]; - + out["kbytes"] = gMessageSystem->mTotalBytesOut / 1024.0; out["packets"] = (S32) gMessageSystem->mPacketsOut; out["compressed_packets"] = (S32) gMessageSystem->mCompressedPacketsOut; @@ -717,7 +712,7 @@ void send_viewer_stats(bool include_preferences) gInventory.mValidationInfo->asLLSD(validation_info); body["ui"] = LLUIUsage::instance().asLLSD(); - + body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read(); // Misc stats, two strings and two ints -- cgit v1.2.3 From e4dd93ed3c0c503f121865917115eef543df5368 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Sun, 14 Apr 2024 03:00:41 +0200 Subject: secondlife/viewer#912 BugSplat Crash 1412267: nvoglv64+0xadcd00 --- indra/newview/llmodelpreview.cpp | 166 +++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 76 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 8fbcf8e18d..16182ad940 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -132,25 +132,17 @@ std::string getLodSuffix(S32 lod) void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) { - LLModelLoader::scene::iterator base_iter = scene.begin(); - bool found = false; - while (!found && (base_iter != scene.end())) + for (auto scene_iter = scene.begin(); scene_iter != scene.end(); scene_iter++) { - matOut = base_iter->first; - - LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); - while (!found && (base_instance_iter != base_iter->second.end())) + for (auto model_iter = scene_iter->second.begin(); model_iter != scene_iter->second.end(); model_iter++) { - LLModelInstance& base_instance = *base_instance_iter++; - LLModel* base_model = base_instance.mModel; - - if (base_model && (base_model->mLabel == name_to_match)) + if (model_iter->mModel && (model_iter->mModel->mLabel == name_to_match)) { - baseModelOut = base_model; + baseModelOut = model_iter->mModel; + matOut = scene_iter->first; return; } } - base_iter++; } } @@ -210,9 +202,12 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) LLModelPreview::~LLModelPreview() { + LLMutexLock lock(this); + if (mModelLoader) { mModelLoader->shutdown(); + mModelLoader = NULL; } if (mPreviewAvatar) @@ -250,7 +245,7 @@ void LLModelPreview::updateDimentionsAndOffsets() accounted.insert(instance.mModel); // update instance skin info for each lods pelvisZoffset - for (int j = 0; j<LLModel::NUM_LODS; ++j) + for (int j = 0; j < LLModel::NUM_LODS; ++j) { if (instance.mLOD[j]) { @@ -291,7 +286,7 @@ void LLModelPreview::rebuildUploadData() BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); U32 load_state = 0; - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + for (auto iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene LLMatrix4 mat = iter->first; @@ -310,9 +305,9 @@ void LLModelPreview::rebuildUploadData() mat *= scale_mat; - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) + for (auto model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { // for each instance with said transform applied - LLModelInstance instance = *model_iter++; + LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; @@ -872,7 +867,7 @@ void LLModelPreview::clearIncompatible(S32 lod) { mBaseModel = mModel[lod]; mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); replaced_base_model = true; } } @@ -1071,7 +1066,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) mBaseModel = mModel[loaded_lod]; mBaseScene = mScene[loaded_lod]; - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); } else { @@ -1175,7 +1170,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) { if (!mBaseModel.empty()) { - const std::string& model_name = mBaseModel[0]->getName(); + std::string model_name = mBaseModel.front()->getName(); LLLineEditor* description_form = mFMP->getChild<LLLineEditor>("description_form"); if (description_form->getText().empty()) { @@ -1196,6 +1191,8 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) void LLModelPreview::resetPreviewTarget() { + LLMutexLock lock(this); + if (mModelLoader) { mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; @@ -1241,7 +1238,7 @@ void LLModelPreview::generateNormals() (*it)->generateNormals(angle_cutoff); } - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); } bool perform_copy = mModelFacesCopy[which_lod].empty(); @@ -2083,7 +2080,7 @@ void LLModelPreview::updateStatusMessages() S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - for (U32 i = 0; i < LLModel::NUM_LODS - 1; i++) + for (U32 i = 0; i < LLModel::NUM_LODS; i++) { total_tris[i] = 0; total_verts[i] = 0; @@ -2387,12 +2384,16 @@ void LLModelPreview::updateStatusMessages() } } - if (mModelNoErrors && mModelLoader) + if (mModelNoErrors) { - if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + LLMutexLock lock(this); + if (mModelLoader) { - // Some textures are still loading, prevent upload until they are done - mModelNoErrors = false; + if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + { + // Some textures are still loading, prevent upload until they are done + mModelNoErrors = false; + } } } @@ -2721,10 +2722,10 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) { LLModelLoader::model_list* model = NULL; - if (lod < 0 || lod > 4) + if (lod < 0 || lod >= LLModel::NUM_LODS) { model = &mBaseModel; - lod = 5; + lod = LLModel::NUM_LODS; } else { @@ -2961,8 +2962,9 @@ void LLModelPreview::loadedCallback( S32 lod, void* opaque) { - LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); - if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) + LLModelPreview* pPreview = static_cast<LLModelPreview*>(opaque); + LLMutexLock lock(pPreview); + if (pPreview && pPreview->mModelLoader && !LLModelPreview::sIgnoreLoadedCallback) { // Load loader's warnings into floater's log tab const LLSD out = pPreview->mModelLoader->logOut(); @@ -2983,7 +2985,9 @@ void LLModelPreview::loadedCallback( } const LLVOAvatar* avatarp = pPreview->getPreviewAvatar(); - if (avatarp) { // set up ground plane for possible rendering + if (avatarp && avatarp->mRoot && avatarp->mDrawable) + { + // set up ground plane for possible rendering const LLVector3 root_pos = avatarp->mRoot->getPosition(); const LLVector4a* ext = avatarp->mDrawable->getSpatialExtents(); const LLVector4a min = ext[0], max = ext[1]; @@ -3120,12 +3124,12 @@ BOOL LLModelPreview::render() LLMutexLock lock(this); mNeedsUpdate = FALSE; - bool edges = mViewOption["show_edges"]; - bool joint_overrides = mViewOption["show_joint_overrides"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; + bool show_edges = mViewOption["show_edges"]; + bool show_joint_overrides = mViewOption["show_joint_overrides"]; + bool show_joint_positions = mViewOption["show_joint_positions"]; + bool show_skin_weight = mViewOption["show_skin_weight"]; + bool show_textures = mViewOption["show_textures"]; + bool show_physics = mViewOption["show_physics"]; S32 width = getWidth(); S32 height = getHeight(); @@ -3134,7 +3138,7 @@ BOOL LLModelPreview::render() LLGLDisable no_blend(GL_BLEND); LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_FALSE); // SL-12781 disable z-buffer to render background color - + { gUIProgram.bind(); @@ -3202,15 +3206,15 @@ BOOL LLModelPreview::render() fmp->childSetValue("upload_skin", true); mFirstSkinUpdate = false; upload_skin = true; - skin_weight = true; + show_skin_weight = true; mViewOption["show_skin_weight"] = true; } fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_overrides", skin_weight); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + fmp->setViewOptionEnabled("show_joint_overrides", show_skin_weight); + fmp->setViewOptionEnabled("show_joint_positions", show_skin_weight); mFMP->childEnable("upload_skin"); - mFMP->childSetValue("show_skin_weight", skin_weight); + mFMP->childSetValue("show_skin_weight", show_skin_weight); } else if ((flags & LEGACY_RIG_FLAG_TOO_MANY_JOINTS) > 0) @@ -3233,11 +3237,12 @@ BOOL LLModelPreview::render() fmp->disableViewOption("show_joint_overrides"); fmp->disableViewOption("show_joint_positions"); - skin_weight = false; + show_skin_weight = false; mFMP->childSetValue("show_skin_weight", false); - fmp->setViewOptionEnabled("show_skin_weight", skin_weight); + fmp->setViewOptionEnabled("show_skin_weight", show_skin_weight); } } + //if (this) return TRUE; if (upload_skin && !has_skin_weights) { //can't upload skin weights if model has no skin weights @@ -3280,7 +3285,7 @@ BOOL LLModelPreview::render() mFMP->childSetEnabled("upload_joints", upload_skin); } - F32 explode = mFMP->childGetValue("physics_explode").asReal(); + F32 physics_explode = mFMP->childGetValue("physics_explode").asReal(); LLGLDepthTest gls_depth(GL_TRUE); // SL-12781 re-enable z-buffer for 3D model preview @@ -3300,7 +3305,7 @@ BOOL LLModelPreview::render() F32 z_near = 0.001f; F32 z_far = mCameraDistance*10.0f + mPreviewScale.magVec() + mCameraOffset.magVec(); - if (skin_weight) + if (show_skin_weight) { target_pos = getPreviewAvatar()->getPositionAgent() + offset; z_near = 0.01f; @@ -3310,7 +3315,7 @@ BOOL LLModelPreview::render() refresh(); } - gObjectPreviewProgram.bind(skin_weight); + gObjectPreviewProgram.bind(show_skin_weight); gGL.loadIdentity(); gPipeline.enableLightsPreview(); @@ -3319,7 +3324,7 @@ BOOL LLModelPreview::render() LLQuaternion(mCameraYaw, LLVector3::z_axis); LLQuaternion av_rot = camera_rot; - F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; + F32 camera_distance = show_skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera LLVector3::z_axis, // up @@ -3335,9 +3340,9 @@ BOOL LLModelPreview::render() gGL.pushMatrix(); gGL.color4fv(PREVIEW_EDGE_COL.mV); - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + if (!mBaseModel.empty() && mVertexBuffer[LLModel::NUM_LODS].empty()) { - genBuffers(-1, skin_weight); + genBuffers(-1, show_skin_weight); //genBuffers(3); } @@ -3352,7 +3357,7 @@ BOOL LLModelPreview::render() if (!vb_vec.empty()) { const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != show_skin_weight; } else { @@ -3363,15 +3368,15 @@ BOOL LLModelPreview::render() if (regen) { - genBuffers(mPreviewLOD, skin_weight); + genBuffers(mPreviewLOD, show_skin_weight); } - if (physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + if (show_physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty()) { genBuffers(LLModel::LOD_PHYSICS, false); } - if (!skin_weight) + if (!show_skin_weight) { for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { @@ -3393,11 +3398,7 @@ BOOL LLModelPreview::render() U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); for (U32 i = 0; i < num_models; ++i) { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(); - - if (textures) + if (show_textures) { int materialCnt = instance.mModel->mMaterialList.size(); if (i < materialCnt) @@ -3421,10 +3422,16 @@ BOOL LLModelPreview::render() gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV); } + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + buffer->setBuffer(); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); - if (edges) + if (show_edges) { glLineWidth(PREVIEW_EDGE_WIDTH); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3437,7 +3444,7 @@ BOOL LLModelPreview::render() gGL.popMatrix(); } - if (physics) + if (show_physics) { glClear(GL_DEPTH_BUFFER_BIT); @@ -3503,12 +3510,12 @@ BOOL LLModelPreview::render() for (U32 i = 0; i < physics.mMesh.size(); ++i) { - if (explode > 0.f) + if (physics_explode > 0.f) { gGL.pushMatrix(); LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters; - offset *= explode; + offset *= physics_explode; gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); } @@ -3523,7 +3530,7 @@ BOOL LLModelPreview::render() gGL.diffuseColor4ubv(hull_colors[i].mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions); - if (explode > 0.f) + if (physics_explode > 0.f) { gGL.popMatrix(); } @@ -3538,14 +3545,17 @@ BOOL LLModelPreview::render() if (render_mesh) { U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); - if (pass > 0){ + if (pass > 0) + { for (U32 i = 0; i < num_models; ++i) { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(PREVIEW_PSYH_FILL_COL.mV); + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; buffer->setBuffer(); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); @@ -3605,10 +3615,11 @@ BOOL LLModelPreview::render() U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); for (U32 v = 0; v < num_models; ++v) { + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; - buffer->setBuffer(); - LLStrider<LLVector3> pos_strider; buffer->getVertexStrider(pos_strider, 0); LLVector4a* pos = (LLVector4a*)pos_strider.get(); @@ -3672,7 +3683,7 @@ BOOL LLModelPreview::render() U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); U32 bind_count = skin->mAlternateBindMatrix.size(); - if (joint_overrides + if (show_joint_overrides && bind_count > 0 && joint_count == bind_count) { @@ -3715,16 +3726,15 @@ BOOL LLModelPreview::render() } } - for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i) + std::size_t size = mVertexBuffer[mPreviewLOD][model].size(); + for (U32 i = 0; i < size; ++i) { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - model->mSkinInfo.updateHash(); LLRenderPass::uploadMatrixPalette(mPreviewAvatar, &model->mSkinInfo); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (textures) + if (show_textures) { int materialCnt = instance.mModel->mMaterialList.size(); if (i < materialCnt) @@ -3748,10 +3758,14 @@ BOOL LLModelPreview::render() gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV); } + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; buffer->setBuffer(); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - if (edges) + if (show_edges) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); @@ -3766,7 +3780,7 @@ BOOL LLModelPreview::render() } } - if (joint_positions) + if (show_joint_positions) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; if (shader) -- cgit v1.2.3 From 44e3b1859a925c3d5c9a9caa841669fad9d322b4 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 16 Apr 2024 19:56:46 +0300 Subject: Call suspend() periodically to avoid viewer freeze --- indra/newview/llfloaterluadebug.cpp | 6 ++++-- indra/newview/llluamanager.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index f247528231..6fd11dd1c7 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -123,8 +123,10 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) if (count < 0) { // error: show error message - mResultOutput->insertText("*** "); - mResultOutput->pasteTextWithLinebreaks(result.asString()); + LLStyle::Params params; + params.readonly_color = LLUIColorTable::instance().getColor("LtRed"); + mResultOutput->appendText(result.asString(), false, params); + mResultOutput->endOfDoc(); return; } if (count == 1) diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 853ed5a634..dfa27ebc37 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -51,11 +51,22 @@ std::map<std::string, std::string> LLLUAmanager::sScriptNames; std::set<std::string> LLLUAmanager::sTerminationList; +const S32 INTERRUPTS_MAX_LIMIT = 20000; +const S32 INTERRUPTS_SUSPEND_LIMIT = 100; + +void set_interrupts_counter(lua_State *L, S32 counter) +{ + lua_pushstring(L, "_INTERRUPTS"); + lua_pushinteger(L, counter); + lua_rawset(L, LUA_REGISTRYINDEX); +} + lua_function(sleep, "sleep(seconds): pause the running coroutine") { F32 seconds = lua_tonumber(L, -1); lua_pop(L, 1); llcoro::suspendUntilTimeout(seconds); + set_interrupts_counter(L, 0); return 0; }; @@ -98,6 +109,8 @@ std::string lua_print_msg(lua_State* L, const std::string_view& level) std::string msg{ out.str() }; // put message out there for any interested party (*koff* LLFloaterLUADebug *koff*) LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); + + llcoro::suspend(); return msg; } @@ -155,6 +168,7 @@ lua_function(get_event_next, const auto& [pump, data]{ listener->getNext() }; lua_pushstdstring(L, pump); lua_pushllsd(L, data); + set_interrupts_counter(L, 0); return 2; } @@ -175,6 +189,25 @@ std::pair<int, LLSD> LLLUAmanager::waitScriptFile(const std::string& filename) return startScriptFile(filename).get(); } +void check_interrupts_counter(lua_State* L) +{ + lua_pushstring(L, "_INTERRUPTS"); + lua_rawget(L, LUA_REGISTRYINDEX); + S32 counter = lua_tointeger(L, -1); + lua_pop(L, 1); + + counter++; + if (counter > INTERRUPTS_MAX_LIMIT) + { + lluau::error(L, "Possible infinite loop, terminated."); + } + else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0) + { + llcoro::suspend(); + } + set_interrupts_counter(L, counter); +} + void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb) { // A script_result_fn will be called when LuaState::expr() completes. @@ -189,6 +222,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // A script_finished_fn is used to initialize the LuaState. // It will be called when the LuaState is destroyed. LuaState L(finished_cb); + set_interrupts_counter(L, 0); lua_callbacks(L)->interrupt = [](lua_State *L, int gc) { @@ -202,6 +236,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r sTerminationList.erase(it); lluau::error(L, "Script was terminated"); } + check_interrupts_counter(L); }; std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); -- cgit v1.2.3 From c78be38a6a4211f06876bc80b3f19f89a5f936e0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 17 Apr 2024 16:39:37 -0400 Subject: Reintroduce LLCoros::killreq() to request killing a named coroutine. Make LLCoros constructor echo "LLApp" status-change events on new "LLCoros" event pump. Rename LLCoros::kill() to killreq() because this operation only registers a request for the named coroutine to terminate next time it calls checkStop(). Add a new CoroData member to record the name of the coroutine requesting termination. killreq() sets that and also posts "killreq" to "LLCoros". Add an optional final-cleanup callback to LLCoros::checkStop(). Make checkStop() check for a pending killreq() request as well as viewer termination. Introduce new LLCoros::Killed exception for that case. Introduce LLCoros::getStopListener(), with two overloads, to encapsulate some of the messy logic to listen (perhaps temporarily) for viewer shutdown. Both overloads are for use by code at the source end of a queue or promise or other resource for which coroutines might still be waiting at viewer shutdown time. One overload is specifically for when the caller knows the name of the one and only coroutine that will wait on the resource (e.g. because the caller IS that coroutine). That overload honors killreq(). Use getStopListener() to simplify the four existing places where we set up such a listener. Add a fifth: also make WorkQueue listen for viewer shutdown (resolving a TODO comment). Remove LLLUAmanager::terminateScript(), getTerminationList() and the static sTerminationList. In the Lua interrupt callback, instead of checking sTerminationList, call LLCoros::checkStop(). Change LLFloaterLUAScripts terminate-script logic to call LLCoros::killreq() instead of posting on "LLLua" and calling LLLUAmanager::terminateScript(). Drop LLApp::setStatus() posting to "LLLua" LLEventPump: the above makes that moot. --- indra/newview/llfloaterluascripts.cpp | 3 +-- indra/newview/llluamanager.cpp | 13 +++---------- indra/newview/llluamanager.h | 3 --- 3 files changed, 4 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 30353a7210..39d5816b0d 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -54,8 +54,7 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) if (mScriptList->hasSelectedItem()) { std::string coro_name = mScriptList->getSelectedValue(); - LLEventPumps::instance().obtain("LLLua").post(llsd::map("status", "close", "coro", coro_name)); - LLLUAmanager::terminateScript(coro_name); + LLCoros::instance().killreq(coro_name); } }); } diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index dfa27ebc37..e2950648a6 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -49,7 +49,6 @@ #include <vector> std::map<std::string, std::string> LLLUAmanager::sScriptNames; -std::set<std::string> LLLUAmanager::sTerminationList; const S32 INTERRUPTS_MAX_LIMIT = 20000; const S32 INTERRUPTS_SUSPEND_LIMIT = 100; @@ -196,7 +195,7 @@ void check_interrupts_counter(lua_State* L) S32 counter = lua_tointeger(L, -1); lua_pop(L, 1); - counter++; + set_interrupts_counter(L, ++counter); if (counter > INTERRUPTS_MAX_LIMIT) { lluau::error(L, "Possible infinite loop, terminated."); @@ -205,7 +204,6 @@ void check_interrupts_counter(lua_State* L) { llcoro::suspend(); } - set_interrupts_counter(L, counter); } void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb) @@ -229,13 +227,8 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // skip if we're interrupting only for garbage collection if (gc >= 0) return; - - auto it = sTerminationList.find(LLCoros::getName()); - if (it != sTerminationList.end()) - { - sTerminationList.erase(it); - lluau::error(L, "Script was terminated"); - } + + LLCoros::checkStop(); check_interrupts_counter(L); }; std::string text{std::istreambuf_iterator<char>(in_file), {}}; diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index d671719bc4..af9dcf70c2 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -85,12 +85,9 @@ public: static void runScriptOnLogin(); static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } - static std::set<std::string> getTerminationList() { return sTerminationList; } - static void terminateScript(std::string& coro_name) { sTerminationList.insert(coro_name); } private: static std::map<std::string, std::string> sScriptNames; - static std::set<std::string> sTerminationList; }; class LLRequireResolver -- cgit v1.2.3 From 982d57fa00ea93ebbf4c8fdf8407310cb171e2e7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 18 Apr 2024 21:52:58 +0300 Subject: viewer-private#217 Fix cef log name --- indra/newview/llviewermedia.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 3791d1e754..18cfa37fe1 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1723,7 +1723,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ std::string user_data_path_cache = gDirUtilp->getCacheDir(false); user_data_path_cache += gDirUtilp->getDirDelimiter(); - std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.txt"); + std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log"); std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); if (gDirUtilp->fileExists(user_data_path_cef_log)) { -- cgit v1.2.3 From fa821576c010eca2cacb0fab25dd240de4062b31 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 18 Apr 2024 16:34:32 -0400 Subject: Move {set,check}_interrupts_counter() to lluau namespace. Use in LuaState::expr() so we can catch a runaway in-memory Lua chunk as well as a script read from a file. --- indra/newview/llluamanager.cpp | 43 ++---------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index e2950648a6..97779a12ad 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -50,22 +50,12 @@ std::map<std::string, std::string> LLLUAmanager::sScriptNames; -const S32 INTERRUPTS_MAX_LIMIT = 20000; -const S32 INTERRUPTS_SUSPEND_LIMIT = 100; - -void set_interrupts_counter(lua_State *L, S32 counter) -{ - lua_pushstring(L, "_INTERRUPTS"); - lua_pushinteger(L, counter); - lua_rawset(L, LUA_REGISTRYINDEX); -} - lua_function(sleep, "sleep(seconds): pause the running coroutine") { F32 seconds = lua_tonumber(L, -1); lua_pop(L, 1); llcoro::suspendUntilTimeout(seconds); - set_interrupts_counter(L, 0); + lluau::set_interrupts_counter(L, 0); return 0; }; @@ -167,7 +157,7 @@ lua_function(get_event_next, const auto& [pump, data]{ listener->getNext() }; lua_pushstdstring(L, pump); lua_pushllsd(L, data); - set_interrupts_counter(L, 0); + lluau::set_interrupts_counter(L, 0); return 2; } @@ -188,24 +178,6 @@ std::pair<int, LLSD> LLLUAmanager::waitScriptFile(const std::string& filename) return startScriptFile(filename).get(); } -void check_interrupts_counter(lua_State* L) -{ - lua_pushstring(L, "_INTERRUPTS"); - lua_rawget(L, LUA_REGISTRYINDEX); - S32 counter = lua_tointeger(L, -1); - lua_pop(L, 1); - - set_interrupts_counter(L, ++counter); - if (counter > INTERRUPTS_MAX_LIMIT) - { - lluau::error(L, "Possible infinite loop, terminated."); - } - else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0) - { - llcoro::suspend(); - } -} - void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb) { // A script_result_fn will be called when LuaState::expr() completes. @@ -220,17 +192,6 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r // A script_finished_fn is used to initialize the LuaState. // It will be called when the LuaState is destroyed. LuaState L(finished_cb); - set_interrupts_counter(L, 0); - - lua_callbacks(L)->interrupt = [](lua_State *L, int gc) - { - // skip if we're interrupting only for garbage collection - if (gc >= 0) - return; - - LLCoros::checkStop(); - check_interrupts_counter(L); - }; std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); if (result_cb) -- cgit v1.2.3 From 426dc4da45f91afbb1107aecf075e501e774e8ee Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 18 Apr 2024 16:53:12 -0400 Subject: Add llluamanager_test.cpp test that terminates runaway Lua script. Also tweak existing Lua interleaved-responses test to accommodate new Lua periodic suspend behavior. --- indra/newview/tests/llluamanager_test.cpp | 35 +++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index b907ac6619..cf1bf25b5c 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -400,9 +400,16 @@ namespace tut auto future = LLLUAmanager::startScriptLine(L, lua); auto replyname{ L.obtainListener()->getReplyName() }; auto& replypump{ LLEventPumps::instance().obtain(replyname) }; - // By the time leap.process() calls get_event_next() and wakes us up, - // we expect that both requester() coroutines have posted and are - // waiting for a reply. + // LuaState::expr() periodically interrupts a running chunk to ensure + // the rest of our coroutines get cycles. Nonetheless, for this test + // we have to wait until both requester() coroutines have posted and + // are waiting for a reply. + for (unsigned count=0; count < 100; ++count) + { + if (requests.size() == 2) + break; + llcoro::suspend(); + } ensure_equals("didn't get both requests", requests.size(), 2); // moreover, we expect they arrived in the order they were created ensure_equals("a wasn't first", requests[0]["name"].asString(), "a"); @@ -413,7 +420,7 @@ namespace tut replypump.post(llsd::map("name", "not special")); // now respond to requester(a) replypump.post(requests[0]); - // tell leap.process() we're done + // tell leap we're done replypump.post(LLSD()); auto [count, result] = future.get(); ensure_equals("leap.lua: " + result.asString(), count, 0); @@ -438,4 +445,24 @@ namespace tut ensure_equals("unexpected killed Lua script error", result.asString(), "viewer is stopping"); } + + template<> template<> + void object::test<8>() + { + set_test_name("stop looping Lua script"); + const std::string desc("looping Lua script should terminate"); + const std::string lua( + "-- " + desc + "\n" + "\n" + "while true do\n" + " x = 1\n" + "end\n" + ); + LuaState L; + auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + // We expect the above erroneous script has been forcibly terminated + // because it ran too long without doing any actual work. + ensure_equals(desc + " count: " + result.asString(), count, -1); + ensure_contains(desc + " result", result.asString(), "terminated"); + } } // namespace tut -- cgit v1.2.3 From ea4ddb5f40ee8dd253be0ac4229de90f1eef61a3 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Mon, 15 Apr 2024 18:39:23 +0300 Subject: Revert "SL-20140 Setting shape hand size to 36 won't save" This reverts commit 810a3d24c2e3671f926091c062b101bdec6a1517. (secondlife/jira-archive-internal#70482) --- indra/newview/character/avatar_lad.xml | 17 ++++---- indra/newview/llscrollingpanelparam.cpp | 63 ++++++++++++++++++++--------- indra/newview/llscrollingpanelparam.h | 3 ++ indra/newview/llscrollingpanelparambase.cpp | 29 +++++++------ indra/newview/llscrollingpanelparambase.h | 7 +--- 5 files changed, 72 insertions(+), 47 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index aef402d4db..2cdd86267e 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -2021,7 +2021,7 @@ value_min="-1" value_max="1"> <param_skeleton> - + <bone name="mEyeLeft" scale="0 0 0" @@ -2031,8 +2031,9 @@ name="mEyeRight" scale="0 0 0" offset="-.005 0 0" /> - - <bone + + +<bone name="mFaceEyeAltLeft" scale="0 0 0" offset="-.005 0 0" /> @@ -2041,7 +2042,7 @@ name="mFaceEyeAltRight" scale="0 0 0" offset="-.005 0 0" /> - + <bone name="mFaceEyeLidLowerRight" scale="0 0.3 0.7" @@ -2052,7 +2053,7 @@ scale="0 0.3 0.7" offset="0 0 0" /> - <bone + <bone name="mFaceEyeLidUpperRight" scale="0 0.3 0.7" offset=" 0 0 0" /> @@ -2061,17 +2062,17 @@ name="mFaceEyeLidUpperLeft" scale="0 0.3 0.7" offset=" 0 0 0" /> - + <bone name="mFaceEyecornerInnerLeft" scale="0 0 0" offset="-0.005 -0.008 0.0" /> - + <bone name="mFaceEyecornerInnerRight" scale="0 0 0" offset="-0.005 0.008 0.0" /> - + </param_skeleton> </param> diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index efd84eaa6d..bfa453a0ae 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -259,15 +259,19 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) // Make sure we're not taking the slider out of bounds // (this is where some simple UI limits are stored) - F32 new_percent = weightToSlider(new_weight); - if (mSlider->getMinValue() < new_percent - && new_percent < mSlider->getMaxValue()) + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild<LLSliderCtrl>("param slider"); + if (slider) { - mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); - mWearable->writeToAvatar(gAgentAvatarp); - gAgentAvatarp->updateVisualParams(); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); + mWearable->writeToAvatar(gAgentAvatarp); + gAgentAvatarp->updateVisualParams(); - mSlider->setValue( weightToSlider( new_weight ) ); + slider->setValue( weightToPercent( new_weight ) ); + } } } } @@ -288,13 +292,17 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata ) F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); // step a fraction in the negative directiona F32 new_weight = current_weight - (range / 10.f); - F32 new_percent = self->weightToSlider(new_weight); - if (self->mSlider->getMinValue() < new_percent - && new_percent < self->mSlider->getMaxValue()) + F32 new_percent = self->weightToPercent(new_weight); + LLSliderCtrl* slider = self->getChild<LLSliderCtrl>("param slider"); + if (slider) { - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); - self->mWearable->writeToAvatar(gAgentAvatarp); - self->mSlider->setValue( self->weightToSlider( new_weight ) ); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->writeToAvatar(gAgentAvatarp); + slider->setValue( self->weightToPercent( new_weight ) ); + } } } @@ -318,16 +326,33 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata ) F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); // step a fraction in the negative direction F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = self->weightToSlider(new_weight); - if (self->mSlider->getMinValue() < new_percent - && new_percent < self->mSlider->getMaxValue()) + F32 new_percent = self->weightToPercent(new_weight); + LLSliderCtrl* slider = self->getChild<LLSliderCtrl>("param slider"); + if (slider) { - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); - self->mWearable->writeToAvatar(gAgentAvatarp); - self->mSlider->setValue( self->weightToSlider( new_weight ) ); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->writeToAvatar(gAgentAvatarp); + slider->setValue( self->weightToPercent( new_weight ) ); + } } } } LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); } + + +F32 LLScrollingPanelParam::weightToPercent( F32 weight ) +{ + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; +} + +F32 LLScrollingPanelParam::percentToWeight( F32 percent ) +{ + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); +} diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index dc344486fc..c7a47d5c7a 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -61,6 +61,9 @@ public: void onHintMouseDown( LLVisualParamHint* hint ); void onHintHeldDown( LLVisualParamHint* hint ); + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); + public: // Constants for LLPanelVisualParam const static F32 PARAM_STEP_TIME_THRESHOLD; diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 2a6c25235d..fe7a362723 100644 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -43,7 +43,6 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& pan LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints) : LLScrollingPanel( panel_params ), mParam(param), - mSlider(nullptr), mAllowModify(allow_modify), mWearable(wearable) { @@ -51,15 +50,13 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& pan buildFromFile( "panel_scrolling_param.xml"); else buildFromFile( "panel_scrolling_param_base.xml"); - - mSlider = getChild<LLSliderCtrl>("param slider"); - mSlider->setMaxValue(100.f * (mParam->getMaxWeight() - mParam->getMinWeight())); - mSlider->setValue(weightToSlider(param->getWeight())); + + getChild<LLUICtrl>("param slider")->setValue(weightToPercent(param->getWeight())); std::string display_name = LLTrans::getString(param->getDisplayName()); - mSlider->setLabelArg("[DESC]", display_name); - mSlider->setEnabled(mAllowModify); - mSlider->setCommitCallback(boost::bind(LLScrollingPanelParamBase::onSliderMoved, mSlider, this)); + getChild<LLUICtrl>("param slider")->setLabelArg("[DESC]", display_name); + getChildView("param slider")->setEnabled(mAllowModify); + childSetCommitCallback("param slider", LLScrollingPanelParamBase::onSliderMoved, this); setVisible(FALSE); setBorderVisible( FALSE ); @@ -80,9 +77,9 @@ void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) } F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); - mSlider->setValue(weightToSlider( current_weight ) ); + getChild<LLUICtrl>("param slider")->setValue(weightToPercent( current_weight ) ); mAllowModify = allow_modify; - mSlider->setEnabled(mAllowModify); + getChildView("param slider")->setEnabled(mAllowModify); } // static @@ -93,7 +90,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) LLViewerVisualParam* param = self->mParam; F32 current_weight = self->mWearable->getVisualParamWeight( param->getID() ); - F32 new_weight = self->sliderToWeight( (F32)slider->getValue().asReal() ); + F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { self->mWearable->setVisualParamWeight( param->getID(), new_weight); @@ -102,12 +99,14 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) } } -F32 LLScrollingPanelParamBase::weightToSlider(F32 weight) +F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) { - return (weight - mParam->getMinWeight()) * 100.f; + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; } -F32 LLScrollingPanelParamBase::sliderToWeight(F32 slider) +F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) { - return slider / 100.f + mParam->getMinWeight(); + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); } diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h index e7f88a21bd..9538826251 100644 --- a/indra/newview/llscrollingpanelparambase.h +++ b/indra/newview/llscrollingpanelparambase.h @@ -36,7 +36,6 @@ class LLViewerVisualParam; class LLWearable; class LLVisualParamHint; class LLViewerVisualParam; -class LLSliderCtrl; class LLJoint; class LLScrollingPanelParamBase : public LLScrollingPanel @@ -50,13 +49,11 @@ public: static void onSliderMoved(LLUICtrl* ctrl, void* userdata); - F32 weightToSlider(F32 weight); - F32 sliderToWeight(F32 slider); + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); public: LLViewerVisualParam* mParam; - LLSliderCtrl* mSlider; - protected: BOOL mAllowModify; LLWearable *mWearable; -- cgit v1.2.3 From 477b45be1be256b7496e1d45b41754c6e40ef58a Mon Sep 17 00:00:00 2001 From: Maki <maki@hotmilk.space> Date: Fri, 19 Apr 2024 02:32:29 -0400 Subject: Add toggle for PipeWire volume catcher, and refactoring --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llviewermedia.cpp | 5 +++++ 2 files changed, 16 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2f7c256b49..705319ee40 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6522,6 +6522,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>MediaPluginPipeWireVolumeCatcher</key> + <map> + <key>Comment</key> + <string>Use PipeWire instead of PulseAudio for controlling web media volume.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>MediaControlFadeTime</key> <map> <key>Comment</key> diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 3791d1e754..601a508f9b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1772,6 +1772,11 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled || clean_browser); +#if LL_LINUX + bool media_plugin_pipewire_volume_catcher = gSavedSettings.getBOOL("MediaPluginPipeWireVolumeCatcher"); + media_source->enablePipeWireVolumeCatcher( media_plugin_pipewire_volume_catcher ); +#endif + // need to set agent string here before instance created media_source->setBrowserUserAgent(LLViewerMedia::getInstance()->getCurrentUserAgent()); -- cgit v1.2.3 From bb1f3f08cf93facbf926e57384674441be7e2884 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 22 Apr 2024 14:56:52 +0300 Subject: Add demo script with idle and notification interactions --- indra/newview/llvoavatar.cpp | 30 +++++++++++++++++++ indra/newview/scripts/lua/LLNotification.lua | 15 ++++++++++ .../newview/scripts/lua/luafloater_speedometer.xml | 35 ++++++++++++++++++++++ .../scripts/lua/test_luafloater_speedometer.lua | 26 ++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 indra/newview/scripts/lua/LLNotification.lua create mode 100644 indra/newview/scripts/lua/luafloater_speedometer.xml create mode 100644 indra/newview/scripts/lua/test_luafloater_speedometer.lua (limited to 'indra/newview') diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 9579a5e4b1..3074990a9b 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -114,6 +114,7 @@ #include "llskinningutil.h" #include "llperfstats.h" +#include "lleventapi.h" #include <boost/lexical_cast.hpp> @@ -11599,4 +11600,33 @@ F32 LLVOAvatar::getAverageGPURenderTime() return ret; } +class LLVOAvatarListener : public LLEventAPI +{ + public: + LLVOAvatarListener() : LLEventAPI("LLVOAvatar", "LLVOAvatar listener to retrieve avatar info") + { + add("getSpeed", + "Return the avatar movement speed in the XY plane", + &LLVOAvatarListener::getSpeed, + LLSD().with("reply", LLSD())); + add("isInAir", + "Return the info whether avatar is in the air, and if so the time in the air", + &LLVOAvatarListener::isInAir, + LLSD().with("reply", LLSD())); + } + + private: + void getSpeed(const LLSD &request) const + { + LLVector3 avatar_velocity = gAgentAvatarp->getCharacterVelocity() * gAgentAvatarp->getTimeDilation(); + avatar_velocity.mV[VZ] = 0.f; + Response response(llsd::map("value", avatar_velocity.magVec()), request); + } + void isInAir(const LLSD &request) const + { + Response response(llsd::map("value", gAgentAvatarp->mInAir, + "duration", gAgentAvatarp->mInAir ? gAgentAvatarp->mTimeInAir.getElapsedTimeF32() : 0), request); + } +}; +static LLVOAvatarListener VOAvatarListener; diff --git a/indra/newview/scripts/lua/LLNotification.lua b/indra/newview/scripts/lua/LLNotification.lua new file mode 100644 index 0000000000..f47730d1cc --- /dev/null +++ b/indra/newview/scripts/lua/LLNotification.lua @@ -0,0 +1,15 @@ +-- Engage the LLNotificationsListener LLEventAPI + +leap = require 'leap' + +local LLNotification = {} + +function LLNotification.add(name, substitutions) + leap.send('LLNotifications', {op='requestAdd', name=name, substitutions=substitutions}) +end + +function LLNotification.requestAdd(name, substitutions) + return leap.request('LLNotifications', {op='requestAdd', name=name, substitutions=substitutions})['response'] +end + +return LLNotification diff --git a/indra/newview/scripts/lua/luafloater_speedometer.xml b/indra/newview/scripts/lua/luafloater_speedometer.xml new file mode 100644 index 0000000000..54b99c7d48 --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_speedometer.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="60" + layout="topleft" + name="lua_speedometer" + title="Speedometer" + can_minimize="false" + width="170"> + <text + type="string" + follows="left|top" + font="SansSerifBold" + font.size="Huge" + text_color="White" + layout="topleft" + top="25" + left_delta="30" + width="70" + height="30" + name="speed_lbl"/> + <text + type="string" + follows="left|top" + width="55" + height="30" + font="SansSerifBold" + font.size="Huge" + text_color="White" + layout="topleft" + left_pad="2" + name="mps_lbl"> + m/s + </text> +</floater> diff --git a/indra/newview/scripts/lua/test_luafloater_speedometer.lua b/indra/newview/scripts/lua/test_luafloater_speedometer.lua new file mode 100644 index 0000000000..610401ae44 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_speedometer.lua @@ -0,0 +1,26 @@ +local Floater = require 'Floater' +local startup = require 'startup' +inspect = require 'inspect' +leap = require 'leap' +LLNotification = require 'LLNotification' +local max_speed = 0 +local flt = Floater:new("luafloater_speedometer.xml") +startup.wait('STATE_STARTED') + +function flt:floater_close(event_data) + msg = "Registered max speed: " .. string.format("%.2f", max_speed) .. " m/s"; + LLNotification.add('SystemMessageTip', {MESSAGE = msg}) +end + +function flt:idle(event_data) + local speed = leap.request('LLVOAvatar', {op='getSpeed'})['value'] + flt:post({action="set_value", ctrl_name="speed_lbl", value = string.format("%.2f", speed)}) + max_speed=math.max(max_speed, speed) +end + +msg = 'Are you sure you want to run this "speedometer" script?' +response = LLNotification.requestAdd('GenericAlertYesCancel', {MESSAGE = msg}) + +if response.OK_okcancelbuttons then + flt:show() +end -- cgit v1.2.3 From cc7b416fb8e776c406db6a4f95e505398f5f7fd5 Mon Sep 17 00:00:00 2001 From: nerodevo <100370411+nerodevo@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:21:38 -0500 Subject: Remove invalid text color parameter from panel_login_first.xml Follow-up to previous commit 4a07fd3. This will resolve the warning showing up when loading the viewer for the first time. --- indra/newview/skins/default/xui/en/panel_login_first.xml | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview') 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 d002e24782..09eb24c019 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -179,7 +179,6 @@ control_name="RememberPassword" follows="left|top" font="SansSerifLarge" - text_color="EmphasisColor" height="24" left="262" bottom_delta="0" -- cgit v1.2.3 From 9bf5fcd225ada9dcd63fc5710f58013e7839df09 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 26 Apr 2024 09:22:39 -0400 Subject: Remove unused newview/llcallbacklist.cpp: real one is in llcommon. newview/llcallbacklist.cpp has no corresponding .h file, it isn't referenced by newview/CMakeLists.txt, and its removal doesn't affect the build. See llcommon/llcallbacklist.{h,cpp} for the real functionality. (cherry picked from commit 8e53d6ff4c6594f014f456b0ba9ebf86ac91f6bc) --- indra/newview/llcallbacklist.cpp | 305 --------------------------------------- 1 file changed, 305 deletions(-) delete mode 100644 indra/newview/llcallbacklist.cpp (limited to 'indra/newview') diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp deleted file mode 100644 index 59ecbdd0ea..0000000000 --- a/indra/newview/llcallbacklist.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/** - * @file llcallbacklist.cpp - * @brief A simple list of callback functions to call. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llcallbacklist.h" -#include "lleventtimer.h" - -// Library includes -#include "llerror.h" - - -// -// Globals -// -LLCallbackList gIdleCallbacks; - -// -// Member functions -// - -LLCallbackList::LLCallbackList() -{ - // nothing -} - -LLCallbackList::~LLCallbackList() -{ -} - - -void LLCallbackList::addFunction( callback_t func, void *data) -{ - if (!func) - { - LL_ERRS() << "LLCallbackList::addFunction - function is NULL" << LL_ENDL; - return; - } - - // only add one callback per func/data pair - callback_pair_t t(func, data); - callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); - if (iter == mCallbackList.end()) - { - mCallbackList.push_back(t); - } -} - - -BOOL LLCallbackList::containsFunction( callback_t func, void *data) -{ - callback_pair_t t(func, data); - callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); - if (iter != mCallbackList.end()) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -BOOL LLCallbackList::deleteFunction( callback_t func, void *data) -{ - callback_pair_t t(func, data); - callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); - if (iter != mCallbackList.end()) - { - mCallbackList.erase(iter); - return TRUE; - } - else - { - return FALSE; - } -} - - -void LLCallbackList::deleteAllFunctions() -{ - mCallbackList.clear(); -} - - -void LLCallbackList::callFunctions() -{ - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); - } -} - -// Shim class to allow arbitrary boost::bind -// expressions to be run as one-time idle callbacks. -class OnIdleCallbackOneTime -{ -public: - OnIdleCallbackOneTime(nullary_func_t callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } -private: - nullary_func_t mCallable; -}; - -void doOnIdleOneTime(nullary_func_t callable) -{ - OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); -} - -// Shim class to allow generic boost functions to be run as -// recurring idle callbacks. Callable should return true when done, -// false to continue getting called. -class OnIdleCallbackRepeating -{ -public: - OnIdleCallbackRepeating(bool_func_t callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } -private: - bool_func_t mCallable; -}; - -void doOnIdleRepeating(bool_func_t callable) -{ - OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); -} - -class NullaryFuncEventTimer: public LLEventTimer -{ -public: - NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } - -private: - BOOL tick() - { - mCallable(); - return TRUE; - } - - nullary_func_t mCallable; -}; - -// Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds) -{ - new NullaryFuncEventTimer(callable, seconds); -} - -class BoolFuncEventTimer: public LLEventTimer -{ -public: - BoolFuncEventTimer(bool_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } -private: - BOOL tick() - { - return mCallable(); - } - - bool_func_t mCallable; -}; - -// Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds) -{ - new BoolFuncEventTimer(callable, seconds); -} - -#ifdef _DEBUG - -void test1(void *data) -{ - S32 *s32_data = (S32 *)data; - LL_INFOS() << "testfunc1 " << *s32_data << LL_ENDL; -} - - -void test2(void *data) -{ - S32 *s32_data = (S32 *)data; - LL_INFOS() << "testfunc2 " << *s32_data << LL_ENDL; -} - - -void -LLCallbackList::test() -{ - S32 a = 1; - S32 b = 2; - LLCallbackList *list = new LLCallbackList; - - LL_INFOS() << "Testing LLCallbackList" << LL_ENDL; - - if (!list->deleteFunction(NULL)) - { - LL_INFOS() << "passed 1" << LL_ENDL; - } - else - { - LL_INFOS() << "error, removed function from empty list" << LL_ENDL; - } - - // LL_INFOS() << "This should crash" << LL_ENDL; - // list->addFunction(NULL); - - list->addFunction(&test1, &a); - list->addFunction(&test1, &a); - - LL_INFOS() << "Expect: test1 1, test1 1" << LL_ENDL; - list->callFunctions(); - - list->addFunction(&test1, &b); - list->addFunction(&test2, &b); - - LL_INFOS() << "Expect: test1 1, test1 1, test1 2, test2 2" << LL_ENDL; - list->callFunctions(); - - if (list->deleteFunction(&test1, &b)) - { - LL_INFOS() << "passed 3" << LL_ENDL; - } - else - { - LL_INFOS() << "error removing function" << LL_ENDL; - } - - LL_INFOS() << "Expect: test1 1, test1 1, test2 2" << LL_ENDL; - list->callFunctions(); - - list->deleteAllFunctions(); - - LL_INFOS() << "Expect nothing" << LL_ENDL; - list->callFunctions(); - - LL_INFOS() << "nothing :-)" << LL_ENDL; - - delete list; - - LL_INFOS() << "test complete" << LL_ENDL; -} - -#endif // _DEBUG -- cgit v1.2.3 From f69ac40e24e78fe265c81ff3785c185229764151 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 26 Apr 2024 23:54:40 +0300 Subject: viewer-private#217 Cef log was deleted too often delete once per session, not once per instance --- indra/newview/llappviewer.cpp | 8 ++++++++ indra/newview/llviewermedia.cpp | 9 +-------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 547a1c49cd..67ef234129 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2352,6 +2352,14 @@ void LLAppViewer::initLoggingAndGetLastDuration() { LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL; } + + std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log"); + if (gDirUtilp->fileExists(user_data_path_cef_log)) + { + std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); + LLFile::remove(user_data_path_cef_old, ENOENT); + LLFile::rename(user_data_path_cef_log, user_data_path_cef_old); + } } } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 18cfa37fe1..d35c63200a 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1723,14 +1723,6 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ std::string user_data_path_cache = gDirUtilp->getCacheDir(false); user_data_path_cache += gDirUtilp->getDirDelimiter(); - std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log"); - std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); - if (gDirUtilp->fileExists(user_data_path_cef_log)) - { - LLFile::remove(user_data_path_cef_old, ENOENT); - LLFile::rename(user_data_path_cef_log, user_data_path_cef_old); - } - // See if the plugin executable exists llstat s; if(LLFile::stat(launcher_name, &s)) @@ -1745,6 +1737,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ { media_source = new LLPluginClassMedia(owner); media_source->setSize(default_width, default_height); + std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log"); media_source->setUserDataPath(user_data_path_cache, gDirUtilp->getUserName(), user_data_path_cef_log); media_source->setLanguageCode(LLUI::getLanguage()); media_source->setZoomFactor(zoom_factor); -- cgit v1.2.3 From 0868427913e0a1411bc857b227dad82414e42457 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 29 Apr 2024 16:24:43 +0300 Subject: Allow changing debug settings via Lua script --- indra/newview/llappviewerlistener.cpp | 14 ++++++++++++++ indra/newview/llappviewerlistener.h | 2 ++ indra/newview/llfloatersettingsdebug.cpp | 20 ++++++++++++++++---- indra/newview/llfloatersettingsdebug.h | 4 ++++ .../skins/default/xui/en/floater_settings_debug.xml | 18 ++++++++++++++++-- 5 files changed, 52 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index 2380a8ebf0..bd0c6955b1 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -35,6 +35,7 @@ // external library headers // other Linden headers #include "llappviewer.h" +#include "llviewercontrol.h" LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): LLEventAPI("LLAppViewer", @@ -48,6 +49,10 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): add("forceQuit", "Quit abruptly", &LLAppViewerListener::forceQuit); + + add("setDebugSetting", + "Apply specified [\"value\"] to the debug [\"setting\"] (this change won't persist across sessions)", + &LLAppViewerListener::setDebugSetting, llsd::map("setting", LLSD(), "value", LLSD())); } void LLAppViewerListener::requestQuit(const LLSD& event) @@ -61,3 +66,12 @@ void LLAppViewerListener::forceQuit(const LLSD& event) LL_INFOS() << "Listener requested force quit" << LL_ENDL; mAppViewerGetter()->forceQuit(); } + +void LLAppViewerListener::setDebugSetting(const LLSD &event) +{ + auto setting_name = event["setting"].asString(); + auto value = event["value"]; + LL_WARNS("LLAppViewerListener") << "Changing debug setting \"" << setting_name << "\" to " << value << LL_ENDL; + //don't save this change between sesssions + gSavedSettings.setUntypedValue(setting_name, value, false); +} diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h index 78c8b1909e..8b38636bd1 100644 --- a/indra/newview/llappviewerlistener.h +++ b/indra/newview/llappviewerlistener.h @@ -47,6 +47,8 @@ private: void requestQuit(const LLSD& event); void forceQuit(const LLSD& event); + void setDebugSetting(const LLSD &event); + LLAppViewerGetter mAppViewerGetter; }; diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 3c7f341613..e1df6a4b1f 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -34,6 +34,7 @@ #include "llcolorswatch.h" #include "llviewercontrol.h" #include "lltexteditor.h" +#include "llclipboard.h" LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) @@ -52,6 +53,8 @@ BOOL LLFloaterSettingsDebug::postBuild() enableResizeCtrls(true, false, true); mComment = getChild<LLTextEditor>("comment_text"); + mSettingName = getChild<LLTextBox>("setting_name_txt"); + mCopyBtn = getChild<LLButton>("copy_btn"); getChild<LLFilterEditor>("filter_input")->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::setSearchFilter, this, _2)); @@ -59,6 +62,8 @@ BOOL LLFloaterSettingsDebug::postBuild() mSettingList->setCommitOnSelectionChange(TRUE); mSettingList->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this)); + mCopyBtn->setCommitCallback([this](LLUICtrl *ctrl, const LLSD ¶m) { onClickCopy(); }); + updateList(); gSavedSettings.getControl("DebugSettingsHideDefault")->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateList, this, false)); @@ -203,9 +208,10 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); getChildView("default_btn")->setVisible(true); - getChildView("setting_name_txt")->setVisible(true); - getChild<LLTextBox>("setting_name_txt")->setText(controlp->getName()); - getChild<LLTextBox>("setting_name_txt")->setToolTip(controlp->getName()); + mSettingName->setVisible(true); + mSettingName->setText(controlp->getName()); + mSettingName->setToolTip(controlp->getName()); + mCopyBtn->setVisible(true); mComment->setVisible(true); std::string old_text = mComment->getText(); @@ -632,7 +638,13 @@ void LLFloaterSettingsDebug::hideUIControls() getChildView("val_text")->setVisible(false); getChildView("default_btn")->setVisible(false); getChildView("boolean_combo")->setVisible(false); - getChildView("setting_name_txt")->setVisible(false); + mSettingName->setVisible(false); + mCopyBtn->setVisible(false); mComment->setVisible(false); } +void LLFloaterSettingsDebug::onClickCopy() +{ + std::string setting_name = mSettingName->getText(); + LLClipboard::instance().copyToClipboard(utf8str_to_wstring(setting_name), 0, setting_name.size()); +} diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index 888eaadcbd..6ff3e344b4 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -31,6 +31,7 @@ #include "llfloater.h" class LLScrollListCtrl; +class LLTextBox; class LLFloaterSettingsDebug : public LLFloater @@ -46,6 +47,7 @@ public: void onCommitSettings(); void onClickDefault(); + void onClickCopy(); bool matchesSearchFilter(std::string setting_name); bool isSettingHidden(LLControlVariable* control); @@ -67,6 +69,8 @@ private: protected: class LLTextEditor* mComment; + LLTextBox* mSettingName; + LLButton* mCopyBtn; std::string mSearchFilter; }; diff --git a/indra/newview/skins/default/xui/en/floater_settings_debug.xml b/indra/newview/skins/default/xui/en/floater_settings_debug.xml index a93be6a18d..6fd8f2b255 100644 --- a/indra/newview/skins/default/xui/en/floater_settings_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_settings_debug.xml @@ -43,6 +43,20 @@ label="Setting" name="setting" /> </scroll_list> + <button + follows="right|bottom" + layout="topleft" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="Icon_Copy" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + name="copy_btn" + tool_tip="Copy to clipboard" + top_delta="8" + left_pad="10" + visible="false" + height="20" + width="20" /> <text type="string" length="1" @@ -51,8 +65,7 @@ layout="topleft" name="setting_name_txt" font="SansSerifSmallBold" - top_delta="8" - left_pad="10" + left_pad="4" visible="false" use_ellipses="true" text_color="White" @@ -67,6 +80,7 @@ name="comment_text" follows="left|top" width="240" + left="320" top_delta="20" word_wrap="true" /> <radio_group -- cgit v1.2.3 From 76d36fe7210443b4564d2646a2fe5aa6d7c490fc Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 29 Apr 2024 19:56:41 +0300 Subject: Allow getting the value of debug settings via Lua script --- indra/newview/llappviewerlistener.cpp | 9 +++++++++ indra/newview/llappviewerlistener.h | 1 + indra/newview/scripts/lua/LLDebugSettings.lua | 13 +++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 indra/newview/scripts/lua/LLDebugSettings.lua (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index bd0c6955b1..35732d8949 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -53,6 +53,10 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): add("setDebugSetting", "Apply specified [\"value\"] to the debug [\"setting\"] (this change won't persist across sessions)", &LLAppViewerListener::setDebugSetting, llsd::map("setting", LLSD(), "value", LLSD())); + + add("getDebugSetting", + "Return the value of specified debug [\"setting\"]", + &LLAppViewerListener::getDebugSetting, llsd::map("setting", LLSD(), "reply", LLSD())); } void LLAppViewerListener::requestQuit(const LLSD& event) @@ -75,3 +79,8 @@ void LLAppViewerListener::setDebugSetting(const LLSD &event) //don't save this change between sesssions gSavedSettings.setUntypedValue(setting_name, value, false); } + +void LLAppViewerListener::getDebugSetting(const LLSD &event) +{ + Response response(llsd::map("value", gSavedSettings.getLLSD(event["setting"])), event); +} diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h index 8b38636bd1..897e4105ac 100644 --- a/indra/newview/llappviewerlistener.h +++ b/indra/newview/llappviewerlistener.h @@ -48,6 +48,7 @@ private: void forceQuit(const LLSD& event); void setDebugSetting(const LLSD &event); + void getDebugSetting(const LLSD &event); LLAppViewerGetter mAppViewerGetter; }; diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua new file mode 100644 index 0000000000..71a12a2ca2 --- /dev/null +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -0,0 +1,13 @@ +leap = require 'leap' + +local LLDebugSettings = {} + +function LLDebugSettings.set(name, value) + leap.send('LLAppViewer', {op='setDebugSetting', setting=name, value=value}) +end + +function LLDebugSettings.get(name) + return leap.request('LLAppViewer', {op='getDebugSetting', setting=name})['value'] +end + +return LLDebugSettings -- cgit v1.2.3 From 79dca07d790a47db192099bcb85e740676a643ee Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 1 May 2024 19:58:47 +0300 Subject: Use LLViewerControlListener to access debug settings --- indra/newview/llappviewerlistener.cpp | 9 --------- indra/newview/llappviewerlistener.h | 1 - indra/newview/llviewercontrollistener.cpp | 6 ++++-- indra/newview/scripts/lua/LLDebugSettings.lua | 8 ++++++-- 4 files changed, 10 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index 35732d8949..bd0c6955b1 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -53,10 +53,6 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): add("setDebugSetting", "Apply specified [\"value\"] to the debug [\"setting\"] (this change won't persist across sessions)", &LLAppViewerListener::setDebugSetting, llsd::map("setting", LLSD(), "value", LLSD())); - - add("getDebugSetting", - "Return the value of specified debug [\"setting\"]", - &LLAppViewerListener::getDebugSetting, llsd::map("setting", LLSD(), "reply", LLSD())); } void LLAppViewerListener::requestQuit(const LLSD& event) @@ -79,8 +75,3 @@ void LLAppViewerListener::setDebugSetting(const LLSD &event) //don't save this change between sesssions gSavedSettings.setUntypedValue(setting_name, value, false); } - -void LLAppViewerListener::getDebugSetting(const LLSD &event) -{ - Response response(llsd::map("value", gSavedSettings.getLLSD(event["setting"])), event); -} diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h index 897e4105ac..8b38636bd1 100644 --- a/indra/newview/llappviewerlistener.h +++ b/indra/newview/llappviewerlistener.h @@ -48,7 +48,6 @@ private: void forceQuit(const LLSD& event); void setDebugSetting(const LLSD &event); - void getDebugSetting(const LLSD &event); LLAppViewerGetter mAppViewerGetter; }; diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 8820f9ec56..5c1b020c9d 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -141,7 +141,8 @@ void LLViewerControlListener::set(LLSD const & request) if (request.has("value")) { - info.control->setValue(request["value"]); + LL_WARNS("LLViewerControlListener") << "Changing debug setting " << std::quoted(info.key) << " to " << request["value"] << LL_ENDL; + info.control->setValue(request["value"], false); } else { @@ -158,7 +159,8 @@ void LLViewerControlListener::toggle(LLSD const & request) if (info.control->isType(TYPE_BOOLEAN)) { - info.control->set(! info.control->get().asBoolean()); + LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << LL_ENDL; + info.control->set(! info.control->get().asBoolean(), false); } else { diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index 71a12a2ca2..80ae7e87bb 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -3,11 +3,15 @@ leap = require 'leap' local LLDebugSettings = {} function LLDebugSettings.set(name, value) - leap.send('LLAppViewer', {op='setDebugSetting', setting=name, value=value}) + return leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value}) +end + +function LLDebugSettings.toggle(name) + return leap.request('LLViewerControl', {op='toggle', group='Global', key=name}) end function LLDebugSettings.get(name) - return leap.request('LLAppViewer', {op='getDebugSetting', setting=name})['value'] + return leap.request('LLViewerControl', {op='get', group='Global', key=name})['value'] end return LLDebugSettings -- cgit v1.2.3 From f9a2748b542d05d153fa591a8c452162d9402828 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 2 May 2024 14:03:34 +0300 Subject: Raise Lua error if LLViewerControlListener response contains one --- indra/newview/llappviewerlistener.cpp | 14 -------------- indra/newview/llappviewerlistener.h | 2 -- indra/newview/llviewercontrollistener.cpp | 5 +++-- indra/newview/scripts/lua/LLDebugSettings.lua | 13 ++++++++++--- 4 files changed, 13 insertions(+), 21 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index bd0c6955b1..2380a8ebf0 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -35,7 +35,6 @@ // external library headers // other Linden headers #include "llappviewer.h" -#include "llviewercontrol.h" LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): LLEventAPI("LLAppViewer", @@ -49,10 +48,6 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): add("forceQuit", "Quit abruptly", &LLAppViewerListener::forceQuit); - - add("setDebugSetting", - "Apply specified [\"value\"] to the debug [\"setting\"] (this change won't persist across sessions)", - &LLAppViewerListener::setDebugSetting, llsd::map("setting", LLSD(), "value", LLSD())); } void LLAppViewerListener::requestQuit(const LLSD& event) @@ -66,12 +61,3 @@ void LLAppViewerListener::forceQuit(const LLSD& event) LL_INFOS() << "Listener requested force quit" << LL_ENDL; mAppViewerGetter()->forceQuit(); } - -void LLAppViewerListener::setDebugSetting(const LLSD &event) -{ - auto setting_name = event["setting"].asString(); - auto value = event["value"]; - LL_WARNS("LLAppViewerListener") << "Changing debug setting \"" << setting_name << "\" to " << value << LL_ENDL; - //don't save this change between sesssions - gSavedSettings.setUntypedValue(setting_name, value, false); -} diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h index 8b38636bd1..78c8b1909e 100644 --- a/indra/newview/llappviewerlistener.h +++ b/indra/newview/llappviewerlistener.h @@ -47,8 +47,6 @@ private: void requestQuit(const LLSD& event); void forceQuit(const LLSD& event); - void setDebugSetting(const LLSD &event); - LLAppViewerGetter mAppViewerGetter; }; diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 5c1b020c9d..16c4084a77 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -159,8 +159,9 @@ void LLViewerControlListener::toggle(LLSD const & request) if (info.control->isType(TYPE_BOOLEAN)) { - LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << LL_ENDL; - info.control->set(! info.control->get().asBoolean(), false); + bool value = !info.control->get().asBoolean(); + LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << " to " << value << LL_ENDL; + info.control->set(value, false); } else { diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index 80ae7e87bb..c809dfff91 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,17 +1,24 @@ leap = require 'leap' +function check_response(res) + if res.error then + error(res.error) + end + return res +end + local LLDebugSettings = {} function LLDebugSettings.set(name, value) - return leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value}) + check_response(leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value})) end function LLDebugSettings.toggle(name) - return leap.request('LLViewerControl', {op='toggle', group='Global', key=name}) + check_response(leap.request('LLViewerControl', {op='toggle', group='Global', key=name})) end function LLDebugSettings.get(name) - return leap.request('LLViewerControl', {op='get', group='Global', key=name})['value'] + return check_response(leap.request('LLViewerControl', {op='get', group='Global', key=name}))['value'] end return LLDebugSettings -- cgit v1.2.3 From c231c97eeefc484b74198ba86251054b7dc0e6bb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 2 May 2024 21:13:28 -0400 Subject: WIP: In llcallbacklist.h, add singleton LLLater for time delays. The big idea is to reduce the number of per-tick callbacks asking, "Is it time yet? Is it time yet?" We do that for LLEventTimer and LLEventTimeout. LLLater presents doAtTime(LLDate), with doAfterInterval() and doPeriodically() methods implemented using doAtTime(). All return handles. The free functions doAfterInterval() and doPeriodically() now forward to the corresponding LLLater methods. LLLater also presents isRunning(handle) and cancel(handle). LLLater borrows the tactic of LLEventTimer: while there's at least one running timer, it registers an LLCallbackList tick() callback to service ready timers. But instead of looping over all of them asking, "Are you ready?" it keeps them in a priority queue ordered by desired timestamp, and only touches those whose timestamp has been reached. Also, it honors a maximum time slice: once the ready timers have run for longer than the limit, it defers processing other ready timers to the next tick() call. The intent is to consume fewer cycles per tick() call, both by the management machinery and the timers themselves. Revamp LLCallbackList to accept C++ callables in addition to (classic C function pointer, void*) pairs. Make addFunction() return a handle (different than LLLater handles) that can be passed to a new deleteFunction() overload, since std::function instances can't be compared for equality. In fact, implement LLCallbackList using boost::signals2::signal, which provides almost exactly what we want. LLCallbackList continues to accept (function pointer, void*) pairs, but now we store a lambda that calls the function pointer with that void*. It takes less horsing around to create a C++ callable from a (function pointer, void*) pair than the other way around. For containsFunction() and deleteFunction(), such pairs are the keys for a lookup table whose values are handles. Instead of having a static global LLCallbackList gIdleCallbacks, make LLCallbackList an LLSingleton to guarantee initialization. For backwards compatibility, gIdleCallbacks is now a macro for LLCallbackList::instance(). Move doOnIdleOneTime() and doOnIdleRepeating() functions to LLCallbackList methods, but for backwards compatibility continue providing free functions. Reimplement LLEventTimer using LLLater::doPeriodically(). One implication is that LLEventTimer need no longer be derived from LLInstanceTracker, which we used to iterate over all instances every tick. Give it start() and stop() methods, since some subclasses (e.g. LLFlashTimer) used to call its member LLTimer's start() and stop(). Remove updateClass(): LLCallbackList::callFunctions() now takes care of that. Remove LLToastLifeTimer::start() and stop(), since LLEventTimer now provides those. Remove getRemainingTimeF32(), since LLLater does not (yet) provide that feature. While at it, make LLEventTimer::tick() return bool instead of BOOL, and change existing overrides. Make LLApp::stepFrame() call LLCallbackList::callFunctions() instead of LLEventTimer::updateClass(). We could have refactored LLEventTimer to use the mechanism now built into LLLater, but frankly the LLEventTimer API is rather clumsy. You MUST derive a subclass and override tick(), and you must instantiate your subclass on the heap because, when your tick() override returns false, LLEventTimer deletes its subclass instance. The LLLater API is simpler to use, and LLEventTimer is much simplified by using it. Merge lleventfilter.h's LLEventTimeoutBase into LLEventTimeout, and likewise merge LLEventThrottleBase into LLEventThrottle. The separation was for testability, but now that they're no longer based on LLTimer, it becomes harder to use dummy time for testing. Temporarily skip tests based on LLEventTimeoutBase and LLEventThrottleBase. Instead of listening for LLEventPump("mainloop") ticks and using LLTimer, LLEventTimeout now uses LLLater::doAfterInterval(). Instead of LLTimer and LLEventTimeout, LLEventThrottle likewise now uses LLLater::doAfterInterval(). Recast a couple local LLEventTimeout pre-lambda callable classes with lambdas. Dignify F64 with a new typedef LLDate::timestamp. LLDate heavily depends on that as its base time representation, but there are those who question use of floating-point for time. This is a step towards insulating us from any future change. --- indra/newview/llappearancemgr.cpp | 5 ++-- indra/newview/lldonotdisturbnotificationstorage.h | 2 +- indra/newview/llfloaterlinkreplace.h | 2 +- indra/newview/llfloaterpreference.cpp | 2 +- indra/newview/llfloaterregionrestarting.h | 2 +- indra/newview/llfloateruipreview.cpp | 2 +- indra/newview/llimview.h | 2 +- indra/newview/lllocalbitmaps.h | 2 +- indra/newview/lllocalgltfmaterials.h | 2 +- indra/newview/llmediadataclient.h | 10 ++++---- indra/newview/llpanelpeople.cpp | 6 ++--- indra/newview/llsetkeybinddialog.cpp | 2 +- indra/newview/llspeakers.h | 2 +- indra/newview/lltoast.cpp | 29 +++++++---------------- indra/newview/lltoast.h | 10 ++++---- indra/newview/llviewermessage.cpp | 2 +- indra/newview/llviewerparcelmediaautoplay.h | 2 +- 17 files changed, 35 insertions(+), 49 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index c84657cf7a..7e84ad3b2a 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -123,8 +123,7 @@ public: stop(); } - /*virtual*/ - BOOL tick() + bool tick() override { if(mEventTimer.hasExpired()) { @@ -332,7 +331,7 @@ public: // virtual // Will be deleted after returning true - only safe to do this if all callbacks have fired. - BOOL tick() + bool tick() override { // mPendingRequests will be zero if all requests have been // responded to. mWaitTimes.empty() will be true if we have diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index 237d58b4de..2d39b5efed 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -42,7 +42,7 @@ public: ~LLDoNotDisturbNotificationStorageTimer(); public: - BOOL tick(); + bool tick() override; }; class LLDoNotDisturbNotificationStorage : public LLParamSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index 060773f93e..8d91187a33 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -89,7 +89,7 @@ public: BOOL postBuild(); virtual void onOpen(const LLSD& key); - virtual BOOL tick(); + bool tick() override; private: void checkEnableStart(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index a3e173398f..34dc263519 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1960,7 +1960,7 @@ public: protected: - BOOL tick() + bool tick() override { mCallback(mNewValue); mEventTimer.stop(); diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h index 46416db2c8..d254149e30 100644 --- a/indra/newview/llfloaterregionrestarting.h +++ b/indra/newview/llfloaterregionrestarting.h @@ -43,7 +43,7 @@ private: LLFloaterRegionRestarting(const LLSD& key); virtual ~LLFloaterRegionRestarting(); virtual BOOL postBuild(); - virtual BOOL tick(); + bool tick() override; virtual void refresh(); virtual void draw(); virtual void regionChange(); diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 553d09bec2..6da380c639 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -254,7 +254,7 @@ class LLFadeEventTimer : public LLEventTimer { public: LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); - BOOL tick(); + bool tick() override; LLGUIPreviewLiveFile* mParent; private: BOOL mFadingOut; // fades in then out; this is toggled in between diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index bace97d37a..f0e3e26a86 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -51,7 +51,7 @@ class LLSessionTimeoutTimer : public LLEventTimer public: LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {} virtual ~LLSessionTimeoutTimer() {}; - /* virtual */ BOOL tick(); + bool tick() override; private: LLUUID mSessionId; diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 1fdf9dccbf..8420049b1e 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -121,7 +121,7 @@ class LLLocalBitmapTimer : public LLEventTimer void startTimer(); void stopTimer(); bool isRunning(); - BOOL tick(); + bool tick() override; }; diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index 13b7577e96..53639dfb1d 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -90,7 +90,7 @@ public: void startTimer(); void stopTimer(); bool isRunning(); - BOOL tick(); + bool tick() override; }; class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr> diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 8cd4793106..428e85b976 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -219,13 +219,13 @@ protected: { public: RetryTimer(F32 time, Request::ptr_t); - virtual BOOL tick(); + virtual bool tick() override; private: // back-pointer Request::ptr_t mRequest; }; - - + + protected: typedef std::list<Request::ptr_t> request_queue_t; typedef std::set<Request::ptr_t> request_set_t; @@ -286,12 +286,12 @@ private: { public: QueueTimer(F32 time, LLMediaDataClient *mdc); - virtual BOOL tick(); + bool tick() override; private: // back-pointer LLPointer<LLMediaDataClient> mMDC; }; - + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } bool mQueueTimerIsRunning; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 13b52e97c5..aad6ceecb2 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -313,7 +313,7 @@ public: mEventTimer.stop(); } - virtual BOOL tick() // from LLEventTimer + virtual bool tick() override // from LLEventTimer { return FALSE; } @@ -367,7 +367,7 @@ public: } - /*virtual*/ BOOL tick() + bool tick() override { if (!mIsActive) return FALSE; @@ -508,7 +508,7 @@ public: } } - /*virtual*/ BOOL tick() + bool tick() override { update(); return FALSE; diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 74844a80e8..79d03922cc 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -53,7 +53,7 @@ public: virtual ~Updater(){} protected: - BOOL tick() + bool tick() override { mCallback(mMask); // Deletes itseft after execution diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 22c9481687..0242da1605 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -159,7 +159,7 @@ public: * * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). */ - virtual BOOL tick(); + bool tick() override; /** * Clears the callback. diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 223aaad811..d30e028d33 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -43,34 +43,21 @@ LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period) { } -/*virtual*/ -BOOL LLToastLifeTimer::tick() -{ - if (mEventTimer.hasExpired()) - { - mToast->expire(); - } - return FALSE; -} - -void LLToastLifeTimer::stop() -{ - mEventTimer.stop(); -} - -void LLToastLifeTimer::start() +bool LLToastLifeTimer::tick() { - mEventTimer.start(); + mToast->expire(); + return false; } void LLToastLifeTimer::restart() { - mEventTimer.reset(); + // start() discards any previously-running mTimer + start(); } -BOOL LLToastLifeTimer::getStarted() +bool LLToastLifeTimer::getStarted() { - return mEventTimer.getStarted(); + return LLLater::instance.isRunning(mTimer); } void LLToastLifeTimer::setPeriod(F32 period) @@ -78,12 +65,14 @@ void LLToastLifeTimer::setPeriod(F32 period) mPeriod = period; } +/*==========================================================================*| F32 LLToastLifeTimer::getRemainingTimeF32() { F32 et = mEventTimer.getElapsedTimeF32(); if (!getStarted() || et > mPeriod) return 0.0f; return mPeriod - et; } +|*==========================================================================*/ //-------------------------------------------------------------------------- LLToast::Params::Params() diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index ab559f1e6f..49969ab70a 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -53,15 +53,13 @@ public: LLToastLifeTimer(LLToast* toast, F32 period); /*virtual*/ - BOOL tick(); - void stop(); - void start(); + bool tick() override; void restart(); - BOOL getStarted(); + bool getStarted(); void setPeriod(F32 period); - F32 getRemainingTimeF32(); +// F32 getRemainingTimeF32(); - LLTimer& getEventTimer() { return mEventTimer;} +// LLTimer& getEventTimer() { return mEventTimer;} private : LLToast* mToast; }; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ff2753d240..b65305337f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2890,7 +2890,7 @@ public: virtual ~LLPostTeleportNotifiers(); //function to be called at the supplied frequency - virtual BOOL tick(); + bool tick() override; }; LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index e83085dee0..9367c2a629 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -35,7 +35,7 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerPar { LLSINGLETON(LLViewerParcelMediaAutoPlay); public: - virtual BOOL tick() override; + bool tick() override; static void playStarted(); private: -- cgit v1.2.3 From 48e1979abaecc03af96e7e752e65c645083a4268 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 2 May 2024 23:57:29 -0400 Subject: Introduce LLLater::getRemaining(handle). Some timer use cases need to know not only whether the timer is active, but how much time remains before it (next) fires. Introduce LLLater::mDoneTimes to track, for each handle, the timestamp at which it's expected to fire. We can't just look up the target timestamp in mQueue's func_at entry because there's no documented way to navigate from a handle_type to a node iterator or pointer. Nor can we store it in mHandles because of order dependency: we need the mDoneTimes iterator so we can bind it into the Periodic functor for doPeriodically(), but we need the mQueue handle to store in mHandles. If we could find the mQueue node from the new handle, we could update the func_at entry after emplace() -- but if we could find the mQueue node from a handle, we wouldn't need to store the target timestamp separately anyway. Split LLLater::doAtTime() into internal doAtTime1() and doAtTime2(): the first creates an mDoneTimes entry and returns an iterator, the second finishes creating new mQueue and mHandles entries based on that mDoneTimes entry. This lets doPeriodically()'s Periodic bind the mDoneTimes iterator. Then instead of continually incrementing an internal data member, it increments the mDoneTimes entry to set the next upcoming timestamp. That lets getRemaining() report the next upcoming timestamp rather than only the original one. Add LLEventTimer::isRunning() and getRemaining(), forwarding to its LLLater handle. Fix various LLEventTimer subclass references to mEventTimer.stop(), etc. Fix non-inline LLEventTimer subclass tick() overrides for bool, not BOOL. Remove LLAppViewer::idle() call to LLEventTimer::updateClass(). Since LLApp::stepFrame() already calls LLCallbackList::callFunctions(), assume we've already handled that every tick. --- indra/newview/llappearancemgr.cpp | 19 ++++++------------- indra/newview/llappviewer.cpp | 7 +++---- indra/newview/lldonotdisturbnotificationstorage.cpp | 4 ++-- indra/newview/llfloaterlinkreplace.cpp | 10 +++++----- indra/newview/llfloaterpreference.cpp | 8 ++++---- indra/newview/llfloaterregionrestarting.cpp | 4 ++-- indra/newview/llfloateruipreview.cpp | 6 +++--- indra/newview/llimview.cpp | 6 +++--- indra/newview/lllocalbitmaps.cpp | 13 ++++--------- indra/newview/lllocalbitmaps.h | 1 - indra/newview/lllocalgltfmaterials.cpp | 13 ++++--------- indra/newview/lllocalgltfmaterials.h | 1 - indra/newview/llmediadataclient.cpp | 14 +++++++------- indra/newview/llpanelpeople.cpp | 18 +++++++++--------- indra/newview/llsetkeybinddialog.cpp | 4 +--- indra/newview/llspeakers.cpp | 4 ++-- indra/newview/lltoast.cpp | 4 ++-- indra/newview/llviewermessage.cpp | 6 +++--- indra/newview/llviewerparcelmediaautoplay.cpp | 4 ++-- 19 files changed, 62 insertions(+), 84 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 7e84ad3b2a..5b8835add8 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -118,25 +118,19 @@ public: LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) { // restart timer on BOF changed event - LLOutfitObserver::instance().addBOFChangedCallback(boost::bind( - &LLOutfitUnLockTimer::reset, this)); + LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); }); stop(); } bool tick() override { - if(mEventTimer.hasExpired()) - { - LLAppearanceMgr::instance().setOutfitLocked(false); - } - return FALSE; + LLAppearanceMgr::instance().setOutfitLocked(false); + return false; } - void stop() { mEventTimer.stop(); } - void start() { mEventTimer.start(); } - void reset() { mEventTimer.reset(); } - BOOL getStarted() { return mEventTimer.getStarted(); } +// void reset() { mEventTimer.reset(); } + bool getStarted() { return isRunning(); } - LLTimer& getEventTimer() { return mEventTimer;} +// LLTimer& getEventTimer() { return mEventTimer;} }; // support for secondlife:///app/appearance SLapps @@ -1706,7 +1700,6 @@ void LLAppearanceMgr::setOutfitLocked(bool locked) mOutfitLocked = locked; if (locked) { - mUnlockOutfitTimer->reset(); mUnlockOutfitTimer->start(); } else diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d6a4c41497..0200ea6ad7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4586,7 +4586,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); /////////////////////////////////////////////////////// void LLAppViewer::idle() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; pingMainloopTimeout("Main:Idle"); // Update frame timers @@ -4594,8 +4594,7 @@ void LLAppViewer::idle() LLFrameTimer::updateFrameTime(); LLFrameTimer::updateFrameCount(); - LLEventTimer::updateClass(); - LLPerfStats::updateClass(); + LLPerfStats::updateClass(); // LLApp::stepFrame() performs the above three calls plus mRunner.run(). // Not sure why we don't call stepFrame() here, except that LLRunner seems @@ -4607,7 +4606,7 @@ void LLAppViewer::idle() LLDirPickerThread::clearDead(); F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); - LLGLTFMaterialList::flushUpdates(); + LLGLTFMaterialList::flushUpdates(); // Service the WorkQueue we use for replies from worker threads. // Use function statics for the timeslice setting so we only have to fetch diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 4d9ef99319..93a0ef0e82 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -55,7 +55,7 @@ LLDoNotDisturbNotificationStorageTimer::~LLDoNotDisturbNotificationStorageTimer( } -BOOL LLDoNotDisturbNotificationStorageTimer::tick() +bool LLDoNotDisturbNotificationStorageTimer::tick() { LLDoNotDisturbNotificationStorage * doNotDisturbNotificationStorage = LLDoNotDisturbNotificationStorage::getInstance(); @@ -64,7 +64,7 @@ BOOL LLDoNotDisturbNotificationStorageTimer::tick() { doNotDisturbNotificationStorage->saveNotifications(); } - return FALSE; + return false; } LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage() diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index b42c49c607..0bc3c241fa 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -45,7 +45,7 @@ LLFloaterLinkReplace::LLFloaterLinkReplace(const LLSD& key) mTargetUUID(LLUUID::null), mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize")) { - mEventTimer.stop(); + stop(); } LLFloaterLinkReplace::~LLFloaterLinkReplace() @@ -202,7 +202,7 @@ void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, cons mStartBtn->setEnabled(FALSE); mRefreshBtn->setEnabled(FALSE); - mEventTimer.start(); + start(); tick(); } else @@ -298,7 +298,7 @@ void LLFloaterLinkReplace::decreaseOpenItemCount() mStatusText->setText(getString("ReplaceFinished")); mStartBtn->setEnabled(TRUE); mRefreshBtn->setEnabled(TRUE); - mEventTimer.stop(); + stop(); LL_INFOS() << "Inventory link replace finished." << LL_ENDL; } else @@ -310,7 +310,7 @@ void LLFloaterLinkReplace::decreaseOpenItemCount() } } -BOOL LLFloaterLinkReplace::tick() +bool LLFloaterLinkReplace::tick() { LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; @@ -320,7 +320,7 @@ BOOL LLFloaterLinkReplace::tick() { if (!mRemainingInventoryItems.size()) { - mEventTimer.stop(); + stop(); break; } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 34dc263519..d9f7f0a171 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1947,7 +1947,7 @@ public: :LLEventTimer(period), mCallback(cb) { - mEventTimer.stop(); + stop(); } virtual ~Updater(){} @@ -1955,7 +1955,7 @@ public: void update(const LLSD& new_value) { mNewValue = new_value; - mEventTimer.start(); + start(); } protected: @@ -1963,9 +1963,9 @@ protected: bool tick() override { mCallback(mNewValue); - mEventTimer.stop(); + stop(); - return FALSE; + return false; } private: diff --git a/indra/newview/llfloaterregionrestarting.cpp b/indra/newview/llfloaterregionrestarting.cpp index 95d4265bb4..6817cce5f6 100644 --- a/indra/newview/llfloaterregionrestarting.cpp +++ b/indra/newview/llfloaterregionrestarting.cpp @@ -74,11 +74,11 @@ void LLFloaterRegionRestarting::regionChange() close(); } -BOOL LLFloaterRegionRestarting::tick() +bool LLFloaterRegionRestarting::tick() { refresh(); - return FALSE; + return false; } void LLFloaterRegionRestarting::refresh() diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 6da380c639..74b6218b46 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -355,7 +355,7 @@ LLFadeEventTimer::LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent) } // Single tick of fade event timer: increment the color -BOOL LLFadeEventTimer::tick() +bool LLFadeEventTimer::tick() { float diff = 0.04f; if(TRUE == mFadingOut) // set fade for in/out color direction @@ -365,7 +365,7 @@ BOOL LLFadeEventTimer::tick() if(NULL == mParent) // no more need to tick, so suicide { - return TRUE; + return true; } // Set up colors @@ -388,7 +388,7 @@ BOOL LLFadeEventTimer::tick() mFadingOut = FALSE; } - return FALSE; + return false; } // Constructor diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ce4a032b27..0144f13f24 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -99,16 +99,16 @@ const LLUUID LLOutgoingCallDialog::OCD_KEY = LLUUID("7CF78E11-0CFE-498D-ADB9-141 LLIMMgr* gIMMgr = NULL; -BOOL LLSessionTimeoutTimer::tick() +bool LLSessionTimeoutTimer::tick() { - if (mSessionId.isNull()) return TRUE; + if (mSessionId.isNull()) return true; LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); if (session && !session->mSessionInitialized) { gIMMgr->showSessionStartError("session_initialization_timed_out_error", mSessionId); } - return TRUE; + return true; } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 1e42773777..60edbfee88 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -996,23 +996,18 @@ LLLocalBitmapTimer::~LLLocalBitmapTimer() void LLLocalBitmapTimer::startTimer() { - mEventTimer.start(); + start(); } void LLLocalBitmapTimer::stopTimer() { - mEventTimer.stop(); + stop(); } -bool LLLocalBitmapTimer::isRunning() -{ - return mEventTimer.getStarted(); -} - -BOOL LLLocalBitmapTimer::tick() +bool LLLocalBitmapTimer::tick() { LLLocalBitmapMgr::getInstance()->doUpdates(); - return FALSE; + return false; } /*=======================================*/ diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 8420049b1e..96a39a3d66 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -120,7 +120,6 @@ class LLLocalBitmapTimer : public LLEventTimer public: void startTimer(); void stopTimer(); - bool isRunning(); bool tick() override; }; diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp index 61e0163798..91753349c8 100644 --- a/indra/newview/lllocalgltfmaterials.cpp +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -288,24 +288,19 @@ LLLocalGLTFMaterialTimer::~LLLocalGLTFMaterialTimer() void LLLocalGLTFMaterialTimer::startTimer() { - mEventTimer.start(); + start(); } void LLLocalGLTFMaterialTimer::stopTimer() { - mEventTimer.stop(); + stop(); } -bool LLLocalGLTFMaterialTimer::isRunning() -{ - return mEventTimer.getStarted(); -} - -BOOL LLLocalGLTFMaterialTimer::tick() +bool LLLocalGLTFMaterialTimer::tick() { // todo: do on idle? No point in timer LLLocalGLTFMaterialMgr::getInstance()->doUpdates(); - return FALSE; + return false; } /*=======================================*/ diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index 53639dfb1d..ff54d48602 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -89,7 +89,6 @@ public: public: void startTimer(); void stopTimer(); - bool isRunning(); bool tick() override; }; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index d3b981e205..5bf587292d 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -418,10 +418,10 @@ LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc) } // virtual -BOOL LLMediaDataClient::QueueTimer::tick() +bool LLMediaDataClient::QueueTimer::tick() { - BOOL result = TRUE; - + bool result = TRUE; + if (!mMDC.isNull()) { result = mMDC->processQueueTimer(); @@ -451,7 +451,7 @@ LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request) } // virtual -BOOL LLMediaDataClient::RetryTimer::tick() +bool LLMediaDataClient::RetryTimer::tick() { mRequest->stopTracking(); @@ -464,12 +464,12 @@ BOOL LLMediaDataClient::RetryTimer::tick() LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *mRequest << ", retrying." << LL_ENDL; mRequest->reEnqueue(); } - + // Release the ref to the request. - mRequest.reset(); + mRequest.reset(); // Don't fire again - return TRUE; + return true; } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index aad6ceecb2..ab79442f51 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -310,12 +310,12 @@ public: : LLEventTimer(period), LLPanelPeople::Updater(cb) { - mEventTimer.stop(); + stop(); } - virtual bool tick() override // from LLEventTimer + bool tick() override // from LLEventTimer { - return FALSE; + return false; } }; @@ -359,7 +359,7 @@ public: { // events can arrive quickly in bulk - we need not process EVERY one of them - // so we wait a short while to let others pile-in, and process them in aggregate. - mEventTimer.start(); + start(); } // save-up all the mask-bits which have come-in @@ -377,10 +377,10 @@ public: } // Stop updates. - mEventTimer.stop(); + stop(); mMask = 0; - return FALSE; + return false; } // virtual @@ -499,19 +499,19 @@ public: { // update immediately and start regular updates update(); - mEventTimer.start(); + start(); } else { // stop regular updates - mEventTimer.stop(); + stop(); } } bool tick() override { update(); - return FALSE; + return false; } private: }; diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 79d03922cc..a6d628e1ad 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -46,9 +46,7 @@ public: :LLEventTimer(period), mMask(mask), mCallback(cb) - { - mEventTimer.start(); - } + {} virtual ~Updater(){} diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 60bada8f58..2bc8d04a8e 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -181,13 +181,13 @@ LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 acti { } -BOOL LLSpeakerActionTimer::tick() +bool LLSpeakerActionTimer::tick() { if (mActionCallback) { return (BOOL)mActionCallback(mSpeakerId); } - return TRUE; + return true; } void LLSpeakerActionTimer::unset() diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index d30e028d33..d2a650f200 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -57,7 +57,7 @@ void LLToastLifeTimer::restart() bool LLToastLifeTimer::getStarted() { - return LLLater::instance.isRunning(mTimer); + return isRunning(); } void LLToastLifeTimer::setPeriod(F32 period) @@ -326,7 +326,7 @@ void LLToast::setFading(bool transparent) F32 LLToast::getTimeLeftToLive() { - F32 time_to_live = mTimer->getRemainingTimeF32(); + F32 time_to_live = mTimer->getRemaining(); if (!mIsFading) { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b65305337f..e8b81ac3b4 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2901,9 +2901,9 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() { } -BOOL LLPostTeleportNotifiers::tick() +bool LLPostTeleportNotifiers::tick() { - BOOL all_done = FALSE; + bool all_done = false; if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) { // get callingcards and landmarks available to the user arriving. @@ -2927,7 +2927,7 @@ BOOL LLPostTeleportNotifiers::tick() gInventory.addObserver(fetcher); } } - all_done = TRUE; + all_done = true; } return all_done; diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index db8fcb4dc4..8cf86910e7 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -60,7 +60,7 @@ void LLViewerParcelMediaAutoPlay::playStarted() LLSingleton<LLViewerParcelMediaAutoPlay>::getInstance()->mPlayed = TRUE; } -BOOL LLViewerParcelMediaAutoPlay::tick() +bool LLViewerParcelMediaAutoPlay::tick() { LLParcel *this_parcel = NULL; LLViewerRegion *this_region = NULL; @@ -156,7 +156,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick() } - return FALSE; // continue ticking forever please. + return false; // continue ticking forever please. } //static -- cgit v1.2.3 From 9f620efa9dd60c5de6b7ea807d53bba922294726 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 3 May 2024 08:52:32 -0400 Subject: Make LLLater store target time in mHandles; ditch 2nd unordered_map. Instead of maintaining a whole separate unordered_map to look up target times, make room in the HandleMap entry for the target time. There's still circularity, but the split into doAtTime1() and doAtTime2() resolves it: since doAtTime2() accepts the mHandles iterator created by doAtTime1(), doAtTime2() can simply store the new mQueue handle_type into the appropriate slot. Also sprinkle in a few more override keywords for consistency. --- indra/newview/llfloaterlinkreplace.h | 4 ++-- indra/newview/llfloaterregionrestarting.h | 6 +++--- indra/newview/llpanelpeople.cpp | 12 +++--------- 3 files changed, 8 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index 8d91187a33..a11e025a71 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -86,8 +86,8 @@ public: LLFloaterLinkReplace(const LLSD& key); virtual ~LLFloaterLinkReplace(); - BOOL postBuild(); - virtual void onOpen(const LLSD& key); + BOOL postBuild() override; + void onOpen(const LLSD& key) override; bool tick() override; diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h index d254149e30..6d3639c40c 100644 --- a/indra/newview/llfloaterregionrestarting.h +++ b/indra/newview/llfloaterregionrestarting.h @@ -42,10 +42,10 @@ public: private: LLFloaterRegionRestarting(const LLSD& key); virtual ~LLFloaterRegionRestarting(); - virtual BOOL postBuild(); + BOOL postBuild() override; bool tick() override; - virtual void refresh(); - virtual void draw(); + void refresh() override; + void draw() override; virtual void regionChange(); std::string mName; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index ab79442f51..8efaab034b 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -312,11 +312,6 @@ public: { stop(); } - - bool tick() override // from LLEventTimer - { - return false; - } }; /** @@ -353,7 +348,7 @@ public: LLAvatarTracker::instance().removeObserver(this); } - /*virtual*/ void changed(U32 mask) + void changed(U32 mask) override { if (mIsActive) { @@ -383,8 +378,7 @@ public: return false; } - // virtual - void setActive(bool active) + void setActive(bool active) override { mIsActive = active; if (active) @@ -493,7 +487,7 @@ public: setActive(false); } - /*virtual*/ void setActive(bool val) + void setActive(bool val) override { if (val) { -- cgit v1.2.3 From 5e64fd06a6281eb4b7cc0e30b3d8dae62c264603 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 3 May 2024 09:16:56 -0400 Subject: Not every LLAvatarListUpdater subclass overrides tick(). LLAvatarListUpdater is an LLEventTimer subclass meant to be a base class of still other subclasses. One would presume that every one of them should override tick(), since LLAvatarListUpdater::tick() is a no-op that simply asks to be called again. But making it abstract (=0) produces errors since at least one subclass does not define its own tick() method. This seems less than useful, since the specific tick() method is the whole point of deriving from LLEventTimer, but oh well. --- indra/newview/llpanelpeople.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 8efaab034b..b342fa5549 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -312,6 +312,11 @@ public: { stop(); } + + bool tick() override // from LLEventTimer + { + return false; + } }; /** -- cgit v1.2.3 From cec3b8d870085925cd0c9fb900b7d5e4629bcbfd Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 7 May 2024 13:10:00 +0300 Subject: Copy xml files to scripts/lua; make Lua debug floater resizable --- indra/newview/scripts/lua/LLDebugSettings.lua | 2 +- .../newview/skins/default/xui/en/floater_lua_debug.xml | 18 +++++++++--------- indra/newview/viewer_manifest.py | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index c809dfff91..c1d74fe00a 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,6 +1,6 @@ leap = require 'leap' -function check_response(res) +local function check_response(res) if res.error then error(res.error) end diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml index a028a1802c..012ea6f254 100644 --- a/indra/newview/skins/default/xui/en/floater_lua_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater can_minimize="false" - can_resize="false" + can_resize="true" can_close="true" bevel_style="in" height="220" @@ -14,7 +14,7 @@ <text type="string" length="1" - follows="left|bottom" + follows="left|top" font="SansSerif" height="30" layout="topleft" @@ -26,7 +26,7 @@ LUA string: </text> <check_box - follows="left|bottom" + follows="right|top" height="15" label="Use clean lua_State" layout="topleft" @@ -37,7 +37,7 @@ <line_editor border_style="line" border_thickness="1" - follows="left|bottom" + follows="left|top|right" font="SansSerif" height="20" layout="topleft" @@ -48,7 +48,7 @@ top_delta="30" width="435" /> <button - follows="left|bottom" + follows="right|top" height="25" label="Execute" layout="topleft" @@ -63,7 +63,7 @@ height="95" layout="topleft" name="result_text" - follows="left|top" + follows="all" max_length="65536" width="515" top_delta="40" @@ -85,7 +85,7 @@ border_style="line" enabled="false" border_thickness="1" - follows="left|bottom" + follows="left|bottom|right" font="SansSerif" height="20" layout="topleft" @@ -96,7 +96,7 @@ top_delta="-2" width="320" /> <button - follows="left|bottom" + follows="right|bottom" height="25" label="Browse..." label_selected="Browse..." @@ -106,7 +106,7 @@ top_delta="-2" width="70" /> <button - follows="left|bottom" + follows="right|bottom" height="25" label="Run" label_selected="Run" diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index b60e349e90..8123827f5a 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -168,6 +168,7 @@ class ViewerManifest(LLManifest): with self.prefix(src_dst="scripts/lua"): self.path("*.lua") + self.path("*.xml") #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing -- cgit v1.2.3 From bd8e1dd8d2340636521200d15a045321ea07b986 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 8 May 2024 16:58:34 -0400 Subject: Tweak a couple things --- indra/newview/llappearancemgr.cpp | 4 ++-- indra/newview/scripts/lua/LLDebugSettings.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5b8835add8..dccd63af38 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -618,8 +618,8 @@ void LLBrokenLinkObserver::changed(U32 mask) if (id == mUUID) { // Might not be processed yet and it is not a - // good idea to update appearane here, postpone. - doOnIdleOneTime([this]() + // good idea to update appearance here, postpone. + doOnIdleOneTime([this] { postProcess(); }); diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index c809dfff91..c1d74fe00a 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,6 +1,6 @@ leap = require 'leap' -function check_response(res) +local function check_response(res) if res.error then error(res.error) end -- cgit v1.2.3 From 24e8a0bb5d47f14727ce4d018232d935232469d2 Mon Sep 17 00:00:00 2001 From: AiraYumi <aira.youme@airanyumi.net> Date: Thu, 9 May 2024 23:23:39 +0900 Subject: enable ime on xwayland (environment setting move) --- indra/newview/linux_tools/wrapper.sh | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index 7d26c81283..a027aaf6d1 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -62,6 +62,10 @@ export SDL_VIDEO_X11_DGAMOUSE=0 if [ "$GTK_IM_MODULE" = "scim" ]; then export GTK_IM_MODULE=xim fi +if [ "$XMODIFIERS" = "" ]; then + ## IME is valid only for fcitx, not when using ibus + export XMODIFIERS="@im=fcitx" +fi ## - Automatically work around the ATI mouse cursor crash bug: ## (this workaround is disabled as most fglrx users do not see the bug) -- cgit v1.2.3 From 1abf5f18d6afc7ae9e1b1562b92e5c1ce33b722f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 15 May 2024 09:03:02 -0400 Subject: Make leap.lua honor an "error" key in viewer response. --- indra/newview/scripts/lua/leap.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index ade91789f0..cfb7377523 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -161,10 +161,12 @@ function leap.request(pump, data) dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) -- kill off temporary WaitForReqid object, even if error pending[reqid] = nil - if ok then - return response - else + if not ok then error(response) + elseif response.error then + error(response.error) + else + return response end end @@ -186,7 +188,7 @@ function leap.generate(pump, data, checklast) local ok, response, resumed_with repeat ok, response = pcall(waitfor.wait, waitfor) - if not ok then + if (not ok) or response.error then break end -- can resume(false) to terminate generate() and clean up @@ -196,6 +198,8 @@ function leap.generate(pump, data, checklast) pending[reqid] = nil if not ok then error(response) + elseif response.error then + error(response.error) end end -- cgit v1.2.3 From c3da5bb12d1c7c173929433589a4068555791bea Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 15 May 2024 09:11:29 -0400 Subject: Manual whitespace fixes (fix_whitespace.py). --- indra/newview/llappviewer.cpp | 7020 ++++++++-------- indra/newview/llfilepicker.cpp | 2080 ++--- indra/newview/llfilepicker.h | 206 +- indra/newview/llfloaterluadebug.cpp | 36 +- indra/newview/llfloatersettingsdebug.cpp | 706 +- indra/newview/llfloatersettingsdebug.h | 38 +- indra/newview/llinventoryfunctions.cpp | 1964 ++--- indra/newview/llinventoryfunctions.h | 282 +- indra/newview/llinventorymodel.cpp | 6722 +++++++-------- indra/newview/llstartup.cpp | 6120 +++++++------- indra/newview/lltoolplacer.cpp | 872 +- indra/newview/lltoolplacer.h | 36 +- indra/newview/llviewercontrollistener.cpp | 292 +- indra/newview/llviewerfloaterreg.cpp | 418 +- indra/newview/llviewermenu.cpp | 12102 ++++++++++++++-------------- indra/newview/llviewermenu.h | 56 +- indra/newview/llviewermenufile.cpp | 1408 ++-- indra/newview/llviewermenufile.h | 76 +- 18 files changed, 20217 insertions(+), 20217 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0b566cbc73..cdb9dac92a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -109,7 +109,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llperfstats.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -149,7 +149,7 @@ #include <boost/throw_exception.hpp> #if LL_WINDOWS -# include <share.h> // For _SH_DENYWR in processMarkerFiles +# include <share.h> // For _SH_DENYWR in processMarkerFiles #else # include <sys/file.h> // For processMarkerFiles #endif @@ -317,16 +317,16 @@ const char* gPlatform = LL_PLATFORM_KEY; LLSD gDebugInfo; -U32 gFrameCount = 0; +U32 gFrameCount = 0; U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground LLPumpIO* gServicePump = NULL; U64MicrosecondsImplicit gFrameTime = 0; F32SecondsImplicit gFrameTimeSeconds = 0.f; F32SecondsImplicit gFrameIntervalSeconds = 0.f; -F32 gFPSClamped = 10.f; // Pretend we start at target rate. -F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets -U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds +F32 gFPSClamped = 10.f; // Pretend we start at target rate. +F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets +U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds LLTimer gRenderStartTime; LLFrameTimer gForegroundTime; @@ -339,24 +339,24 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME; S32 gPendingMetricsUploads = 0; -BOOL gDisconnected = FALSE; +BOOL gDisconnected = FALSE; // used to restore texture state after a mode switch -LLFrameTimer gRestoreGLTimer; -BOOL gRestoreGL = FALSE; -bool gUseWireframe = FALSE; +LLFrameTimer gRestoreGLTimer; +BOOL gRestoreGL = FALSE; +bool gUseWireframe = FALSE; LLMemoryInfo gSysMemory; U64Bytes gMemoryAllocated(0); // updated in display_stats() in llviewerdisplay.cpp std::string gLastVersionChannel; -LLVector3 gWindVec(3.0, 3.0, 0.0); -LLVector3 gRelativeWindVec(0.0, 0.0, 0.0); +LLVector3 gWindVec(3.0, 3.0, 0.0); +LLVector3 gRelativeWindVec(0.0, 0.0, 0.0); -U32 gPacketsIn = 0; +U32 gPacketsIn = 0; -BOOL gPrintMessagesThisFrame = FALSE; +BOOL gPrintMessagesThisFrame = FALSE; BOOL gRandomizeFramerate = FALSE; BOOL gPeriodicSlowFrame = FALSE; @@ -394,53 +394,53 @@ void processComposeSwitch(const std::string&, const std::string&, static std::set<std::string> default_trans_args; void init_default_trans_args() { - default_trans_args.insert("SECOND_LIFE"); // World - default_trans_args.insert("APP_NAME"); - default_trans_args.insert("CAPITALIZED_APP_NAME"); - default_trans_args.insert("SECOND_LIFE_GRID"); - default_trans_args.insert("SUPPORT_SITE"); - // This URL shows up in a surprising number of places in various skin - // files. We really only want to have to maintain a single copy of it. - default_trans_args.insert("create_account_url"); + default_trans_args.insert("SECOND_LIFE"); // World + default_trans_args.insert("APP_NAME"); + default_trans_args.insert("CAPITALIZED_APP_NAME"); + default_trans_args.insert("SECOND_LIFE_GRID"); + default_trans_args.insert("SUPPORT_SITE"); + // This URL shows up in a surprising number of places in various skin + // files. We really only want to have to maintain a single copy of it. + default_trans_args.insert("create_account_url"); } struct SettingsFile : public LLInitParam::Block<SettingsFile> { - Mandatory<std::string> name; - Optional<std::string> file_name; - Optional<bool> required, - persistent; - Optional<std::string> file_name_setting; - - SettingsFile() - : name("name"), - file_name("file_name"), - required("required", false), - persistent("persistent", true), - file_name_setting("file_name_setting") - {} + Mandatory<std::string> name; + Optional<std::string> file_name; + Optional<bool> required, + persistent; + Optional<std::string> file_name_setting; + + SettingsFile() + : name("name"), + file_name("file_name"), + required("required", false), + persistent("persistent", true), + file_name_setting("file_name_setting") + {} }; struct SettingsGroup : public LLInitParam::Block<SettingsGroup> { - Mandatory<std::string> name; - Mandatory<S32> path_index; - Multiple<SettingsFile> files; - - SettingsGroup() - : name("name"), - path_index("path_index"), - files("file") - {} + Mandatory<std::string> name; + Mandatory<S32> path_index; + Multiple<SettingsFile> files; + + SettingsGroup() + : name("name"), + path_index("path_index"), + files("file") + {} }; struct SettingsFiles : public LLInitParam::Block<SettingsFiles> { - Multiple<SettingsGroup> groups; + Multiple<SettingsGroup> groups; - SettingsFiles() - : groups("group") - {} + SettingsFiles() + : groups("group") + {} }; static std::string gWindowTitle; @@ -455,122 +455,122 @@ static bool app_metrics_qa_mode = false; void idle_afk_check() { - // check idle timers - F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); - F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); - if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) - { - LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; - gAgent.setAFK(); - } + // check idle timers + F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); + F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); + if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) + { + LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; + gAgent.setAFK(); + } } // A callback set in LLAppViewer::init() static void ui_audio_callback(const LLUUID& uuid) { - if (gAudiop) - { - SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - gAudiop->triggerSound(soundData); - } + if (gAudiop) + { + SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + gAudiop->triggerSound(soundData); + } } // A callback set in LLAppViewer::init() static void deferred_ui_audio_callback(const LLUUID& uuid) { - if (gAudiop) - { - SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - LLDeferredSounds::instance().deferSound(soundData); - } + if (gAudiop) + { + SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + LLDeferredSounds::instance().deferSound(soundData); + } } -bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) +bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) { - if(!match || !base || base->getPlainText()) - return false; - - LLUUID match_id = match->getID(); - - LLIconCtrl* icon; - - if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor - || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group - { - LLGroupIconCtrl::Params icon_params; - icon_params.group_id = match_id; - icon_params.rect = LLRect(0, 16, 16, 0); - icon_params.visible = true; - icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params); - } - else - { - LLAvatarIconCtrl::Params icon_params; - icon_params.avatar_id = match_id; - icon_params.rect = LLRect(0, 16, 16, 0); - icon_params.visible = true; - icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params); - } - - LLInlineViewSegment::Params params; - params.force_newline = false; - params.view = icon; - params.left_pad = 4; - params.right_pad = 4; - params.top_pad = -2; - params.bottom_pad = 2; - - base->appendWidget(params," ",false); - - return true; + if(!match || !base || base->getPlainText()) + return false; + + LLUUID match_id = match->getID(); + + LLIconCtrl* icon; + + if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor + || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group + { + LLGroupIconCtrl::Params icon_params; + icon_params.group_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params); + } + else + { + LLAvatarIconCtrl::Params icon_params; + icon_params.avatar_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params); + } + + LLInlineViewSegment::Params params; + params.force_newline = false; + params.view = icon; + params.left_pad = 4; + params.right_pad = 4; + params.top_pad = -2; + params.bottom_pad = 2; + + base->appendWidget(params," ",false); + + return true; } // Use these strictly for things that are constructed at startup, // or for things that are performance critical. JC static void settings_to_globals() { - LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); - BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); - BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); + LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); + BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); + BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); - MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); - MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); + MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); + MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); - LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); + LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); #if LL_DARWIN LLRender::sGLCoreProfile = true; #else LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile"); #endif - LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); - LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); - LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); - LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); - LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; - LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); - LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); - LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); - LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); - LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); - LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); - // clamp auto-open time to some minimum usable value - LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay")); - LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive"); - LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); - LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); - - gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); - gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); - gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); - - gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); - gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); + LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); + LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); + LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); + LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); + LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; + LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); + LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); + LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); + LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); + // clamp auto-open time to some minimum usable value + LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay")); + LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive"); + LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); + LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); + + gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); + gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); + gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); + + gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); + gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale")); - + #if LL_DARWIN LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL"); - gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); + gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); #endif } @@ -588,41 +588,41 @@ static void settings_modify() class LLFastTimerLogThread : public LLThread { public: - std::string mFile; - - LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") - { - std::string file_name = test_name + std::string(".slp"); - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); - } - - void run() - { - llofstream os(mFile.c_str()); - - while (!LLAppViewer::instance()->isQuitting()) - { - LLTrace::BlockTimer::writeLog(os); - os.flush(); - ms_sleep(32); - } - - os.close(); - } + std::string mFile; + + LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") + { + std::string file_name = test_name + std::string(".slp"); + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); + } + + void run() + { + llofstream os(mFile.c_str()); + + while (!LLAppViewer::instance()->isQuitting()) + { + LLTrace::BlockTimer::writeLog(os); + os.flush(); + ms_sleep(32); + } + + os.close(); + } }; //virtual bool LLAppViewer::initSLURLHandler() { - // does nothing unless subclassed - return false; + // does nothing unless subclassed + return false; } //virtual bool LLAppViewer::sendURLToOtherInstance(const std::string& url) { - // does nothing unless subclassed - return false; + // does nothing unless subclassed + return false; } //---------------------------------------------------------------------------- @@ -638,402 +638,402 @@ LLPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL; std::string getRuntime() { - return llformat("%.4f", (F32)LLTimer::getElapsedSeconds().value()); + return llformat("%.4f", (F32)LLTimer::getElapsedSeconds().value()); } LLAppViewer::LLAppViewer() -: mMarkerFile(), - mLogoutMarkerFile(), - mReportedCrash(false), - mNumSessions(0), +: mMarkerFile(), + mLogoutMarkerFile(), + mReportedCrash(false), + mNumSessions(0), mGeneralThreadPool(nullptr), - mPurgeCache(false), - mPurgeCacheOnExit(false), - mPurgeUserDataOnExit(false), - mSecondInstance(false), - mUpdaterNotFound(false), - mSavedFinalSnapshot(false), - mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. - mQuitRequested(false), - mLogoutRequestSent(false), - mLastAgentControlFlags(0), - mLastAgentForceUpdate(0), - mMainloopTimeout(NULL), - mAgentRegionLastAlive(false), - mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)), - mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), - mFastTimerLogThread(NULL), - mSettingsLocationList(NULL), - mIsFirstRun(false) + mPurgeCache(false), + mPurgeCacheOnExit(false), + mPurgeUserDataOnExit(false), + mSecondInstance(false), + mUpdaterNotFound(false), + mSavedFinalSnapshot(false), + mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. + mQuitRequested(false), + mLogoutRequestSent(false), + mLastAgentControlFlags(0), + mLastAgentForceUpdate(0), + mMainloopTimeout(NULL), + mAgentRegionLastAlive(false), + mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)), + mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), + mFastTimerLogThread(NULL), + mSettingsLocationList(NULL), + mIsFirstRun(false) { - if(NULL != sInstance) - { - LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; - } + if(NULL != sInstance) + { + LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; + } mDumpPath =""; - // Need to do this initialization before we do anything else, since anything - // that touches files should really go through the lldir API - gDirUtilp->initAppDirs("SecondLife"); - // - // IMPORTANT! Do NOT put anything that will write - // into the log files during normal startup until AFTER - // we run the "program crashed last time" error handler below. - // - sInstance = this; - - gLoggedInTime.stop(); - - processMarkerFiles(); - // - // OK to write stuff to logs now, we've now crash reported if necessary - // - - LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple()); - - // Under some circumstances we want to read the static_debug_info.log file - // from the previous viewer run between this constructor call and the - // init() call, which will overwrite the static_debug_info.log file for - // THIS run. So setDebugFileNames() early. + // Need to do this initialization before we do anything else, since anything + // that touches files should really go through the lldir API + gDirUtilp->initAppDirs("SecondLife"); + // + // IMPORTANT! Do NOT put anything that will write + // into the log files during normal startup until AFTER + // we run the "program crashed last time" error handler below. + // + sInstance = this; + + gLoggedInTime.stop(); + + processMarkerFiles(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // + + LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple()); + + // Under some circumstances we want to read the static_debug_info.log file + // from the previous viewer run between this constructor call and the + // init() call, which will overwrite the static_debug_info.log file for + // THIS run. So setDebugFileNames() early. # ifdef LL_BUGSPLAT - // MAINT-8917: don't create a dump directory just for the - // static_debug_info.log file - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + // MAINT-8917: don't create a dump directory just for the + // static_debug_info.log file + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); # else // ! LL_BUGSPLAT - // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); # endif // ! LL_BUGSPLAT - mDumpPath = logdir; + mDumpPath = logdir; - setDebugFileNames(logdir); + setDebugFileNames(logdir); } LLAppViewer::~LLAppViewer() { - delete mSettingsLocationList; + delete mSettingsLocationList; - destroyMainloopTimeout(); + destroyMainloopTimeout(); - // If we got to this destructor somehow, the app didn't hang. - removeMarkerFiles(); + // If we got to this destructor somehow, the app didn't hang. + removeMarkerFiles(); } class LLUITranslationBridge : public LLTranslationBridge { public: - virtual std::string getString(const std::string &xml_desc) - { - return LLTrans::getString(xml_desc); - } + virtual std::string getString(const std::string &xml_desc) + { + return LLTrans::getString(xml_desc); + } }; bool LLAppViewer::init() { - setupErrorHandling(mSecondInstance); + setupErrorHandling(mSecondInstance); - // - // Start of the application - // + // + // Start of the application + // // initialize the LLSettingsType translation bridge. LLTranslationBridge::ptr_t trans = std::make_shared<LLUITranslationBridge>(); LLSettingsType::initParamSingleton(trans); - // initialize SSE options - LLVector4a::initClass(); + // initialize SSE options + LLVector4a::initClass(); - //initialize particle index pool - LLVOPartGroup::initClass(); + //initialize particle index pool + LLVOPartGroup::initClass(); - // set skin search path to default, will be overridden later - // this allows simple skinned file lookups to work - gDirUtilp->setSkinFolder("default", "en"); + // set skin search path to default, will be overridden later + // this allows simple skinned file lookups to work + gDirUtilp->setSkinFolder("default", "en"); -// initLoggingAndGetLastDuration(); +// initLoggingAndGetLastDuration(); - // - // OK to write stuff to logs now, we've now crash reported if necessary - // - init_default_trans_args(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // + init_default_trans_args(); // inits from settings.xml and from strings.xml - if (!initConfiguration()) - return false; + if (!initConfiguration()) + return false; - LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; - //set the max heap size. - initMaxHeapSize() ; - LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); + //set the max heap size. + initMaxHeapSize() ; + LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); - // Although initLoggingAndGetLastDuration() is the right place to mess with - // setFatalFunction(), we can't query gSavedSettings until after - // initConfiguration(). - S32 rc(gSavedSettings.getS32("QAModeTermCode")); - if (rc >= 0) - { - // QAModeTermCode set, terminate with that rc on LL_ERRS. Use - // _exit() rather than exit() because normal cleanup depends too - // much on successful startup! - LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); - } + // Although initLoggingAndGetLastDuration() is the right place to mess with + // setFatalFunction(), we can't query gSavedSettings until after + // initConfiguration(). + S32 rc(gSavedSettings.getS32("QAModeTermCode")); + if (rc >= 0) + { + // QAModeTermCode set, terminate with that rc on LL_ERRS. Use + // _exit() rather than exit() because normal cleanup depends too + // much on successful startup! + LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); + } mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); - // Initialize the non-LLCurl libcurl library. Should be called - // before consumers (LLTextureFetch). - mAppCoreHttp.init(); + // Initialize the non-LLCurl libcurl library. Should be called + // before consumers (LLTextureFetch). + mAppCoreHttp.init(); - LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; LLMachineID::init(); - { - if (gSavedSettings.getBOOL("QAModeMetrics")) - { - app_metrics_qa_mode = true; - app_metrics_interval = METRICS_INTERVAL_QA; - } - LLViewerAssetStatsFF::init(); - } - - initThreads(); - LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; - - // Initialize settings early so that the defaults for ignorable dialogs are - // picked up and then correctly re-saved after launching the updater (STORM-1268). - LLUI::settings_map_t settings_map; - settings_map["config"] = &gSavedSettings; - settings_map["ignores"] = &gWarningSettings; - settings_map["floater"] = &gSavedSettings; // *TODO: New settings file - settings_map["account"] = &gSavedPerAccountSettings; - - LLUI::initParamSingleton(settings_map, - LLUIImageList::getInstance(), - ui_audio_callback, - deferred_ui_audio_callback); - LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; - - // NOW LLUI::getLanguage() should work. gDirUtilp must know the language - // for this session ASAP so all the file-loading commands that follow, - // that use findSkinnedFilenames(), will include the localized files. - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); - - // Setup LLTrans after LLUI::initClass has been called. - initStrings(); + { + if (gSavedSettings.getBOOL("QAModeMetrics")) + { + app_metrics_qa_mode = true; + app_metrics_interval = METRICS_INTERVAL_QA; + } + LLViewerAssetStatsFF::init(); + } + + initThreads(); + LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; + + // Initialize settings early so that the defaults for ignorable dialogs are + // picked up and then correctly re-saved after launching the updater (STORM-1268). + LLUI::settings_map_t settings_map; + settings_map["config"] = &gSavedSettings; + settings_map["ignores"] = &gWarningSettings; + settings_map["floater"] = &gSavedSettings; // *TODO: New settings file + settings_map["account"] = &gSavedPerAccountSettings; + + LLUI::initParamSingleton(settings_map, + LLUIImageList::getInstance(), + ui_audio_callback, + deferred_ui_audio_callback); + LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; + + // NOW LLUI::getLanguage() should work. gDirUtilp must know the language + // for this session ASAP so all the file-loading commands that follow, + // that use findSkinnedFilenames(), will include the localized files. + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); + + // Setup LLTrans after LLUI::initClass has been called. + initStrings(); // initialize LLWearableType translation bridge. // Will immediately use LLTranslationBridge to init LLWearableDictionary LLWearableType::initParamSingleton(trans); - // Setup notifications after LLUI::initClass() has been called. - LLNotifications::instance(); - LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; + // Setup notifications after LLUI::initClass() has been called. + LLNotifications::instance(); + LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - // *FIX: The following code isn't grouped into functions yet. + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + // *FIX: The following code isn't grouped into functions yet. - // - // Various introspection concerning the libs we're using - particularly - // the libs involved in getting to a full login screen. - // - LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; - LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; + // + // Various introspection concerning the libs we're using - particularly + // the libs involved in getting to a full login screen. + // + LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; + LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; - ///////////////////////////////////////////////// - // OS-specific login dialogs - ///////////////////////////////////////////////// + ///////////////////////////////////////////////// + // OS-specific login dialogs + ///////////////////////////////////////////////// - //test_cached_control(); + //test_cached_control(); - // track number of times that app has run - mNumSessions = gSavedSettings.getS32("NumSessions"); - mNumSessions++; - gSavedSettings.setS32("NumSessions", mNumSessions); + // track number of times that app has run + mNumSessions = gSavedSettings.getS32("NumSessions"); + mNumSessions++; + gSavedSettings.setS32("NumSessions", mNumSessions); - // LLKeyboard relies on LLUI to know what some accelerator keys are called. - LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); + // LLKeyboard relies on LLUI to know what some accelerator keys are called. + LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); - // Provide the text fields with callbacks for opening Urls - LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); - LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); - LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); - LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); + // Provide the text fields with callbacks for opening Urls + LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); + LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); + LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); + LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); - // Let code in llui access the viewer help floater - LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); + // Let code in llui access the viewer help floater + LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); - LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; + LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; - // Load translations for tooltips - LLFloater::initClass(); - LLUrlFloaterDispatchHandler::registerInDispatcher(); + // Load translations for tooltips + LLFloater::initClass(); + LLUrlFloaterDispatchHandler::registerInDispatcher(); - ///////////////////////////////////////////////// + ///////////////////////////////////////////////// - LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated + LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated - LLViewerFloaterReg::registerFloaters(); + LLViewerFloaterReg::registerFloaters(); - ///////////////////////////////////////////////// - // - // Load settings files - // - // - LLGroupMgr::parseRoleActions("role_actions.xml"); + ///////////////////////////////////////////////// + // + // Load settings files + // + // + LLGroupMgr::parseRoleActions("role_actions.xml"); - LLAgent::parseTeleportMessages("teleport_strings.xml"); + LLAgent::parseTeleportMessages("teleport_strings.xml"); - // load MIME type -> media impl mappings - std::string mime_types_name; + // load MIME type -> media impl mappings + std::string mime_types_name; #if LL_DARWIN - mime_types_name = "mime_types_mac.xml"; + mime_types_name = "mime_types_mac.xml"; #elif LL_LINUX - mime_types_name = "mime_types_linux.xml"; + mime_types_name = "mime_types_linux.xml"; #else - mime_types_name = "mime_types.xml"; + mime_types_name = "mime_types.xml"; #endif - LLMIMETypes::parseMIMETypes( mime_types_name ); - - // Copy settings to globals. *TODO: Remove or move to appropriage class initializers - settings_to_globals(); - // Setup settings listeners - settings_setup_listeners(); - // Modify settings based on system configuration and compile options - settings_modify(); - - // Find partition serial number (Windows) or hardware serial (Mac) - mSerialNumber = generateSerialNumber(); - - // do any necessary set-up for accepting incoming SLURLs from apps - initSLURLHandler(); - - if(false == initHardwareTest()) - { - // Early out from user choice. - return false; - } - LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; - - // Prepare for out-of-memory situations, during which we will crash on - // purpose and save a dump. + LLMIMETypes::parseMIMETypes( mime_types_name ); + + // Copy settings to globals. *TODO: Remove or move to appropriage class initializers + settings_to_globals(); + // Setup settings listeners + settings_setup_listeners(); + // Modify settings based on system configuration and compile options + settings_modify(); + + // Find partition serial number (Windows) or hardware serial (Mac) + mSerialNumber = generateSerialNumber(); + + // do any necessary set-up for accepting incoming SLURLs from apps + initSLURLHandler(); + + if(false == initHardwareTest()) + { + // Early out from user choice. + return false; + } + LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; + + // Prepare for out-of-memory situations, during which we will crash on + // purpose and save a dump. #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP - MemSetErrorHandler(first_mem_error_handler); + MemSetErrorHandler(first_mem_error_handler); #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP - // *Note: this is where gViewerStats used to be created. + // *Note: this is where gViewerStats used to be created. - if (!initCache()) - { - LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; - std::ostringstream msg; - msg << LLTrans::getString("MBUnableToAccessFile"); - OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); - return 0; - } - LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; + if (!initCache()) + { + LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; + std::ostringstream msg; + msg << LLTrans::getString("MBUnableToAccessFile"); + OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); + return 0; + } + LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; // Initialize event recorder LLViewerEventRecorder::createInstance(); - // - // Initialize the window - // - gGLActive = TRUE; - initWindow(); - LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; + // + // Initialize the window + // + gGLActive = TRUE; + initWindow(); + LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; // writeSystemInfo can be called after window is initialized (gViewerWindow non-null) writeSystemInfo(); - // initWindow also initializes the Feature List, so now we can initialize this global. - LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); + // initWindow also initializes the Feature List, so now we can initialize this global. + LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); - // call all self-registered classes - LLInitClassList::instance().fireCallbacks(); + // call all self-registered classes + LLInitClassList::instance().fireCallbacks(); - LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts + LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts - gGLManager.getGLInfo(gDebugInfo); - gGLManager.printGLInfoString(); + gGLManager.getGLInfo(gDebugInfo); + gGLManager.printGLInfoString(); - // If we don't have the right GL requirements, exit. - if (!gGLManager.mHasRequirements) - { + // If we don't have the right GL requirements, exit. + if (!gGLManager.mHasRequirements) + { // already handled with a MBVideoDrvErr - return 0; - } - - // Without SSE2 support we will crash almost immediately, warn here. - if (!gSysCPU.hasSSE2()) - { - // can't use an alert here since we're exiting and - // all hell breaks lose. - OSMessageBox( - LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), - LLStringUtil::null, - OSMB_OK); - return 0; - } - - // alert the user if they are using unsupported hardware - if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) - { - bool unsupported = false; - LLSD args; - std::string minSpecs; - - // get cpu data from xml - std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); - S32 minCPU = 0; - minCPUString >> minCPU; - - // get RAM data from XML - std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); - U64Bytes minRAM; - minRAMString >> minRAM; - - if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysCPU.getMHz() < minCPU) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysMemory.getPhysicalMemoryKB() < minRAM) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); - minSpecs += "\n"; - unsupported = true; - } - - if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) - { - LLNotificationsUtil::add("UnknownGPU"); - } - - if(unsupported) - { - if(!gSavedSettings.controlExists("WarnUnsupportedHardware") - || gSavedSettings.getBOOL("WarnUnsupportedHardware")) - { - args["MINSPECS"] = minSpecs; - LLNotificationsUtil::add("UnsupportedHardware", args ); - } - - } - } + return 0; + } + + // Without SSE2 support we will crash almost immediately, warn here. + if (!gSysCPU.hasSSE2()) + { + // can't use an alert here since we're exiting and + // all hell breaks lose. + OSMessageBox( + LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), + LLStringUtil::null, + OSMB_OK); + return 0; + } + + // alert the user if they are using unsupported hardware + if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) + { + bool unsupported = false; + LLSD args; + std::string minSpecs; + + // get cpu data from xml + std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); + S32 minCPU = 0; + minCPUString >> minCPU; + + // get RAM data from XML + std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); + U64Bytes minRAM; + minRAMString >> minRAM; + + if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysCPU.getMHz() < minCPU) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysMemory.getPhysicalMemoryKB() < minRAM) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); + minSpecs += "\n"; + unsupported = true; + } + + if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) + { + LLNotificationsUtil::add("UnknownGPU"); + } + + if(unsupported) + { + if(!gSavedSettings.controlExists("WarnUnsupportedHardware") + || gSavedSettings.getBOOL("WarnUnsupportedHardware")) + { + args["MINSPECS"] = minSpecs; + LLNotificationsUtil::add("UnsupportedHardware", args ); + } + + } + } #if LL_WINDOWS && ADDRESS_SIZE == 64 if (gGLManager.mIsIntel) @@ -1084,54 +1084,54 @@ bool LLAppViewer::init() // Obsolete? mExpectedGLVersion is always zero #if LL_WINDOWS - if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) - { - std::string url; - if (gGLManager.mIsIntel) - { - url = LLTrans::getString("IntelDriverPage"); - } - else if (gGLManager.mIsNVIDIA) - { - url = LLTrans::getString("NvidiaDriverPage"); - } - else if (gGLManager.mIsAMD) - { - url = LLTrans::getString("AMDDriverPage"); - } - - if (!url.empty()) - { - LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); - } - } + if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) + { + std::string url; + if (gGLManager.mIsIntel) + { + url = LLTrans::getString("IntelDriverPage"); + } + else if (gGLManager.mIsNVIDIA) + { + url = LLTrans::getString("NvidiaDriverPage"); + } + else if (gGLManager.mIsAMD) + { + url = LLTrans::getString("AMDDriverPage"); + } + + if (!url.empty()) + { + LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); + } + } #endif - // save the graphics card - gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); + // save the graphics card + gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); - // Save the current version to the prefs file - gSavedSettings.setString("LastRunVersion", - LLVersionInfo::instance().getChannelAndVersion()); + // Save the current version to the prefs file + gSavedSettings.setString("LastRunVersion", + LLVersionInfo::instance().getChannelAndVersion()); - gSimLastTime = gRenderStartTime.getElapsedTimeF32(); - gSimFrames = (F32)gFrameCount; + gSimLastTime = gRenderStartTime.getElapsedTimeF32(); + gSimFrames = (F32)gFrameCount; if (gSavedSettings.getBOOL("JoystickEnabled")) { LLViewerJoystick::getInstance()->init(false); } - try { - initializeSecHandler(); - } - catch (LLProtectedDataException&) - { - LLNotificationsUtil::add("CorruptedProtectedDataStore"); - } + try { + initializeSecHandler(); + } + catch (LLProtectedDataException&) + { + LLNotificationsUtil::add("CorruptedProtectedDataStore"); + } - gGLActive = FALSE; + gGLActive = FALSE; #if LL_RELEASE_FOR_DOWNLOAD // Skip updater if this is a non-interactive instance @@ -1230,25 +1230,25 @@ bool LLAppViewer::init() << LL_ENDL; } - LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; + LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; - //EXT-7013 - On windows for some locale (Japanese) standard - //datetime formatting functions didn't support some parameters such as "weekday". - //Names for days and months localized in xml are also useful for Polish locale(STORM-107). - std::string language = gSavedSettings.getString("Language"); - if(language == "ja" || language == "pl") - { - LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames")); - LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames")); - LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames")); - LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames")); - LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat")); - - LLStringOps::sAM = LLTrans::getString("dateTimeAM"); - LLStringOps::sPM = LLTrans::getString("dateTimePM"); - } + //EXT-7013 - On windows for some locale (Japanese) standard + //datetime formatting functions didn't support some parameters such as "weekday". + //Names for days and months localized in xml are also useful for Polish locale(STORM-107). + std::string language = gSavedSettings.getString("Language"); + if(language == "ja" || language == "pl") + { + LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames")); + LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames")); + LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames")); + LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames")); + LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat")); + + LLStringOps::sAM = LLTrans::getString("dateTimeAM"); + LLStringOps::sPM = LLTrans::getString("dateTimePM"); + } - LLAgentLanguage::init(); + LLAgentLanguage::init(); /// Tell the Coprocedure manager how to discover and store the pool sizes // what I wanted @@ -1256,27 +1256,27 @@ bool LLAppViewer::init() boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1), boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS)); - // TODO: consider moving proxy initialization here or LLCopocedureManager after proxy initialization, may be implement - // some other protection to make sure we don't use network before initializng proxy + // TODO: consider moving proxy initialization here or LLCopocedureManager after proxy initialization, may be implement + // some other protection to make sure we don't use network before initializng proxy - /*----------------------------------------------------------------------*/ - // nat 2016-06-29 moved the following here from the former mainLoop(). - mMainloopTimeout = new LLWatchdogTimeout(); + /*----------------------------------------------------------------------*/ + // nat 2016-06-29 moved the following here from the former mainLoop(). + mMainloopTimeout = new LLWatchdogTimeout(); - // Create IO Pump to use for HTTP Requests. - gServicePump = new LLPumpIO(gAPRPoolp); + // Create IO Pump to use for HTTP Requests. + gServicePump = new LLPumpIO(gAPRPoolp); - // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. - LLVoiceChannel::initClass(); - LLVoiceClient::initParamSingleton(gServicePump); - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); + LLVoiceChannel::initClass(); + LLVoiceClient::initParamSingleton(gServicePump); + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); - joystick = LLViewerJoystick::getInstance(); - joystick->setNeedsReset(true); - /*----------------------------------------------------------------------*/ - // Load User's bindings - loadKeyBindings(); + joystick = LLViewerJoystick::getInstance(); + joystick->setNeedsReset(true); + /*----------------------------------------------------------------------*/ + // Load User's bindings + loadKeyBindings(); //LLSimpleton creations LLEnvironment::createInstance(); @@ -1291,7 +1291,7 @@ bool LLAppViewer::init() } #endif - return true; + return true; } void processComposeSwitch(const std::string& option, @@ -1317,18 +1317,18 @@ void processComposeSwitch(const std::string& option, void LLAppViewer::initMaxHeapSize() { - //set the max heap size. - //here is some info regarding to the max heap size: - //------------------------------------------------------------------------------------------ - // OS | setting | SL address bits | max manageable memory space | max heap size - // Win 32 | default | 32-bit | 2GB | < 1.7GB - // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB - //Linux 32 | default | 32-bit | 3GB | < 2.7GB - //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB - //64-bit OS |default | 32-bit | 4GB | < 3.7GB - //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) - //------------------------------------------------------------------------------------------ - //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. + //set the max heap size. + //here is some info regarding to the max heap size: + //------------------------------------------------------------------------------------------ + // OS | setting | SL address bits | max manageable memory space | max heap size + // Win 32 | default | 32-bit | 2GB | < 1.7GB + // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB + //Linux 32 | default | 32-bit | 3GB | < 2.7GB + //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) + //------------------------------------------------------------------------------------------ + //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. #ifndef LL_X86_64 F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; @@ -1345,42 +1345,42 @@ LLTrace::BlockTimerStatHandle FTM_FRAME("Frame"); bool LLAppViewer::frame() { - bool ret = false; - - if (gSimulateMemLeak) - { - try - { - ret = doFrame(); - } - catch (const LLContinueError&) - { - LOG_UNHANDLED_EXCEPTION(""); - } - catch (std::bad_alloc&) - { - LLMemory::logMemoryInfo(TRUE); - LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); - if (mem_leak_instance) - { - mem_leak_instance->stop(); - } - LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL; - } - } - else - { - try - { - ret = doFrame(); - } - catch (const LLContinueError&) - { - LOG_UNHANDLED_EXCEPTION(""); - } - } - - return ret; + bool ret = false; + + if (gSimulateMemLeak) + { + try + { + ret = doFrame(); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); + } + catch (std::bad_alloc&) + { + LLMemory::logMemoryInfo(TRUE); + LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); + if (mem_leak_instance) + { + mem_leak_instance->stop(); + } + LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL; + } + } + else + { + try + { + ret = doFrame(); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); + } + } + + return ret; } bool LLAppViewer::doFrame() @@ -1473,63 +1473,63 @@ bool LLAppViewer::doFrame() } } - if (!LLApp::isExiting()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) - pingMainloopTimeout("Main:JoystickKeyboard"); - - // 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 - && (gHeadlessClient || gViewerWindow->getWindow()->getVisible()) - && gViewerWindow->getActive() - && !gViewerWindow->getWindow()->getMinimized() - && LLStartUp::getStartupState() == STATE_STARTED - && (gHeadlessClient || !gViewerWindow->getShowProgress()) - && !gFocusMgr.focusLocked()) - { + if (!LLApp::isExiting()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) + pingMainloopTimeout("Main:JoystickKeyboard"); + + // 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 + && (gHeadlessClient || gViewerWindow->getWindow()->getVisible()) + && gViewerWindow->getActive() + && !gViewerWindow->getWindow()->getMinimized() + && LLStartUp::getStartupState() == STATE_STARTED + && (gHeadlessClient || !gViewerWindow->getShowProgress()) + && !gFocusMgr.focusLocked()) + { LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); - joystick->scanJoystick(); - gKeyboard->scanKeyboard(); + joystick->scanJoystick(); + gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); - } + } - // Update state based on messages, user input, object idle. - { - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) - pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! - } + // Update state based on messages, user input, object idle. + { + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! + } - { + { LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); - idle(); - } + idle(); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) - resumeMainloopTimeout(); - } - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } + } - if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) - { - pauseMainloopTimeout(); - saveFinalSnapshot(); + if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) + { + pauseMainloopTimeout(); + saveFinalSnapshot(); if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->terminate(); } - disconnectViewer(); - resumeMainloopTimeout(); - } + disconnectViewer(); + resumeMainloopTimeout(); + } - // Render scene. - // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 + // Render scene. + // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Display"); @@ -1553,159 +1553,159 @@ bool LLAppViewer::doFrame() LLViewerStatsRecorder::instance().idle(); } } - } + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) - pingMainloopTimeout("Main:Sleep"); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pingMainloopTimeout("Main:Sleep"); - pauseMainloopTimeout(); - } + pauseMainloopTimeout(); + } - // Sleep and run background threads - { - //LL_RECORD_BLOCK_TIME(SLEEP2); - LL_PROFILE_ZONE_WARN( "Sleep2" ) + // Sleep and run background threads + { + //LL_RECORD_BLOCK_TIME(SLEEP2); + LL_PROFILE_ZONE_WARN( "Sleep2" ) - // yield some time to the os based on command line option - static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1); - if(yield_time >= 0) - { + // yield some time to the os based on command line option + static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1); + if(yield_time >= 0) + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Yield"); - LL_PROFILE_ZONE_NUM( yield_time ) - ms_sleep(yield_time); - } - - if (gNonInteractive) - { - S32 non_interactive_ms_sleep_time = 100; - LLAppViewer::getTextureCache()->pause(); - ms_sleep(non_interactive_ms_sleep_time); - } - - // yield cooperatively when not running as foreground window - // and when not quiting (causes trouble at mac's cleanup stage) - if (!LLApp::isExiting() - && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) - || !gFocusMgr.getAppHasFocus())) - { - // Sleep if we're not rendering, or the window is minimized. - static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); - S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); - // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads - // of equal priority on Windows - if (milliseconds_to_sleep > 0) - { + LL_PROFILE_ZONE_NUM( yield_time ) + ms_sleep(yield_time); + } + + if (gNonInteractive) + { + S32 non_interactive_ms_sleep_time = 100; + LLAppViewer::getTextureCache()->pause(); + ms_sleep(non_interactive_ms_sleep_time); + } + + // yield cooperatively when not running as foreground window + // and when not quiting (causes trouble at mac's cleanup stage) + if (!LLApp::isExiting() + && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) + || !gFocusMgr.getAppHasFocus())) + { + // Sleep if we're not rendering, or the window is minimized. + static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); + // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads + // of equal priority on Windows + if (milliseconds_to_sleep > 0) + { LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); - // also pause worker threads during this wait period - LLAppViewer::getTextureCache()->pause(); - } - } - - if (mRandomizeFramerate) - { - ms_sleep(rand() % 200); - } - - if (mPeriodicSlowFrame - && (gFrameCount % 10 == 0)) - { - LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; - ms_sleep(500); - } - - S32 total_work_pending = 0; - S32 total_io_pending = 0; - { - S32 work_pending = 0; - S32 io_pending = 0; - F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f); - - work_pending += updateTextureThreads(max_time); - - { + // also pause worker threads during this wait period + LLAppViewer::getTextureCache()->pause(); + } + } + + if (mRandomizeFramerate) + { + ms_sleep(rand() % 200); + } + + if (mPeriodicSlowFrame + && (gFrameCount % 10 == 0)) + { + LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; + ms_sleep(500); + } + + S32 total_work_pending = 0; + S32 total_io_pending = 0; + { + S32 work_pending = 0; + S32 io_pending = 0; + F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f); + + work_pending += updateTextureThreads(max_time); + + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("LFS Thread"); - io_pending += LLLFSThread::updateClass(1); - } - - if (io_pending > 1000) - { - ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up - } - - total_work_pending += work_pending ; - total_io_pending += io_pending ; - - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) - gMeshRepo.update() ; - } - - if(!total_work_pending) //pause texture fetching threads if nothing to process. - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) - LLAppViewer::getTextureCache()->pause(); - LLAppViewer::getTextureFetch()->pause(); - } - if(!total_io_pending) //pause file threads if nothing to process. - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) - LLLFSThread::sLocal->pause(); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) - resumeMainloopTimeout(); - } - pingMainloopTimeout("Main:End"); - } - } - - if (LLApp::isExiting()) - { - // Save snapshot for next time, if we made it through initialization - if (STATE_STARTED == LLStartUp::getStartupState()) - { - saveFinalSnapshot(); - } - - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->terminate(); - } - - delete gServicePump; - gServicePump = NULL; - - destroyMainloopTimeout(); - - LL_INFOS() << "Exiting main_loop" << LL_ENDL; - } + io_pending += LLLFSThread::updateClass(1); + } + + if (io_pending > 1000) + { + ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up + } + + total_work_pending += work_pending ; + total_io_pending += io_pending ; + + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) + gMeshRepo.update() ; + } + + if(!total_work_pending) //pause texture fetching threads if nothing to process. + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) + LLAppViewer::getTextureCache()->pause(); + LLAppViewer::getTextureFetch()->pause(); + } + if(!total_io_pending) //pause file threads if nothing to process. + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) + LLLFSThread::sLocal->pause(); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } + pingMainloopTimeout("Main:End"); + } + } + + if (LLApp::isExiting()) + { + // Save snapshot for next time, if we made it through initialization + if (STATE_STARTED == LLStartUp::getStartupState()) + { + saveFinalSnapshot(); + } + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->terminate(); + } + + delete gServicePump; + gServicePump = NULL; + + destroyMainloopTimeout(); + + LL_INFOS() << "Exiting main_loop" << LL_ENDL; + } }LLPerfStats::StatsRecorder::endFrame(); LL_PROFILER_FRAME_END - return ! LLApp::isRunning(); + return ! LLApp::isRunning(); } S32 LLAppViewer::updateTextureThreads(F32 max_time) { - S32 work_pending = 0; - { + S32 work_pending = 0; + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Texture Cache"); - work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread - } - { + work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + } + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Image Decode"); - work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread - } - { + work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + } + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Image Fetch"); - work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread - } - return work_pending; + work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + } + return work_pending; } void LLAppViewer::flushLFSIO() @@ -1730,200 +1730,200 @@ bool LLAppViewer::cleanup() { LLAtmosphere::cleanupClass(); - //ditch LLVOAvatarSelf instance - gAgentAvatarp = NULL; + //ditch LLVOAvatarSelf instance + gAgentAvatarp = NULL; LLNotifications::instance().clear(); - // workaround for DEV-35406 crash on shutdown - LLEventPumps::instance().reset(true); + // workaround for DEV-35406 crash on shutdown + LLEventPumps::instance().reset(true); - //dump scene loading monitor results - if (LLSceneMonitor::instanceExists()) - { - if (!isSecondInstance()) - { + //dump scene loading monitor results + if (LLSceneMonitor::instanceExists()) + { + if (!isSecondInstance()) + { std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv"); - LLSceneMonitor::instance().dumpToFile(dump_path); - } - LLSceneMonitor::deleteSingleton(); - } - - // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block - // here, completely redundant with the one that occurs later in this same - // function. Presumably the duplication was due to an automated merge gone - // bad. Not knowing which instance to prefer, we chose to retain the later - // one because it happens just after mFastTimerLogThread is deleted. This - // comment is in case we guessed wrong, so we can move it here instead. + LLSceneMonitor::instance().dumpToFile(dump_path); + } + LLSceneMonitor::deleteSingleton(); + } + + // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block + // here, completely redundant with the one that occurs later in this same + // function. Presumably the duplication was due to an automated merge gone + // bad. Not knowing which instance to prefer, we chose to retain the later + // one because it happens just after mFastTimerLogThread is deleted. This + // comment is in case we guessed wrong, so we can move it here instead. #if LL_LINUX - // remove any old breakpad minidump files from the log directory - if (! isError()) - { - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); - gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); - } + // remove any old breakpad minidump files from the log directory + if (! isError()) + { + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); + } #endif - // Kill off LLLeap objects. We can find them all because LLLeap is derived - // from LLInstanceTracker. - LLLeap::instance_snapshot().deleteAll(); + // Kill off LLLeap objects. We can find them all because LLLeap is derived + // from LLInstanceTracker. + LLLeap::instance_snapshot().deleteAll(); - //flag all elements as needing to be destroyed immediately - // to ensure shutdown order - LLMortician::setZealous(TRUE); + //flag all elements as needing to be destroyed immediately + // to ensure shutdown order + LLMortician::setZealous(TRUE); // Give any remaining SLPlugin instances a chance to exit cleanly. LLPluginProcessParent::shutdown(); - disconnectViewer(); - LLViewerCamera::deleteSingleton(); + disconnectViewer(); + LLViewerCamera::deleteSingleton(); + + LL_INFOS() << "Viewer disconnected" << LL_ENDL; - LL_INFOS() << "Viewer disconnected" << LL_ENDL; - - if (gKeyboard) - { - gKeyboard->resetKeys(); - } + if (gKeyboard) + { + gKeyboard->resetKeys(); + } - display_cleanup(); + display_cleanup(); - release_start_screen(); // just in case + release_start_screen(); // just in case - LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder + LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder - LL_INFOS() << "Cleaning Up" << LL_ENDL; + LL_INFOS() << "Cleaning Up" << LL_ENDL; - // shut down mesh streamer - gMeshRepo.shutdown(); + // shut down mesh streamer + gMeshRepo.shutdown(); - // shut down Havok - LLPhysicsExtensions::quitSystem(); + // shut down Havok + LLPhysicsExtensions::quitSystem(); - // Must clean up texture references before viewer window is destroyed. - if(LLHUDManager::instanceExists()) - { - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDObject::cleanupHUDObjects(); - LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; - } + // Must clean up texture references before viewer window is destroyed. + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDObject::cleanupHUDObjects(); + LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; + } - LLKeyframeDataCache::clear(); + LLKeyframeDataCache::clear(); - // End TransferManager before deleting systems it depends on (Audio, AssetStorage) + // End TransferManager before deleting systems it depends on (Audio, AssetStorage) #if 0 // this seems to get us stuck in an infinite loop... - gTransferManager.cleanup(); + gTransferManager.cleanup(); #endif - // Note: this is where gWorldMap used to be deleted. + // Note: this is where gWorldMap used to be deleted. - // Note: this is where gHUDManager used to be deleted. - if(LLHUDManager::instanceExists()) - { - LLHUDManager::getInstance()->shutdownClass(); - } + // Note: this is where gHUDManager used to be deleted. + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->shutdownClass(); + } - delete gAssetStorage; - gAssetStorage = NULL; + delete gAssetStorage; + gAssetStorage = NULL; - LLPolyMesh::freeAllMeshes(); + LLPolyMesh::freeAllMeshes(); - LLStartUp::cleanupNameCache(); + LLStartUp::cleanupNameCache(); - // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. - if (LLWorldMap::instanceExists()) - { - LLWorldMap::getInstance()->reset(); // release any images - } + if (LLWorldMap::instanceExists()) + { + LLWorldMap::getInstance()->reset(); // release any images + } - LLCalc::cleanUp(); + LLCalc::cleanUp(); - LL_INFOS() << "Global stuff deleted" << LL_ENDL; + LL_INFOS() << "Global stuff deleted" << LL_ENDL; - if (gAudiop) - { + if (gAudiop) + { LL_INFOS() << "Shutting down audio" << LL_ENDL; // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it. gAudiop->stopInternetStream(); // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); - delete sai; - gAudiop->setStreamingAudioImpl(NULL); + delete sai; + gAudiop->setStreamingAudioImpl(NULL); // shut down the audio subsystem gAudiop->shutdown(); - delete gAudiop; - gAudiop = NULL; - } - - // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. + delete gAudiop; + gAudiop = NULL; + } - // Patch up settings for next time - // Must do this before we delete the viewer window, - // such that we can suck rectangle information out of - // it. - cleanupSavedSettings(); - LL_INFOS() << "Settings patched up" << LL_ENDL; + // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. - // delete some of the files left around in the cache. - removeCacheFiles("*.wav"); - removeCacheFiles("*.tmp"); - removeCacheFiles("*.lso"); - removeCacheFiles("*.out"); - removeCacheFiles("*.dsf"); - removeCacheFiles("*.bodypart"); - removeCacheFiles("*.clothing"); + // Patch up settings for next time + // Must do this before we delete the viewer window, + // such that we can suck rectangle information out of + // it. + cleanupSavedSettings(); + LL_INFOS() << "Settings patched up" << LL_ENDL; - LL_INFOS() << "Cache files removed" << LL_ENDL; + // delete some of the files left around in the cache. + removeCacheFiles("*.wav"); + removeCacheFiles("*.tmp"); + removeCacheFiles("*.lso"); + removeCacheFiles("*.out"); + removeCacheFiles("*.dsf"); + removeCacheFiles("*.bodypart"); + removeCacheFiles("*.clothing"); - LL_INFOS() << "Shutting down Views" << LL_ENDL; + LL_INFOS() << "Cache files removed" << LL_ENDL; - // Destroy the UI - if( gViewerWindow) - gViewerWindow->shutdownViews(); + LL_INFOS() << "Shutting down Views" << LL_ENDL; - LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; + // Destroy the UI + if( gViewerWindow) + gViewerWindow->shutdownViews(); - // Cleanup Inventory after the UI since it will delete any remaining observers - // (Deleted observers should have already removed themselves) - gInventory.cleanupInventory(); + LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; - LLCoros::getInstance()->printActiveCoroutines(); + // Cleanup Inventory after the UI since it will delete any remaining observers + // (Deleted observers should have already removed themselves) + gInventory.cleanupInventory(); - LL_INFOS() << "Cleaning up Selections" << LL_ENDL; + LLCoros::getInstance()->printActiveCoroutines(); - // Clean up selection managers after UI is destroyed, as UI may be observing them. - // Clean up before GL is shut down because we might be holding on to objects with texture references - LLSelectMgr::cleanupGlobals(); + LL_INFOS() << "Cleaning up Selections" << LL_ENDL; - LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; + // Clean up selection managers after UI is destroyed, as UI may be observing them. + // Clean up before GL is shut down because we might be holding on to objects with texture references + LLSelectMgr::cleanupGlobals(); - // Shut down OpenGL - if( gViewerWindow) - { - gViewerWindow->shutdownGL(); + LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; - // Destroy window, and make sure we're not fullscreen - // This may generate window reshape and activation events. - // Therefore must do this before destroying the message system. - delete gViewerWindow; - gViewerWindow = NULL; - LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; - } + // Shut down OpenGL + if( gViewerWindow) + { + gViewerWindow->shutdownGL(); + + // Destroy window, and make sure we're not fullscreen + // This may generate window reshape and activation events. + // Therefore must do this before destroying the message system. + delete gViewerWindow; + gViewerWindow = NULL; + LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; + } LLSplashScreen::show(); LLSplashScreen::update(LLTrans::getString("ShuttingDown")); - LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; + LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; - // viewer UI relies on keyboard so keep it aound until viewer UI isa gone - delete gKeyboard; - gKeyboard = NULL; + // viewer UI relies on keyboard so keep it aound until viewer UI isa gone + delete gKeyboard; + gKeyboard = NULL; if (LLViewerJoystick::instanceExists()) { @@ -1931,280 +1931,280 @@ bool LLAppViewer::cleanup() LLViewerJoystick::getInstance()->terminate(); } - LL_INFOS() << "Cleaning up Objects" << LL_ENDL; + LL_INFOS() << "Cleaning up Objects" << LL_ENDL; - LLViewerObject::cleanupVOClasses(); + LLViewerObject::cleanupVOClasses(); - SUBSYSTEM_CLEANUP(LLAvatarAppearance); + SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLPostProcess); + SUBSYSTEM_CLEANUP(LLPostProcess); - LLTracker::cleanupInstance(); + LLTracker::cleanupInstance(); - // *FIX: This is handled in LLAppViewerWin32::cleanup(). - // I'm keeping the comment to remember its order in cleanup, - // in case of unforseen dependency. - //#if LL_WINDOWS - // gDXHardware.cleanup(); - //#endif // LL_WINDOWS + // *FIX: This is handled in LLAppViewerWin32::cleanup(). + // I'm keeping the comment to remember its order in cleanup, + // in case of unforseen dependency. + //#if LL_WINDOWS + // gDXHardware.cleanup(); + //#endif // LL_WINDOWS - LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); - if (!volume_manager->cleanup()) - { - LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; - } - LLPrimitive::cleanupVolumeManager(); + LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); + if (!volume_manager->cleanup()) + { + LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; + } + LLPrimitive::cleanupVolumeManager(); - LL_INFOS() << "Additional Cleanup..." << LL_ENDL; + LL_INFOS() << "Additional Cleanup..." << LL_ENDL; - LLViewerParcelMgr::cleanupGlobals(); + LLViewerParcelMgr::cleanupGlobals(); - // *Note: this is where gViewerStats used to be deleted. + // *Note: this is where gViewerStats used to be deleted. - //end_messaging_system(); + //end_messaging_system(); - LLPrimitive::cleanupVolumeManager(); - SUBSYSTEM_CLEANUP(LLWorldMapView); - SUBSYSTEM_CLEANUP(LLFolderViewItem); + LLPrimitive::cleanupVolumeManager(); + SUBSYSTEM_CLEANUP(LLWorldMapView); + SUBSYSTEM_CLEANUP(LLFolderViewItem); - LL_INFOS() << "Saving Data" << LL_ENDL; + LL_INFOS() << "Saving Data" << LL_ENDL; - // Store the time of our current logoff - gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + // Store the time of our current logoff + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); if (LLEnvironment::instanceExists()) { - //Store environment settings if necessary + //Store environment settings if necessary LLEnvironment::getInstance()->saveToSettings(); } - // Must do this after all panels have been deleted because panels that have persistent rects - // save their rects on delete. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - - LLUIColorTable::instance().saveUserSettings(); - - // PerAccountSettingsFile should be empty if no user has been logged on. - // *FIX:Mani This should get really saved in a "logoff" mode. - if (gSavedSettings.getString("PerAccountSettingsFile").empty()) - { - LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; - } - // Only save per account settings if the previous login succeeded, otherwise - // we might end up with a cleared out settings file in case a previous login - // failed after loading per account settings. - else if (!mSavePerAccountSettings) - { - LL_INFOS() << "Not saving per-account settings; last login was not successful." << LL_ENDL; - } - else - { - gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - LL_INFOS() << "Saved settings" << LL_ENDL; - - if (LLViewerParcelAskPlay::instanceExists()) - { - LLViewerParcelAskPlay::getInstance()->saveSettings(); - } - } - - std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); - gWarningSettings.saveToFile(warnings_settings_filename, TRUE); - - // Save URL history file - LLURLHistory::saveFile("url_history.xml"); - - // save mute list. gMuteList used to also be deleted here too. - if (gAgent.isInitialized() && LLMuteList::instanceExists()) - { - LLMuteList::getInstance()->cache(gAgent.getID()); - } - - //save call log list - if (LLConversationLog::instanceExists()) - { - LLConversationLog::instance().cache(); - } - - clearSecHandler(); + // Must do this after all panels have been deleted because panels that have persistent rects + // save their rects on delete. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - if (mPurgeCacheOnExit) - { - LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); - } - - writeDebugInfo(); - - LLLocationHistory::getInstance()->save(); - - LLAvatarIconIDCache::getInstance()->save(); - - // Stop the plugin read thread if it's running. - LLPluginProcessParent::setUseReadThread(false); - - LL_INFOS() << "Shutting down Threads" << LL_ENDL; - - // Let threads finish - LLTimer idleTimer; - idleTimer.reset(); - const F64 max_idle_time = 5.f; // 5 seconds - while(1) - { - S32 pending = 0; - pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread - pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - pending += LLLFSThread::updateClass(0); - F64 idle_time = idleTimer.getElapsedTimeF64(); - if(!pending) - { - break ; //done - } - else if(idle_time >= max_idle_time) - { - LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; - break; - } - } + LLUIColorTable::instance().saveUserSettings(); - if (mPurgeUserDataOnExit) + // PerAccountSettingsFile should be empty if no user has been logged on. + // *FIX:Mani This should get really saved in a "logoff" mode. + if (gSavedSettings.getString("PerAccountSettingsFile").empty()) { - // Ideally we should not save anything from this session since it is going to be purged now, - // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code - std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); - gDirUtilp->deleteDirAndContents(user_path); + LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; } + // Only save per account settings if the previous login succeeded, otherwise + // we might end up with a cleared out settings file in case a previous login + // failed after loading per account settings. + else if (!mSavePerAccountSettings) + { + LL_INFOS() << "Not saving per-account settings; last login was not successful." << LL_ENDL; + } + else + { + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + LL_INFOS() << "Saved settings" << LL_ENDL; - // Delete workers first - // shotdown all worker threads before deleting them in case of co-dependencies - mAppCoreHttp.requestStop(); - sTextureFetch->shutdown(); - sTextureCache->shutdown(); - sImageDecodeThread->shutdown(); - sPurgeDiskCacheThread->shutdown(); - if (mGeneralThreadPool) - { - mGeneralThreadPool->close(); - } - - sTextureFetch->shutDownTextureCacheThread() ; - LLLFSThread::sLocal->shutdown(); + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->saveSettings(); + } + } - LL_INFOS() << "Shutting down message system" << LL_ENDL; - end_messaging_system(); + std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); + gWarningSettings.saveToFile(warnings_settings_filename, TRUE); - // Non-LLCurl libcurl library - mAppCoreHttp.cleanup(); + // Save URL history file + LLURLHistory::saveFile("url_history.xml"); - SUBSYSTEM_CLEANUP(LLFilePickerThread); - SUBSYSTEM_CLEANUP(LLDirPickerThread); + // save mute list. gMuteList used to also be deleted here too. + if (gAgent.isInitialized() && LLMuteList::instanceExists()) + { + LLMuteList::getInstance()->cache(gAgent.getID()); + } - //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) - delete sTextureCache; - sTextureCache = NULL; - if (sTextureFetch) + //save call log list + if (LLConversationLog::instanceExists()) + { + LLConversationLog::instance().cache(); + } + + clearSecHandler(); + + if (mPurgeCacheOnExit) + { + LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); + } + + writeDebugInfo(); + + LLLocationHistory::getInstance()->save(); + + LLAvatarIconIDCache::getInstance()->save(); + + // Stop the plugin read thread if it's running. + LLPluginProcessParent::setUseReadThread(false); + + LL_INFOS() << "Shutting down Threads" << LL_ENDL; + + // Let threads finish + LLTimer idleTimer; + idleTimer.reset(); + const F64 max_idle_time = 5.f; // 5 seconds + while(1) + { + S32 pending = 0; + pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread + pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + pending += LLLFSThread::updateClass(0); + F64 idle_time = idleTimer.getElapsedTimeF64(); + if(!pending) + { + break ; //done + } + else if(idle_time >= max_idle_time) + { + LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; + break; + } + } + + if (mPurgeUserDataOnExit) + { + // Ideally we should not save anything from this session since it is going to be purged now, + // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); + gDirUtilp->deleteDirAndContents(user_path); + } + + // Delete workers first + // shotdown all worker threads before deleting them in case of co-dependencies + mAppCoreHttp.requestStop(); + sTextureFetch->shutdown(); + sTextureCache->shutdown(); + sImageDecodeThread->shutdown(); + sPurgeDiskCacheThread->shutdown(); + if (mGeneralThreadPool) + { + mGeneralThreadPool->close(); + } + + sTextureFetch->shutDownTextureCacheThread() ; + LLLFSThread::sLocal->shutdown(); + + LL_INFOS() << "Shutting down message system" << LL_ENDL; + end_messaging_system(); + + // Non-LLCurl libcurl library + mAppCoreHttp.cleanup(); + + SUBSYSTEM_CLEANUP(LLFilePickerThread); + SUBSYSTEM_CLEANUP(LLDirPickerThread); + + //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) + delete sTextureCache; + sTextureCache = NULL; + if (sTextureFetch) { sTextureFetch->shutdown(); sTextureFetch->waitOnPending(); delete sTextureFetch; sTextureFetch = NULL; } - delete sImageDecodeThread; + delete sImageDecodeThread; sImageDecodeThread = NULL; - delete mFastTimerLogThread; - mFastTimerLogThread = NULL; - delete sPurgeDiskCacheThread; - sPurgeDiskCacheThread = NULL; + delete mFastTimerLogThread; + mFastTimerLogThread = NULL; + delete sPurgeDiskCacheThread; + sPurgeDiskCacheThread = NULL; delete mGeneralThreadPool; mGeneralThreadPool = NULL; - if (LLFastTimerView::sAnalyzePerformance) - { - LL_INFOS() << "Analyzing performance" << LL_ENDL; + if (LLFastTimerView::sAnalyzePerformance) + { + LL_INFOS() << "Analyzing performance" << LL_ENDL; - std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; - std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; - std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; + std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; + std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; + std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); - } + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); + } - SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; + SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; - LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; + LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; - //Note: - //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() - //because some new image might be generated during cleaning up media. --bao - gTextureList.shutdown(); // shutdown again in case a callback added something - LLUIImageList::getInstance()->cleanUp(); + //Note: + //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() + //because some new image might be generated during cleaning up media. --bao + gTextureList.shutdown(); // shutdown again in case a callback added something + LLUIImageList::getInstance()->cleanUp(); - SUBSYSTEM_CLEANUP(LLImage); - SUBSYSTEM_CLEANUP(LLLFSThread); + SUBSYSTEM_CLEANUP(LLImage); + SUBSYSTEM_CLEANUP(LLLFSThread); - LL_INFOS() << "Misc Cleanup" << LL_ENDL; + LL_INFOS() << "Misc Cleanup" << LL_ENDL; - gSavedSettings.cleanup(); - LLUIColorTable::instance().clear(); + gSavedSettings.cleanup(); + LLUIColorTable::instance().clear(); - LLWatchdog::getInstance()->cleanup(); + LLWatchdog::getInstance()->cleanup(); - LLViewerAssetStatsFF::cleanup(); + LLViewerAssetStatsFF::cleanup(); - // If we're exiting to launch an URL, do that here so the screen - // is at the right resolution before we launch IE. - if (!gLaunchFileOnQuit.empty()) - { - LL_INFOS() << "Launch file on quit." << LL_ENDL; + // If we're exiting to launch an URL, do that here so the screen + // is at the right resolution before we launch IE. + if (!gLaunchFileOnQuit.empty()) + { + LL_INFOS() << "Launch file on quit." << LL_ENDL; #if LL_WINDOWS - // Indicate an application is starting. - SetCursor(LoadCursor(NULL, IDC_WAIT)); + // Indicate an application is starting. + SetCursor(LoadCursor(NULL, IDC_WAIT)); #endif - // HACK: Attempt to wait until the screen res. switch is complete. - ms_sleep(1000); + // HACK: Attempt to wait until the screen res. switch is complete. + ms_sleep(1000); - LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); - LL_INFOS() << "File launched." << LL_ENDL; - } - // make sure nothing uses applyProxySettings by this point. - LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; - SUBSYSTEM_CLEANUP(LLProxy); + LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); + LL_INFOS() << "File launched." << LL_ENDL; + } + // make sure nothing uses applyProxySettings by this point. + LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; + SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); - ll_close_fail_log(); + ll_close_fail_log(); - LLError::LLCallStacks::cleanup(); + LLError::LLCallStacks::cleanup(); - LLEnvironment::deleteSingleton(); - LLSelectMgr::deleteSingleton(); - LLViewerEventRecorder::deleteSingleton(); + LLEnvironment::deleteSingleton(); + LLSelectMgr::deleteSingleton(); + LLViewerEventRecorder::deleteSingleton(); LLWorld::deleteSingleton(); LLVoiceClient::deleteSingleton(); - // It's not at first obvious where, in this long sequence, a generic cleanup - // call OUGHT to go. So let's say this: as we migrate cleanup from - // explicit hand-placed calls into the generic mechanism, eventually - // all cleanup will get subsumed into the generic call. So the calls you - // still see above are calls that MUST happen before the generic cleanup - // kicks in. + // It's not at first obvious where, in this long sequence, a generic cleanup + // call OUGHT to go. So let's say this: as we migrate cleanup from + // explicit hand-placed calls into the generic mechanism, eventually + // all cleanup will get subsumed into the generic call. So the calls you + // still see above are calls that MUST happen before the generic cleanup + // kicks in. - // This calls every remaining LLSingleton's cleanupSingleton() and - // deleteSingleton() methods. - LLSingletonBase::deleteAll(); + // This calls every remaining LLSingleton's cleanupSingleton() and + // deleteSingleton() methods. + LLSingletonBase::deleteAll(); LLSplashScreen::hide(); LL_INFOS() << "Goodbye!" << LL_ENDL; - removeDumpDir(); + removeDumpDir(); - // return 0; - return true; + // return 0; + return true; } void LLAppViewer::initGeneralThread() @@ -2220,11 +2220,11 @@ void LLAppViewer::initGeneralThread() bool LLAppViewer::initThreads() { - static const bool enable_threads = true; + static const bool enable_threads = true; - LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); + LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); - LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo + LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo //auto configure thread count LLSD threadCounts = gSavedSettings.getLLSD("ThreadPoolSizes"); @@ -2239,39 +2239,39 @@ bool LLAppViewer::initThreads() } // The only configurable thread count right now is ImageDecode - // The viewer typically starts around 8 threads not including image decode, + // The viewer typically starts around 8 threads not including image decode, // so try to leave at least one core free S32 image_decode_count = llclamp(cores - 9, 1, 8); threadCounts["ImageDecode"] = image_decode_count; gSavedSettings.setLLSD("ThreadPoolSizes", threadCounts); - // Image decoding - LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); - LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); - LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), - enable_threads && true, - app_metrics_qa_mode); + // Image decoding + LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); + LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); + LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), + enable_threads && true, + app_metrics_qa_mode); // general task background thread (LLPerfStats, etc) LLAppViewer::instance()->initGeneralThread(); - LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); + LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); - if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) - { - LLTrace::BlockTimer::setLogLock(new LLMutex()); - mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); - mFastTimerLogThread->start(); - } + if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) + { + LLTrace::BlockTimer::setLogLock(new LLMutex()); + mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); + mFastTimerLogThread->start(); + } - // Mesh streaming and caching - gMeshRepo.init(); + // Mesh streaming and caching + gMeshRepo.init(); - LLFilePickerThread::initClass(); - LLDirPickerThread::initClass(); + LLFilePickerThread::initClass(); + LLDirPickerThread::initClass(); - // *FIX: no error handling here! - return true; + // *FIX: no error handling here! + return true; } void errorCallback(LLError::ELevel level, const std::string &error_string) @@ -2315,7 +2315,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() if (mSecondInstance) { LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); - + LLUUID uid; uid.generate(); LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); @@ -2386,123 +2386,123 @@ void LLAppViewer::initLoggingAndGetLastDuration() } bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults) + bool set_defaults) { - if (!mSettingsLocationList) - { - LL_ERRS() << "Invalid settings location list" << LL_ENDL; - } - - for (const SettingsGroup& group : mSettingsLocationList->groups) - { - // skip settings groups that aren't the one we requested - if (group.name() != location_key) continue; - - ELLPath path_index = (ELLPath)group.path_index(); - if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) - { - LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; - return false; - } - - for (const SettingsFile& file : group.files) - { - LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() - << " - from location " << location_key << LL_ENDL; - - auto settings_group = LLControlGroup::getInstance(file.name); - if(!settings_group) - { - LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; - continue; - } - - std::string full_settings_path; - - if (file.file_name_setting.isProvided() - && gSavedSettings.controlExists(file.file_name_setting)) - { - // try to find filename stored in file_name_setting control - full_settings_path = gSavedSettings.getString(file.file_name_setting); - if (full_settings_path.empty()) - { - continue; - } - else if (!gDirUtilp->fileExists(full_settings_path)) - { - // search in default path - full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path); - } - } - else - { - // by default, use specified file name - full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); - } - - if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) - { // success! - LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; - } - else - { // failed to load - if(file.required) - { + if (!mSettingsLocationList) + { + LL_ERRS() << "Invalid settings location list" << LL_ENDL; + } + + for (const SettingsGroup& group : mSettingsLocationList->groups) + { + // skip settings groups that aren't the one we requested + if (group.name() != location_key) continue; + + ELLPath path_index = (ELLPath)group.path_index(); + if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) + { + LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; + return false; + } + + for (const SettingsFile& file : group.files) + { + LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() + << " - from location " << location_key << LL_ENDL; + + auto settings_group = LLControlGroup::getInstance(file.name); + if(!settings_group) + { + LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; + continue; + } + + std::string full_settings_path; + + if (file.file_name_setting.isProvided() + && gSavedSettings.controlExists(file.file_name_setting)) + { + // try to find filename stored in file_name_setting control + full_settings_path = gSavedSettings.getString(file.file_name_setting); + if (full_settings_path.empty()) + { + continue; + } + else if (!gDirUtilp->fileExists(full_settings_path)) + { + // search in default path + full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path); + } + } + else + { + // by default, use specified file name + full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); + } + + if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) + { // success! + LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; + } + else + { // failed to load + if(file.required) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; - return false; - } - else - { - // only complain if we actually have a filename at this point - if (!full_settings_path.empty()) - { - LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; - } - } - } - } - } - - return true; + LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; + return false; + } + else + { + // only complain if we actually have a filename at this point + if (!full_settings_path.empty()) + { + LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; + } + } + } + } + } + + return true; } std::string LLAppViewer::getSettingsFilename(const std::string& location_key, - const std::string& file) + const std::string& file) { - for (const SettingsGroup& group : mSettingsLocationList->groups) - { - if (group.name() == location_key) - { - for (const SettingsFile& settings_file : group.files) - { - if (settings_file.name() == file) - { - return settings_file.file_name; - } - } - } - } - - return std::string(); + for (const SettingsGroup& group : mSettingsLocationList->groups) + { + if (group.name() == location_key) + { + for (const SettingsFile& settings_file : group.files) + { + if (settings_file.name() == file) + { + return settings_file.file_name; + } + } + } + } + + return std::string(); } void LLAppViewer::loadColorSettings() { - LLUIColorTable::instance().loadFromSettings(); + LLUIColorTable::instance().loadFromSettings(); } namespace { void handleCommandLineError(LLControlGroupCLP& clp) { - LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; + LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; - LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; + LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; - OSMessageBox(STRINGIZE(LLTrans::getString("MBCmdLineError") << clp.getErrorMessage()), - LLStringUtil::null, - OSMB_OK); + OSMessageBox(STRINGIZE(LLTrans::getString("MBCmdLineError") << clp.getErrorMessage()), + LLStringUtil::null, + OSMB_OK); } } // anonymous namespace @@ -2510,42 +2510,42 @@ namespace // Name can be specified as "<control_group>.<control_name>", with default group being Global. bool tempSetControl(const std::string& name, const std::string& value) { - std::string name_part; - std::string group_part; - LLControlVariable* control = NULL; - - // Name can be further split into ControlGroup.Name, with the default control group being Global - size_t pos = name.find('.'); - if (pos != std::string::npos) - { - group_part = name.substr(0, pos); - name_part = name.substr(pos+1); - LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; - auto g = LLControlGroup::getInstance(group_part); - if (g) control = g->getControl(name_part); - } - else - { - LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; - control = gSavedSettings.getControl(name); - } - - if (control) - { - control->setValue(value, false); - return true; - } - return false; + std::string name_part; + std::string group_part; + LLControlVariable* control = NULL; + + // Name can be further split into ControlGroup.Name, with the default control group being Global + size_t pos = name.find('.'); + if (pos != std::string::npos) + { + group_part = name.substr(0, pos); + name_part = name.substr(pos+1); + LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; + auto g = LLControlGroup::getInstance(group_part); + if (g) control = g->getControl(name_part); + } + else + { + LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; + control = gSavedSettings.getControl(name); + } + + if (control) + { + control->setValue(value, false); + return true; + } + return false; } bool LLAppViewer::initConfiguration() { - //Load settings files list - std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); - LLXMLNodePtr root; - BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL); - if (!success) - { + //Load settings files list + std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); + LLXMLNodePtr root; + BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL); + if (!success) + { LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL; LLError::LLUserWarningMsg::showMissingFiles(); if (gDirUtilp->fileExists(settings_file_list)) @@ -2562,175 +2562,175 @@ bool LLAppViewer::initConfiguration() << "and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; } - } + } - mSettingsLocationList = new SettingsFiles(); + mSettingsLocationList = new SettingsFiles(); - LLXUIParser parser; - parser.readXUI(root, *mSettingsLocationList, settings_file_list); + LLXUIParser parser; + parser.readXUI(root, *mSettingsLocationList, settings_file_list); - if (!mSettingsLocationList->validateBlock()) - { + if (!mSettingsLocationList->validateBlock()) + { LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Invalid settings file list " << settings_file_list << LL_ENDL; - } - - // The settings and command line parsing have a fragile - // order-of-operation: - // - load defaults from app_settings - // - set procedural settings values - // - read command line settings - // - selectively apply settings needed to load user settings. + } + + // The settings and command line parsing have a fragile + // order-of-operation: + // - load defaults from app_settings + // - set procedural settings values + // - read command line settings + // - selectively apply settings needed to load user settings. // - load overrides from user_settings - // - apply command line settings (to override the overrides) - // - load per account settings (happens in llstartup - - // - load defaults - bool set_defaults = true; - if(!loadSettingsFromDirectory("Default", set_defaults)) - { - OSMessageBox( - "Unable to load default settings file. The installation may be corrupted.", - LLStringUtil::null,OSMB_OK); - return false; - } - - initStrings(); // setup paths for LLTrans based on settings files only - // - set procedural settings - // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet - gSavedSettings.setString("ClientSettingsFile", + // - apply command line settings (to override the overrides) + // - load per account settings (happens in llstartup + + // - load defaults + bool set_defaults = true; + if(!loadSettingsFromDirectory("Default", set_defaults)) + { + OSMessageBox( + "Unable to load default settings file. The installation may be corrupted.", + LLStringUtil::null,OSMB_OK); + return false; + } + + initStrings(); // setup paths for LLTrans based on settings files only + // - set procedural settings + // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet + gSavedSettings.setString("ClientSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); -#ifndef LL_RELEASE_FOR_DOWNLOAD - // provide developer build only overrides for these control variables that are not - // persisted to settings.xml - LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); - if (c) - { - c->setValue(true, false); - } - - gSavedSettings.setBOOL("QAMode", TRUE ); - gSavedSettings.setS32("WatchdogEnabled", 0); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // provide developer build only overrides for these control variables that are not + // persisted to settings.xml + LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); + if (c) + { + c->setValue(true, false); + } + + gSavedSettings.setBOOL("QAMode", TRUE ); + gSavedSettings.setS32("WatchdogEnabled", 0); #endif - // These are warnings that appear on the first experience of that condition. - // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse - // for disable/reset ability -// LLFirstUse::addConfigVariable("FirstBalanceIncrease"); -// LLFirstUse::addConfigVariable("FirstBalanceDecrease"); -// LLFirstUse::addConfigVariable("FirstSit"); -// LLFirstUse::addConfigVariable("FirstMap"); -// LLFirstUse::addConfigVariable("FirstGoTo"); -// LLFirstUse::addConfigVariable("FirstBuild"); -// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); -// LLFirstUse::addConfigVariable("FirstTeleport"); -// LLFirstUse::addConfigVariable("FirstOverrideKeys"); -// LLFirstUse::addConfigVariable("FirstAttach"); -// LLFirstUse::addConfigVariable("FirstAppearance"); -// LLFirstUse::addConfigVariable("FirstInventory"); -// LLFirstUse::addConfigVariable("FirstSandbox"); -// LLFirstUse::addConfigVariable("FirstFlexible"); -// LLFirstUse::addConfigVariable("FirstDebugMenus"); -// LLFirstUse::addConfigVariable("FirstSculptedPrim"); -// LLFirstUse::addConfigVariable("FirstVoice"); -// LLFirstUse::addConfigVariable("FirstMedia"); - - // - read command line settings. - 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)) - { - handleCommandLineError(clp); - return false; - } - - // - selectively apply settings - - // If the user has specified a alternate settings file name. - // Load it now before loading the user_settings/settings.xml - if(clp.hasOption("settings")) - { - std::string user_settings_filename = - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - clp.getOption("settings")[0]); - gSavedSettings.setString("ClientSettingsFile", user_settings_filename); - LL_INFOS("Settings") << "Using command line specified settings filename: " - << user_settings_filename << LL_ENDL; - } - - // - load overrides from user_settings - loadSettingsFromDirectory("User"); - - if (gSavedSettings.getBOOL("FirstRunThisInstall")) - { - // Set firstrun flag to indicate that some further init actiona should be taken - // like determining screen DPI value and so on - mIsFirstRun = true; - - gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); - } - - if (clp.hasOption("sessionsettings")) - { - std::string session_settings_filename = clp.getOption("sessionsettings")[0]; - gSavedSettings.setString("SessionSettingsFile", session_settings_filename); - LL_INFOS("Settings") << "Using session settings filename: " - << session_settings_filename << LL_ENDL; - } - loadSettingsFromDirectory("Session"); - - if (clp.hasOption("usersessionsettings")) - { - std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0]; - gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename); - LL_INFOS("Settings") << "Using user session settings filename: " - << user_session_settings_filename << LL_ENDL; - - } - loadSettingsFromDirectory("UserSession"); - - // - apply command line settings - if (! clp.notify()) - { - handleCommandLineError(clp); - return false; - } - - // Register the core crash option as soon as we can - // if we want gdb post-mortem on cores we need to be up and running - // ASAP or we might miss init issue etc. - if(gSavedSettings.getBOOL("DisableCrashLogger")) - { - LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << LL_ENDL; - disableCrashlogger(); - } - - gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); - // Handle initialization from settings. - // Start up the debugging console before handling other options. - if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) - { - initConsole(); - } - - if(clp.hasOption("help")) - { - std::ostringstream msg; - msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; - LL_INFOS() << msg.str() << LL_ENDL; - - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - - return false; - } + // These are warnings that appear on the first experience of that condition. + // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse + // for disable/reset ability +// LLFirstUse::addConfigVariable("FirstBalanceIncrease"); +// LLFirstUse::addConfigVariable("FirstBalanceDecrease"); +// LLFirstUse::addConfigVariable("FirstSit"); +// LLFirstUse::addConfigVariable("FirstMap"); +// LLFirstUse::addConfigVariable("FirstGoTo"); +// LLFirstUse::addConfigVariable("FirstBuild"); +// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); +// LLFirstUse::addConfigVariable("FirstTeleport"); +// LLFirstUse::addConfigVariable("FirstOverrideKeys"); +// LLFirstUse::addConfigVariable("FirstAttach"); +// LLFirstUse::addConfigVariable("FirstAppearance"); +// LLFirstUse::addConfigVariable("FirstInventory"); +// LLFirstUse::addConfigVariable("FirstSandbox"); +// LLFirstUse::addConfigVariable("FirstFlexible"); +// LLFirstUse::addConfigVariable("FirstDebugMenus"); +// LLFirstUse::addConfigVariable("FirstSculptedPrim"); +// LLFirstUse::addConfigVariable("FirstVoice"); +// LLFirstUse::addConfigVariable("FirstMedia"); + + // - read command line settings. + 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)) + { + handleCommandLineError(clp); + return false; + } + + // - selectively apply settings + + // If the user has specified a alternate settings file name. + // Load it now before loading the user_settings/settings.xml + if(clp.hasOption("settings")) + { + std::string user_settings_filename = + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + clp.getOption("settings")[0]); + gSavedSettings.setString("ClientSettingsFile", user_settings_filename); + LL_INFOS("Settings") << "Using command line specified settings filename: " + << user_settings_filename << LL_ENDL; + } + + // - load overrides from user_settings + loadSettingsFromDirectory("User"); + + if (gSavedSettings.getBOOL("FirstRunThisInstall")) + { + // Set firstrun flag to indicate that some further init actiona should be taken + // like determining screen DPI value and so on + mIsFirstRun = true; + + gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); + } + + if (clp.hasOption("sessionsettings")) + { + std::string session_settings_filename = clp.getOption("sessionsettings")[0]; + gSavedSettings.setString("SessionSettingsFile", session_settings_filename); + LL_INFOS("Settings") << "Using session settings filename: " + << session_settings_filename << LL_ENDL; + } + loadSettingsFromDirectory("Session"); + + if (clp.hasOption("usersessionsettings")) + { + std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0]; + gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename); + LL_INFOS("Settings") << "Using user session settings filename: " + << user_session_settings_filename << LL_ENDL; + + } + loadSettingsFromDirectory("UserSession"); + + // - apply command line settings + if (! clp.notify()) + { + handleCommandLineError(clp); + return false; + } + + // Register the core crash option as soon as we can + // if we want gdb post-mortem on cores we need to be up and running + // ASAP or we might miss init issue etc. + if(gSavedSettings.getBOOL("DisableCrashLogger")) + { + LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << LL_ENDL; + disableCrashlogger(); + } + + gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); + // Handle initialization from settings. + // Start up the debugging console before handling other options. + if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) + { + initConsole(); + } + + if(clp.hasOption("help")) + { + std::ostringstream msg; + msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; + LL_INFOS() << msg.str() << LL_ENDL; + + OSMessageBox( + msg.str(), + LLStringUtil::null, + OSMB_OK); + + return false; + } if(clp.hasOption("set")) { @@ -2748,43 +2748,43 @@ bool LLAppViewer::initConfiguration() const std::string& value = *(++itr); if (!tempSetControl(name,value)) { - LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; + LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; } } } } if (clp.hasOption("logevents")) { - LLViewerEventRecorder::instance().setEventLoggingOn(); + LLViewerEventRecorder::instance().setEventLoggingOn(); } - std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); - if(! CmdLineChannel.empty()) + std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); + if(! CmdLineChannel.empty()) { - LLVersionInfo::instance().resetChannel(CmdLineChannel); - } + LLVersionInfo::instance().resetChannel(CmdLineChannel); + } - // If we have specified crash on startup, set the global so we'll trigger the crash at the right time - gCrashOnStartup = gSavedSettings.getBOOL("CrashOnStartup"); + // If we have specified crash on startup, set the global so we'll trigger the crash at the right time + gCrashOnStartup = gSavedSettings.getBOOL("CrashOnStartup"); - if (gSavedSettings.getBOOL("LogPerformance")) - { - LLTrace::BlockTimer::sLog = true; - LLTrace::BlockTimer::sLogName = std::string("performance"); - } + if (gSavedSettings.getBOOL("LogPerformance")) + { + LLTrace::BlockTimer::sLog = true; + LLTrace::BlockTimer::sLogName = std::string("performance"); + } - std::string test_name(gSavedSettings.getString("LogMetrics")); - if (! test_name.empty()) - { - LLTrace::BlockTimer::sMetricLog = TRUE; - // '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test - // In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...) - LL_INFOS() << "'--logmetrics' argument : " << test_name << LL_ENDL; - LLTrace::BlockTimer::sLogName = test_name; - } + std::string test_name(gSavedSettings.getString("LogMetrics")); + if (! test_name.empty()) + { + LLTrace::BlockTimer::sMetricLog = TRUE; + // '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test + // In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...) + LL_INFOS() << "'--logmetrics' argument : " << test_name << LL_ENDL; + LLTrace::BlockTimer::sLogName = test_name; + } - if (clp.hasOption("graphicslevel")) - { + if (clp.hasOption("graphicslevel")) + { // User explicitly requested --graphicslevel on the command line. We // expect this switch has already set RenderQualityPerformance. Check // that value for validity later. @@ -2793,18 +2793,18 @@ bool LLAppViewer::initConfiguration() // will call LLFeatureManager::applyRecommendedSettings(), which // overwrites this settings variable! mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance"); - } + } - LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); - gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); + LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); + gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); - if (gSavedSettings.getBOOL("DebugSession")) - { - gDebugSession = TRUE; - gDebugGL = TRUE; + if (gSavedSettings.getBOOL("DebugSession")) + { + gDebugSession = TRUE; + gDebugGL = TRUE; - ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); - } + ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); + } if (gSavedSettings.getBOOL("RenderDebugGLSession")) { @@ -2815,47 +2815,47 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setBOOL("RenderDebugGLSession", FALSE); } - const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); - if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) - { - // Examining "Language" may not suffice -- see LLUI::getLanguage() - // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much - // good because we haven't yet called LLUI::initClass(). - gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), - gSavedSettings.getString("Language")); - } - - if (gSavedSettings.getBOOL("SpellCheck")) - { - std::list<std::string> dict_list; - std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); - boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); - if (!dict_list.empty()) - { - LLSpellChecker::setUseSpellCheck(dict_list.front()); - dict_list.pop_front(); - LLSpellChecker::instance().setSecondaryDictionaries(dict_list); - } - } - - if (gNonInteractive) - { - tempSetControl("AllowMultipleViewers", "TRUE"); - tempSetControl("SLURLPassToOtherInstance", "FALSE"); - tempSetControl("RenderWater", "FALSE"); - tempSetControl("FlyingAtExit", "FALSE"); - tempSetControl("WindowWidth", "1024"); - tempSetControl("WindowHeight", "200"); - LLError::setEnabledLogTypesMask(0); - llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); - } - - - // Handle slurl use. NOTE: Don't let SL-55321 reappear. - // This initial-SLURL logic, up through the call to - // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- - // because if sendURLToOtherInstance() succeeds, we take a fast exit, - // SKIPPING the splash screen and everything else. + const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); + if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) + { + // Examining "Language" may not suffice -- see LLUI::getLanguage() + // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much + // good because we haven't yet called LLUI::initClass(). + gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), + gSavedSettings.getString("Language")); + } + + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list<std::string> dict_list; + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + } + } + + if (gNonInteractive) + { + tempSetControl("AllowMultipleViewers", "TRUE"); + tempSetControl("SLURLPassToOtherInstance", "FALSE"); + tempSetControl("RenderWater", "FALSE"); + tempSetControl("FlyingAtExit", "FALSE"); + tempSetControl("WindowWidth", "1024"); + tempSetControl("WindowHeight", "200"); + LLError::setEnabledLogTypesMask(0); + llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); + } + + + // Handle slurl use. NOTE: Don't let SL-55321 reappear. + // This initial-SLURL logic, up through the call to + // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- + // because if sendURLToOtherInstance() succeeds, we take a fast exit, + // SKIPPING the splash screen and everything else. // *FIX: This init code should be made more robust to prevent // the issue SL-55321 from returning. One thought is to allow @@ -2873,143 +2873,143 @@ bool LLAppViewer::initConfiguration() // other browsers) and do the rough equivalent of command // injection and steal passwords. Phoenix. SL-55321 - std::string starting_location; - - std::string cmd_line_login_location(gSavedSettings.getString("CmdLineLoginLocation")); - if(! cmd_line_login_location.empty()) - { - starting_location = cmd_line_login_location; - } - else - { - std::string default_login_location(gSavedSettings.getString("DefaultLoginLocation")); - if (! default_login_location.empty()) - { - starting_location = default_login_location; - } - } - - LLSLURL start_slurl; - if (! starting_location.empty()) - { - start_slurl = starting_location; - LLStartUp::setStartSLURL(start_slurl); - if(start_slurl.getType() == LLSLURL::LOCATION) - { - LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); - } - } - - // NextLoginLocation is set as a side effect of LLStartUp::setStartSLURL() - std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); - if ( !nextLoginLocation.empty() ) - { - LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL; - LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation)); - } - else if ( ( clp.hasOption("login") || clp.hasOption("autologin")) - && gSavedSettings.getString("CmdLineLoginLocation").empty()) - { - // If automatic login from command line with --login switch - // init StartSLURL location. - std::string start_slurl_setting = gSavedSettings.getString("LoginLocation"); - LL_DEBUGS("AppInit") << "start slurl setting '" << start_slurl_setting << "'" << LL_ENDL; - LLStartUp::setStartSLURL(LLSLURL(start_slurl_setting)); - } - else - { - // the login location will be set by the login panel (see LLPanelLogin) - } - - //RN: if we received a URL, hand it off to the existing instance. - // don't call anotherInstanceRunning() when doing URL handoff, as - // it relies on checking a marker file which will not work when running - // out of different directories - - if (start_slurl.isValid() && - (gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) - { - if (sendURLToOtherInstance(start_slurl.getSLURLString())) - { - // successfully handed off URL to existing instance, exit - return false; - } - } - - // Display splash screen. Must be after above check for previous - // crash as this dialog is always frontmost. - std::string splash_msg; - LLStringUtil::format_map_t args; - args["[APP_NAME]"] = LLTrans::getString("SECOND_LIFE"); - splash_msg = LLTrans::getString("StartupLoading", args); - LLSplashScreen::show(); - LLSplashScreen::update(splash_msg); - - //LLVolumeMgr::initClass(); - LLVolumeMgr* volume_manager = new LLVolumeMgr(); - volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled - LLPrimitive::setVolumeManager(volume_manager); - - // Note: this is where we used to initialize gFeatureManagerp. - - gStartTime = totalTime(); - - // - // Set the name of the window - // - gWindowTitle = LLTrans::getString("APP_NAME"); + std::string starting_location; + + std::string cmd_line_login_location(gSavedSettings.getString("CmdLineLoginLocation")); + if(! cmd_line_login_location.empty()) + { + starting_location = cmd_line_login_location; + } + else + { + std::string default_login_location(gSavedSettings.getString("DefaultLoginLocation")); + if (! default_login_location.empty()) + { + starting_location = default_login_location; + } + } + + LLSLURL start_slurl; + if (! starting_location.empty()) + { + start_slurl = starting_location; + LLStartUp::setStartSLURL(start_slurl); + if(start_slurl.getType() == LLSLURL::LOCATION) + { + LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); + } + } + + // NextLoginLocation is set as a side effect of LLStartUp::setStartSLURL() + std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); + if ( !nextLoginLocation.empty() ) + { + LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL; + LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation)); + } + else if ( ( clp.hasOption("login") || clp.hasOption("autologin")) + && gSavedSettings.getString("CmdLineLoginLocation").empty()) + { + // If automatic login from command line with --login switch + // init StartSLURL location. + std::string start_slurl_setting = gSavedSettings.getString("LoginLocation"); + LL_DEBUGS("AppInit") << "start slurl setting '" << start_slurl_setting << "'" << LL_ENDL; + LLStartUp::setStartSLURL(LLSLURL(start_slurl_setting)); + } + else + { + // the login location will be set by the login panel (see LLPanelLogin) + } + + //RN: if we received a URL, hand it off to the existing instance. + // don't call anotherInstanceRunning() when doing URL handoff, as + // it relies on checking a marker file which will not work when running + // out of different directories + + if (start_slurl.isValid() && + (gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) + { + if (sendURLToOtherInstance(start_slurl.getSLURLString())) + { + // successfully handed off URL to existing instance, exit + return false; + } + } + + // Display splash screen. Must be after above check for previous + // crash as this dialog is always frontmost. + std::string splash_msg; + LLStringUtil::format_map_t args; + args["[APP_NAME]"] = LLTrans::getString("SECOND_LIFE"); + splash_msg = LLTrans::getString("StartupLoading", args); + LLSplashScreen::show(); + LLSplashScreen::update(splash_msg); + + //LLVolumeMgr::initClass(); + LLVolumeMgr* volume_manager = new LLVolumeMgr(); + volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled + LLPrimitive::setVolumeManager(volume_manager); + + // Note: this is where we used to initialize gFeatureManagerp. + + gStartTime = totalTime(); + + // + // Set the name of the window + // + gWindowTitle = LLTrans::getString("APP_NAME"); #if LL_DEBUG - gWindowTitle += std::string(" [DEBUG]"); + gWindowTitle += std::string(" [DEBUG]"); #endif - if (!gArgs.empty()) - { - gWindowTitle += std::string(" ") + gArgs; - } - LLStringUtil::truncate(gWindowTitle, 255); - - // - // Check for another instance of the app running - // This happens AFTER LLSplashScreen::show(). That may or may not be - // important. - // - if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) - { - OSMessageBox( - LLTrans::getString("MBAlreadyRunning"), - LLStringUtil::null, - OSMB_OK); - return false; - } - - if (mSecondInstance) - { - // This is the second instance of SL. Mute voice, - // but make sure the setting is *not* persisted. - // Also see LLVivoxVoiceClient::voiceEnabled() - LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); - if(enable_voice) - { - const BOOL DO_NOT_PERSIST = FALSE; - enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); - } - } - - gLastRunVersion = gSavedSettings.getString("LastRunVersion"); - - loadColorSettings(); - - // Let anyone else who cares know that we've populated our settings - // variables. - for (const auto& key : LLControlGroup::key_snapshot()) - { - // For each named instance of LLControlGroup, send an event saying - // we've initialized an LLControlGroup instance by that name. - LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); - } + if (!gArgs.empty()) + { + gWindowTitle += std::string(" ") + gArgs; + } + LLStringUtil::truncate(gWindowTitle, 255); + + // + // Check for another instance of the app running + // This happens AFTER LLSplashScreen::show(). That may or may not be + // important. + // + if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) + { + OSMessageBox( + LLTrans::getString("MBAlreadyRunning"), + LLStringUtil::null, + OSMB_OK); + return false; + } + + if (mSecondInstance) + { + // This is the second instance of SL. Mute voice, + // but make sure the setting is *not* persisted. + // Also see LLVivoxVoiceClient::voiceEnabled() + LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); + if(enable_voice) + { + const BOOL DO_NOT_PERSIST = FALSE; + enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); + } + } + + gLastRunVersion = gSavedSettings.getString("LastRunVersion"); + + loadColorSettings(); + + // Let anyone else who cares know that we've populated our settings + // variables. + for (const auto& key : LLControlGroup::key_snapshot()) + { + // For each named instance of LLControlGroup, send an event saying + // we've initialized an LLControlGroup instance by that name. + LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); + } LLError::LLUserWarningMsg::setOutOfMemoryStrings(LLTrans::getString("MBOutOfMemoryTitle"), LLTrans::getString("MBOutOfMemoryErr")); - return true; // Config was successful. + return true; // Config was successful. } // The following logic is replicated in initConfiguration() (to be able to get @@ -3018,214 +3018,214 @@ bool LLAppViewer::initConfiguration() // keeps growing, necessitating a method all its own. void LLAppViewer::initStrings() { - std::string strings_file = "strings.xml"; - std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); - if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) - { - if (strings_path_full.empty()) - { - LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; - } - else - { - llstat st; - int rc = LLFile::stat(strings_path_full, &st); - if (rc != 0) - { - LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; - } - else if (S_ISDIR(st.st_mode)) - { - LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; - } - else - { - LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; - } - } - - // initial check to make sure files are there failed - gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); + std::string strings_file = "strings.xml"; + std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); + if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) + { + if (strings_path_full.empty()) + { + LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; + } + else + { + llstat st; + int rc = LLFile::stat(strings_path_full, &st); + if (rc != 0) + { + LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; + } + else if (S_ISDIR(st.st_mode)) + { + LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; + } + else + { + LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; + } + } + + // initial check to make sure files are there failed + gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Viewer failed to find localization and UI files." - << " Please reinstall viewer from https://secondlife.com/support/downloads" - << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; - } - LLTransUtil::parseStrings(strings_file, default_trans_args); - LLTransUtil::parseLanguageStrings("language_settings.xml"); - - // parseStrings() sets up the LLTrans substitution table. Add this one item. - LLTrans::setDefaultArg("[sourceid]", gSavedSettings.getString("sourceid")); - - // Now that we've set "[sourceid]", have to go back through - // default_trans_args and reinitialize all those other keys because some - // of them, in turn, reference "[sourceid]". - for (const std::string& key : default_trans_args) - { - std::string brackets(key), nobrackets(key); - // Invalid to inspect key[0] if key is empty(). But then, the entire - // body of this loop is pointless if key is empty(). - if (key.empty()) - continue; - - if (key[0] != '[') - { - // key was passed without brackets. That means that 'nobrackets' - // is correct but 'brackets' is not. - brackets = STRINGIZE('[' << brackets << ']'); - } - else - { - // key was passed with brackets. That means that 'brackets' is - // correct but 'nobrackets' is not. Erase the left bracket. - nobrackets.erase(0, 1); - std::string::size_type length(nobrackets.length()); - if (length && nobrackets[length - 1] == ']') - { - nobrackets.erase(length - 1); - } - } - // Calling LLTrans::getString() is what embeds the other default - // translation strings into this one. - LLTrans::setDefaultArg(brackets, LLTrans::getString(nobrackets)); - } + LL_ERRS() << "Viewer failed to find localization and UI files." + << " Please reinstall viewer from https://secondlife.com/support/downloads" + << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; + } + LLTransUtil::parseStrings(strings_file, default_trans_args); + LLTransUtil::parseLanguageStrings("language_settings.xml"); + + // parseStrings() sets up the LLTrans substitution table. Add this one item. + LLTrans::setDefaultArg("[sourceid]", gSavedSettings.getString("sourceid")); + + // Now that we've set "[sourceid]", have to go back through + // default_trans_args and reinitialize all those other keys because some + // of them, in turn, reference "[sourceid]". + for (const std::string& key : default_trans_args) + { + std::string brackets(key), nobrackets(key); + // Invalid to inspect key[0] if key is empty(). But then, the entire + // body of this loop is pointless if key is empty(). + if (key.empty()) + continue; + + if (key[0] != '[') + { + // key was passed without brackets. That means that 'nobrackets' + // is correct but 'brackets' is not. + brackets = STRINGIZE('[' << brackets << ']'); + } + else + { + // key was passed with brackets. That means that 'brackets' is + // correct but 'nobrackets' is not. Erase the left bracket. + nobrackets.erase(0, 1); + std::string::size_type length(nobrackets.length()); + if (length && nobrackets[length - 1] == ']') + { + nobrackets.erase(length - 1); + } + } + // Calling LLTrans::getString() is what embeds the other default + // translation strings into this one. + LLTrans::setDefaultArg(brackets, LLTrans::getString(nobrackets)); + } } bool LLAppViewer::meetsRequirementsForMaximizedStart() { bool maximizedOk = (gSysMemory.getPhysicalMemoryKB() >= U32Gigabytes(1)); - return maximizedOk; + return maximizedOk; } bool LLAppViewer::initWindow() { - LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; - - // store setting in a global for easy access and modification - gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); - - // always start windowed - BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); - - LLViewerWindow::Params window_params; - window_params - .title(gWindowTitle) - .name(VIEWER_WINDOW_CLASSNAME) - .x(gSavedSettings.getS32("WindowX")) - .y(gSavedSettings.getS32("WindowY")) - .width(gSavedSettings.getU32("WindowWidth")) - .height(gSavedSettings.getU32("WindowHeight")) - .min_width(gSavedSettings.getU32("MinWindowWidth")) - .min_height(gSavedSettings.getU32("MinWindowHeight")) - .fullscreen(gSavedSettings.getBOOL("FullScreen")) - .ignore_pixel_depth(ignorePixelDepth) - .first_run(mIsFirstRun); - - gViewerWindow = new LLViewerWindow(window_params); - - LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL; - - // Need to load feature table before cheking to start watchdog. - bool use_watchdog = false; - int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled"); - if (watchdog_enabled_setting == -1) - { - use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled"); - } - else - { - // The user has explicitly set this setting; always use that value. - use_watchdog = bool(watchdog_enabled_setting); - } - - LL_INFOS("AppInit") << "watchdog" - << (use_watchdog ? " " : " NOT ") - << "enabled" - << " (setting = " << watchdog_enabled_setting << ")" - << LL_ENDL; - - if (use_watchdog) - { - LLWatchdog::getInstance()->init(); - } - - LLNotificationsUI::LLNotificationManager::getInstance(); + LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; + + // store setting in a global for easy access and modification + gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); + + // always start windowed + BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); + + LLViewerWindow::Params window_params; + window_params + .title(gWindowTitle) + .name(VIEWER_WINDOW_CLASSNAME) + .x(gSavedSettings.getS32("WindowX")) + .y(gSavedSettings.getS32("WindowY")) + .width(gSavedSettings.getU32("WindowWidth")) + .height(gSavedSettings.getU32("WindowHeight")) + .min_width(gSavedSettings.getU32("MinWindowWidth")) + .min_height(gSavedSettings.getU32("MinWindowHeight")) + .fullscreen(gSavedSettings.getBOOL("FullScreen")) + .ignore_pixel_depth(ignorePixelDepth) + .first_run(mIsFirstRun); + + gViewerWindow = new LLViewerWindow(window_params); + + LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL; + + // Need to load feature table before cheking to start watchdog. + bool use_watchdog = false; + int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled"); + if (watchdog_enabled_setting == -1) + { + use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled"); + } + else + { + // The user has explicitly set this setting; always use that value. + use_watchdog = bool(watchdog_enabled_setting); + } + + LL_INFOS("AppInit") << "watchdog" + << (use_watchdog ? " " : " NOT ") + << "enabled" + << " (setting = " << watchdog_enabled_setting << ")" + << LL_ENDL; + + if (use_watchdog) + { + LLWatchdog::getInstance()->init(); + } + + LLNotificationsUI::LLNotificationManager::getInstance(); #ifdef LL_DARWIN - //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) - LLOSInfo& os_info = LLOSInfo::instance(); - if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) - { - if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) - gViewerWindow->getWindow()->setOldResize(true); - } + //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) + LLOSInfo& os_info = LLOSInfo::instance(); + if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) + { + if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) + gViewerWindow->getWindow()->setOldResize(true); + } #endif - if (gSavedSettings.getBOOL("WindowMaximized")) - { - gViewerWindow->getWindow()->maximize(); - } + if (gSavedSettings.getBOOL("WindowMaximized")) + { + gViewerWindow->getWindow()->maximize(); + } - // - // Initialize GL stuff - // + // + // Initialize GL stuff + // - if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) - { - LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false); - gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel); - } + if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) + { + LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false); + gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel); + } - // Set this flag in case we crash while initializing GL - gSavedSettings.setBOOL("RenderInitError", TRUE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); + // Set this flag in case we crash while initializing GL + gSavedSettings.setBOOL("RenderInitError", TRUE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - gPipeline.init(); - LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; + gPipeline.init(); + LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; - stop_glerror(); - gViewerWindow->initGLDefaults(); + stop_glerror(); + gViewerWindow->initGLDefaults(); - gSavedSettings.setBOOL("RenderInitError", FALSE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); + gSavedSettings.setBOOL("RenderInitError", FALSE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - //If we have a startup crash, it's usually near GL initialization, so simulate that. - if(gCrashOnStartup) - { - LLAppViewer::instance()->forceErrorLLError(); - } + //If we have a startup crash, it's usually near GL initialization, so simulate that. + if(gCrashOnStartup) + { + LLAppViewer::instance()->forceErrorLLError(); + } - // - // Determine if the window should start maximized on initial run based - // on graphics capability - // - if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart()) - { - LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL; - gSavedSettings.setBOOL("WindowMaximized", TRUE); - } + // + // Determine if the window should start maximized on initial run based + // on graphics capability + // + if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart()) + { + LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL; + gSavedSettings.setBOOL("WindowMaximized", TRUE); + } - if (gSavedSettings.getBOOL("WindowMaximized")) - { - gViewerWindow->getWindow()->maximize(); - } + if (gSavedSettings.getBOOL("WindowMaximized")) + { + gViewerWindow->getWindow()->maximize(); + } - LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); + LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); - // Show watch cursor - gViewerWindow->setCursor(UI_CURSOR_WAIT); + // Show watch cursor + gViewerWindow->setCursor(UI_CURSOR_WAIT); - // Finish view initialization - gViewerWindow->initBase(); + // Finish view initialization + gViewerWindow->initBase(); - // show viewer window - //gViewerWindow->getWindow()->show(); + // show viewer window + //gViewerWindow->getWindow()->show(); - LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; + LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; - return true; + return true; } bool LLAppViewer::isUpdaterMissing() @@ -3264,28 +3264,28 @@ void LLAppViewer::writeDebugInfo(bool isStatic) LLSD LLAppViewer::getViewerInfo() const { - // The point of having one method build an LLSD info block and the other - // construct the user-visible About string is to ensure that the same info - // is available to a getInfo() caller as to the user opening - // LLFloaterAbout. - LLSD info; - auto& versionInfo(LLVersionInfo::instance()); - // With GitHub builds, the build number is too big to fit in a 32-bit int, - // and LLSD doesn't deal with integers wider than int. Use string. - info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), - versionInfo.getPatch(), stringize(versionInfo.getBuild())); - info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); - info["CHANNEL"] = versionInfo.getChannel(); - info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = versionInfo.getBuildConfig(); - if (build_config != "Release") - { - info["BUILD_CONFIG"] = build_config; - } - - // return a URL to the release notes for this viewer, such as: - // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html - std::string url = versionInfo.getReleaseNotes(); // VVM supplied + // The point of having one method build an LLSD info block and the other + // construct the user-visible About string is to ensure that the same info + // is available to a getInfo() caller as to the user opening + // LLFloaterAbout. + LLSD info; + auto& versionInfo(LLVersionInfo::instance()); + // With GitHub builds, the build number is too big to fit in a 32-bit int, + // and LLSD doesn't deal with integers wider than int. Use string. + info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), + versionInfo.getPatch(), stringize(versionInfo.getBuild())); + info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); + info["CHANNEL"] = versionInfo.getChannel(); + info["ADDRESS_SIZE"] = ADDRESS_SIZE; + std::string build_config = versionInfo.getBuildConfig(); + if (build_config != "Release") + { + info["BUILD_CONFIG"] = build_config; + } + + // return a URL to the release notes for this viewer, such as: + // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html + std::string url = versionInfo.getReleaseNotes(); // VVM supplied if (url.empty()) { url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); @@ -3293,32 +3293,32 @@ LLSD LLAppViewer::getViewerInfo() const url += "/"; url += LLURI::escape(versionInfo.getVersion()) + ".html"; } - info["VIEWER_RELEASE_NOTES_URL"] = url; - - // Position - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - LLVector3d pos = gAgent.getPositionGlobal(); - info["POSITION"] = ll_sd_from_vector3d(pos); - info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); - - boost::regex regex("\\.(secondlife|lindenlab)\\..*"); - info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); - info["SERVER_VERSION"] = gLastVersionChannel; - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - info["SLURL"] = slurl.getSLURLString(); - } - - // CPU - info["CPU"] = gSysCPU.getCPUString(); - info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits<LLUnits::Megabytes>()); - // Moved hack adjustment to Windows memory size into llsys.cpp - info["OS_VERSION"] = LLOSInfo::instance().getOSString(); - info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); - info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); + info["VIEWER_RELEASE_NOTES_URL"] = url; + + // Position + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLVector3d pos = gAgent.getPositionGlobal(); + info["POSITION"] = ll_sd_from_vector3d(pos); + info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); + info["REGION"] = gAgent.getRegion()->getName(); + + boost::regex regex("\\.(secondlife|lindenlab)\\..*"); + info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); + info["SERVER_VERSION"] = gLastVersionChannel; + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + info["SLURL"] = slurl.getSLURLString(); + } + + // CPU + info["CPU"] = gSysCPU.getCPUString(); + info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits<LLUnits::Megabytes>()); + // Moved hack adjustment to Windows memory size into llsys.cpp + info["OS_VERSION"] = LLOSInfo::instance().getOSString(); + info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); + info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); #if LL_WINDOWS std::string drvinfo; @@ -3343,22 +3343,22 @@ LLSD LLAppViewer::getViewerInfo() const drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_ANY); } - if (!drvinfo.empty()) - { - info["GRAPHICS_DRIVER_VERSION"] = drvinfo; - } - else - { - LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; - LLSD driver_info = gDXHardware.getDisplayInfo(); - if (driver_info.has("DriverVersion")) - { - info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; - } - } + if (!drvinfo.empty()) + { + info["GRAPHICS_DRIVER_VERSION"] = drvinfo; + } + else + { + LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; + LLSD driver_info = gDXHardware.getDisplayInfo(); + if (driver_info.has("DriverVersion")) + { + info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; + } + } #endif - info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); + info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); // Settings @@ -3377,16 +3377,16 @@ LLSD LLAppViewer::getViewerInfo() const info["HIDPI"] = gHiDPISupport; #endif - // Libraries + // Libraries - info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); - bool want_fullname = true; - info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined"; - if(LLVoiceClient::getInstance()->voiceEnabled()) - { + info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); + bool want_fullname = true; + info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined"; + if(LLVoiceClient::getInstance()->voiceEnabled()) + { LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion(); const std::string build_version = version.mBuildVersion; - std::ostringstream version_string; + std::ostringstream version_string; if (std::equal(build_version.begin(), build_version.begin() + version.serverVersion.size(), version.serverVersion.begin())) { // Normal case: Show type and build version. @@ -3396,210 +3396,210 @@ LLSD LLAppViewer::getViewerInfo() const { // Mismatch: Show both versions. version_string << version.serverVersion << "/" << build_version << std::endl; } - info["VOICE_VERSION"] = version_string.str(); - } - else - { - info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); - } + info["VOICE_VERSION"] = version_string.str(); + } + else + { + info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); + } #if !LL_LINUX - std::ostringstream cef_ver_codec; - cef_ver_codec << "Dullahan: "; - cef_ver_codec << DULLAHAN_VERSION_MAJOR; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_MINOR; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_POINT; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_BUILD; - - cef_ver_codec << std::endl; - cef_ver_codec << " CEF: "; - cef_ver_codec << CEF_VERSION; - - cef_ver_codec << std::endl; - cef_ver_codec << " Chromium: "; - cef_ver_codec << CHROME_VERSION_MAJOR; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_MINOR; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_BUILD; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_PATCH; - - info["LIBCEF_VERSION"] = cef_ver_codec.str(); + std::ostringstream cef_ver_codec; + cef_ver_codec << "Dullahan: "; + cef_ver_codec << DULLAHAN_VERSION_MAJOR; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_MINOR; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_POINT; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_BUILD; + + cef_ver_codec << std::endl; + cef_ver_codec << " CEF: "; + cef_ver_codec << CEF_VERSION; + + cef_ver_codec << std::endl; + cef_ver_codec << " Chromium: "; + cef_ver_codec << CHROME_VERSION_MAJOR; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_MINOR; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_BUILD; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_PATCH; + + info["LIBCEF_VERSION"] = cef_ver_codec.str(); #else - info["LIBCEF_VERSION"] = "Undefined"; + info["LIBCEF_VERSION"] = "Undefined"; #endif #if !LL_LINUX - std::ostringstream vlc_ver_codec; - vlc_ver_codec << LIBVLC_VERSION_MAJOR; - vlc_ver_codec << "."; - vlc_ver_codec << LIBVLC_VERSION_MINOR; - vlc_ver_codec << "."; - vlc_ver_codec << LIBVLC_VERSION_REVISION; - info["LIBVLC_VERSION"] = vlc_ver_codec.str(); + std::ostringstream vlc_ver_codec; + vlc_ver_codec << LIBVLC_VERSION_MAJOR; + vlc_ver_codec << "."; + vlc_ver_codec << LIBVLC_VERSION_MINOR; + vlc_ver_codec << "."; + vlc_ver_codec << LIBVLC_VERSION_REVISION; + info["LIBVLC_VERSION"] = vlc_ver_codec.str(); #else - info["LIBVLC_VERSION"] = "Undefined"; + info["LIBVLC_VERSION"] = "Undefined"; #endif - S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); - if (packets_in > 0) - { - info["PACKETS_LOST"] = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_LOST); - info["PACKETS_IN"] = packets_in; - info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); - } - - if (mServerReleaseNotesURL.empty()) - { - if (gAgent.getRegion()) - { - info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("RetrievingData"); - } - else - { - info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("NotConnected"); - } - } - else if (LLStringUtil::startsWith(mServerReleaseNotesURL, "http")) // it's an URL - { - info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(mServerReleaseNotesURL) + " " + LLTrans::getString("ReleaseNotes") + "]"; - } - else - { - info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; - } + S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); + if (packets_in > 0) + { + info["PACKETS_LOST"] = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_LOST); + info["PACKETS_IN"] = packets_in; + info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); + } + + if (mServerReleaseNotesURL.empty()) + { + if (gAgent.getRegion()) + { + info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("RetrievingData"); + } + else + { + info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("NotConnected"); + } + } + else if (LLStringUtil::startsWith(mServerReleaseNotesURL, "http")) // it's an URL + { + info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(mServerReleaseNotesURL) + " " + LLTrans::getString("ReleaseNotes") + "]"; + } + else + { + info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; + } // populate field for new local disk cache with some details info["DISK_CACHE_INFO"] = LLDiskCache::getInstance()->getCacheInfo(); - return info; + return info; } std::string LLAppViewer::getViewerInfoString(bool default_string) const { - std::ostringstream support; - - LLSD info(getViewerInfo()); - - // Render the LLSD from getInfo() as a format_map_t - LLStringUtil::format_map_t args; - - // allow the "Release Notes" URL label to be localized - args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes", default_string); - - for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap()); - ii != iend; ++ii) - { - if (! ii->second.isArray()) - { - // Scalar value - if (ii->second.isUndefined()) - { - args[ii->first] = LLTrans::getString("none_text", default_string); - } - else - { - // don't forget to render value asString() - args[ii->first] = ii->second.asString(); - } - } - else - { - // array value: build KEY_0, KEY_1 etc. entries - for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n) - { - args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString(); - } - } - } - - // Now build the various pieces - support << LLTrans::getString("AboutHeader", args, default_string); - if (info.has("BUILD_CONFIG")) - { - support << "\n" << LLTrans::getString("BuildConfig", args, default_string); - } - if (info.has("REGION")) - { - support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); - } - support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); - support << "\n"; - if (info.has("GRAPHICS_DRIVER_VERSION")) - { - support << "\n" << LLTrans::getString("AboutDriver", args, default_string); - } - support << "\n" << LLTrans::getString("AboutOGL", args, default_string); - support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string); + std::ostringstream support; + + LLSD info(getViewerInfo()); + + // Render the LLSD from getInfo() as a format_map_t + LLStringUtil::format_map_t args; + + // allow the "Release Notes" URL label to be localized + args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes", default_string); + + for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap()); + ii != iend; ++ii) + { + if (! ii->second.isArray()) + { + // Scalar value + if (ii->second.isUndefined()) + { + args[ii->first] = LLTrans::getString("none_text", default_string); + } + else + { + // don't forget to render value asString() + args[ii->first] = ii->second.asString(); + } + } + else + { + // array value: build KEY_0, KEY_1 etc. entries + for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n) + { + args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString(); + } + } + } + + // Now build the various pieces + support << LLTrans::getString("AboutHeader", args, default_string); + if (info.has("BUILD_CONFIG")) + { + support << "\n" << LLTrans::getString("BuildConfig", args, default_string); + } + if (info.has("REGION")) + { + support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); + } + support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); + support << "\n"; + if (info.has("GRAPHICS_DRIVER_VERSION")) + { + support << "\n" << LLTrans::getString("AboutDriver", args, default_string); + } + support << "\n" << LLTrans::getString("AboutOGL", args, default_string); + support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string); #if LL_DARWIN - support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string); + support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string); #endif - support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string); - if (info.has("COMPILER")) - { - support << "\n" << LLTrans::getString("AboutCompiler", args, default_string); - } - if (info.has("PACKETS_IN")) - { - support << '\n' << LLTrans::getString("AboutTraffic", args, default_string); - } - - // SLT timestamp - LLSD substitution; - substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected(); - support << "\n" << LLTrans::getString("AboutTime", substitution, default_string); - - return support.str(); + support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string); + if (info.has("COMPILER")) + { + support << "\n" << LLTrans::getString("AboutCompiler", args, default_string); + } + if (info.has("PACKETS_IN")) + { + support << '\n' << LLTrans::getString("AboutTraffic", args, default_string); + } + + // SLT timestamp + LLSD substitution; + substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected(); + support << "\n" << LLTrans::getString("AboutTime", substitution, default_string); + + return support.str(); } void LLAppViewer::cleanupSavedSettings() { - gSavedSettings.setBOOL("MouseSun", FALSE); + gSavedSettings.setBOOL("MouseSun", FALSE); - gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator + gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator - gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); + gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); - gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); + gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); - if (gDebugView) - { - gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); - } + if (gDebugView) + { + gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); + } - // save window position if not maximized - // as we don't track it in callbacks - if(NULL != gViewerWindow) - { - BOOL maximized = gViewerWindow->getWindow()->getMaximized(); - if (!maximized) - { - LLCoordScreen window_pos; + // save window position if not maximized + // as we don't track it in callbacks + if(NULL != gViewerWindow) + { + BOOL maximized = gViewerWindow->getWindow()->getMaximized(); + if (!maximized) + { + LLCoordScreen window_pos; - if (gViewerWindow->getWindow()->getPosition(&window_pos)) - { - gSavedSettings.setS32("WindowX", window_pos.mX); - gSavedSettings.setS32("WindowY", window_pos.mY); - } - } - } + if (gViewerWindow->getWindow()->getPosition(&window_pos)) + { + gSavedSettings.setS32("WindowX", window_pos.mX); + gSavedSettings.setS32("WindowY", window_pos.mY); + } + } + } gSavedSettings.setF32("MapScale", LLWorldMapView::getScaleSetting()); - // Some things are cached in LLAgent. - if (gAgent.isInitialized()) - { - gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); - } + // Some things are cached in LLAgent. + if (gAgent.isInitialized()) + { + gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); + } } void LLAppViewer::removeCacheFiles(const std::string& file_mask) { - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask); + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask); } void LLAppViewer::writeSystemInfo() @@ -3609,96 +3609,96 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["Dynamic"] = LLSD::emptyMap(); #if LL_WINDOWS && !LL_BUGSPLAT - gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); + gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); #else //Not ideal but sufficient for good reporting. gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); //LLError::logFileName(); #endif - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); - gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); + gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); - gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); - gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString(); - gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); - gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz(); - gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); - gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); - gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); + gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString(); + gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); + gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz(); + gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); + gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); + gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); - gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); - gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); - gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); + gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); + gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); + gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); - // The user is not logged on yet, but record the current grid choice login url - // which may have been the intended grid. - gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); + // The user is not logged on yet, but record the current grid choice login url + // which may have been the intended grid. + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); - // *FIX:Mani - move this down in llappviewerwin32 + // *FIX:Mani - move this down in llappviewerwin32 #ifdef LL_WINDOWS - DWORD thread_id = GetCurrentThreadId(); - gDebugInfo["MainloopThreadID"] = (S32)thread_id; + DWORD thread_id = GetCurrentThreadId(); + gDebugInfo["MainloopThreadID"] = (S32)thread_id; #endif #ifndef LL_BUGSPLAT - // "CrashNotHandled" is set here, while things are running well, - // in case of a freeze. If there is a freeze, the crash logger will be launched - // and can read this value from the debug_info.log. - gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); + // "CrashNotHandled" is set here, while things are running well, + // in case of a freeze. If there is a freeze, the crash logger will be launched + // and can read this value from the debug_info.log. + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); #else // LL_BUGSPLAT - // "CrashNotHandled" is obsolete; it used (not very successsfully) + // "CrashNotHandled" is obsolete; it used (not very successsfully) // to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze - gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); #endif // ! LL_BUGSPLAT - // Insert crash host url (url to post crash log to) if configured. This insures - // that the crash report will go to the proper location in the case of a - // prior freeze. - std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl"); - if(crashHostUrl != "") - { - gDebugInfo["CrashHostUrl"] = crashHostUrl; - } - - // Dump some debugging info - LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; - LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; - - // Dump the local time and time zone - time_t now; - time(&now); - char tbuffer[256]; /* Flawfinder: ignore */ - strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now)); - LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL; - - // query some system information - LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL; - LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL; - LL_INFOS("SystemInfo") << "OS: " << LLOSInfo::instance().getOSStringSimple() << LL_ENDL; - LL_INFOS("SystemInfo") << "OS info: " << LLOSInfo::instance() << LL_ENDL; + // Insert crash host url (url to post crash log to) if configured. This insures + // that the crash report will go to the proper location in the case of a + // prior freeze. + std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl"); + if(crashHostUrl != "") + { + gDebugInfo["CrashHostUrl"] = crashHostUrl; + } + + // Dump some debugging info + LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; + LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; + + // Dump the local time and time zone + time_t now; + time(&now); + char tbuffer[256]; /* Flawfinder: ignore */ + strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now)); + LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL; + + // query some system information + LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL; + LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL; + LL_INFOS("SystemInfo") << "OS: " << LLOSInfo::instance().getOSStringSimple() << LL_ENDL; + LL_INFOS("SystemInfo") << "OS info: " << LLOSInfo::instance() << LL_ENDL; gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); - gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); - gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); - gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); + gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); + gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); if (gViewerWindow) { - std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); - for (auto res_iter : resolutions) - { - gDebugInfo["DisplayInfo"].append(res_iter); - } + std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); + for (auto res_iter : resolutions) + { + gDebugInfo["DisplayInfo"].append(res_iter); + } } - writeDebugInfo(); // Save out debug_info.log early, in case of crash. + writeDebugInfo(); // Save out debug_info.log early, in case of crash. } #ifdef LL_WINDOWS @@ -3710,265 +3710,265 @@ void LLAppViewer::writeSystemInfo() // TODO make this a member function. void getFileList() { - std::stringstream filenames; - - typedef std::vector<std::string> vec; - std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); - vec file_vec = gDirUtilp->getFilesInDir(pathname); - for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) - { - filenames << *iter << " "; - if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) - { - std::string fullname = pathname + *iter; - llifstream fdat( fullname.c_str(), std::ifstream::binary); - if (fdat) - { - char buf[5]; - fdat.read(buf,4); - fdat.close(); - if (!strncmp(buf,"MDMP",4)) - { - gDebugInfo["Dynamic"]["MinidumpPath"] = fullname; - break; - } - } - } - } - filenames << std::endl; - gDebugInfo["Dynamic"]["DumpDirContents"] = filenames.str(); + std::stringstream filenames; + + typedef std::vector<std::string> vec; + std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); + vec file_vec = gDirUtilp->getFilesInDir(pathname); + for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) + { + filenames << *iter << " "; + if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) + { + std::string fullname = pathname + *iter; + llifstream fdat( fullname.c_str(), std::ifstream::binary); + if (fdat) + { + char buf[5]; + fdat.read(buf,4); + fdat.close(); + if (!strncmp(buf,"MDMP",4)) + { + gDebugInfo["Dynamic"]["MinidumpPath"] = fullname; + break; + } + } + } + } + filenames << std::endl; + gDebugInfo["Dynamic"]["DumpDirContents"] = filenames.str(); } #endif // static void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) { - std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); - if ( marker_version.length() > MAX_MARKER_LENGTH ) - { - LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" - << " greater than maximum (" << MAX_MARKER_LENGTH << ")" - << ": marker matching may be incorrect" - << LL_ENDL; - } - - // record the viewer version in the marker file - marker_file.write(marker_version.data(), marker_version.length()); + std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); + if ( marker_version.length() > MAX_MARKER_LENGTH ) + { + LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" + << " greater than maximum (" << MAX_MARKER_LENGTH << ")" + << ": marker matching may be incorrect" + << LL_ENDL; + } + + // record the viewer version in the marker file + marker_file.write(marker_version.data(), marker_version.length()); } bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const { - bool sameVersion = false; - - std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); - char marker_version[MAX_MARKER_LENGTH]; - S32 marker_version_length; - - LLAPRFile marker_file; - marker_file.open(marker_name, LL_APR_RB); - if (marker_file.getFileHandle()) - { - marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); - std::string marker_string(marker_version, marker_version_length); - if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) - { - sameVersion = true; - } - LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " - << "\n mine '" << my_version << "'" - << "\n marker '" << marker_string << "'" - << "\n " << ( sameVersion ? "same" : "different" ) << " version" - << LL_ENDL; - marker_file.close(); - } - return sameVersion; + bool sameVersion = false; + + std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); + char marker_version[MAX_MARKER_LENGTH]; + S32 marker_version_length; + + LLAPRFile marker_file; + marker_file.open(marker_name, LL_APR_RB); + if (marker_file.getFileHandle()) + { + marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); + std::string marker_string(marker_version, marker_version_length); + if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) + { + sameVersion = true; + } + LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " + << "\n mine '" << my_version << "'" + << "\n marker '" << marker_string << "'" + << "\n " << ( sameVersion ? "same" : "different" ) << " version" + << LL_ENDL; + marker_file.close(); + } + return sameVersion; } void LLAppViewer::processMarkerFiles() { - //We've got 4 things to test for here - // - Other Process Running (SecondLife.exec_marker present, locked) - // - Freeze (SecondLife.exec_marker present, not locked) - // - LLError Crash (SecondLife.llerror_marker present) - // - Other Crash (SecondLife.error_marker present) - // These checks should also remove these files for the last 2 cases if they currently exist - - std::ostringstream marker_log_stream; - bool marker_is_same_version = true; - // first, look for the marker created at startup and deleted on a clean exit - mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) - { - // File exists... - // first, read it to see if it was created by the same version (we need this later) - marker_is_same_version = markerIsSameVersion(mMarkerFileName); - - // now test to see if this file is locked by a running process (try to open for write) - marker_log_stream << "Checking exec marker file for lock..."; - mMarkerFile.open(mMarkerFileName, LL_APR_WB); - apr_file_t* fMarker = mMarkerFile.getFileHandle() ; - if (!fMarker) - { - marker_log_stream << "Exec marker file open failed - assume it is locked."; - mSecondInstance = true; // lock means that instance is running. - } - else - { - // We were able to open it, now try to lock it ourselves... - if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) - { - marker_log_stream << "Locking exec marker failed."; - mSecondInstance = true; // lost a race? be conservative - } - else - { - // No other instances; we've locked this file now, so record our version; delete on quit. - recordMarkerVersion(mMarkerFile); - marker_log_stream << "Exec marker file existed but was not locked; rewritten."; - } - } - initLoggingAndGetLastDuration(); - - std::string marker_log_msg(marker_log_stream.str()); - LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; - - if (mSecondInstance) - { - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; - } - else if (marker_is_same_version) - { - // the file existed, is ours, and matched our version, so we can report on what it says - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; - gLastExecEvent = LAST_EXEC_OTHER_CRASH; - } - else - { - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; - } - } - else // marker did not exist... last exec (if any) did not freeze - { - initLoggingAndGetLastDuration(); - // Create the marker file for this execution & lock it; it will be deleted on a clean exit - apr_status_t s; - s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); - - if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) - { - LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; - if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) - { - recordMarkerVersion(mMarkerFile); - LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; - } - } - else - { - LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; - } - } - - // now check for cases in which the exec marker may have been cleaned up by crash handlers - - // check for any last exec event report based on whether or not it happened during logout - // (the logout marker is created when logout begins) - std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(logout_marker_file)) - { - gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; - LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; - } - else - { - LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(logout_marker_file); - } - // further refine based on whether or not a marker created during an llerr crash is found - std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(llerror_marker_file)) - { - if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_LLERROR_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(llerror_marker_file); - } - // and last refine based on whether or not a marker created during a non-llerr crash is found - std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(error_marker_file)) - { - if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_OTHER_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(error_marker_file); - } + //We've got 4 things to test for here + // - Other Process Running (SecondLife.exec_marker present, locked) + // - Freeze (SecondLife.exec_marker present, not locked) + // - LLError Crash (SecondLife.llerror_marker present) + // - Other Crash (SecondLife.error_marker present) + // These checks should also remove these files for the last 2 cases if they currently exist + + std::ostringstream marker_log_stream; + bool marker_is_same_version = true; + // first, look for the marker created at startup and deleted on a clean exit + mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); + if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) + { + // File exists... + // first, read it to see if it was created by the same version (we need this later) + marker_is_same_version = markerIsSameVersion(mMarkerFileName); + + // now test to see if this file is locked by a running process (try to open for write) + marker_log_stream << "Checking exec marker file for lock..."; + mMarkerFile.open(mMarkerFileName, LL_APR_WB); + apr_file_t* fMarker = mMarkerFile.getFileHandle() ; + if (!fMarker) + { + marker_log_stream << "Exec marker file open failed - assume it is locked."; + mSecondInstance = true; // lock means that instance is running. + } + else + { + // We were able to open it, now try to lock it ourselves... + if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) + { + marker_log_stream << "Locking exec marker failed."; + mSecondInstance = true; // lost a race? be conservative + } + else + { + // No other instances; we've locked this file now, so record our version; delete on quit. + recordMarkerVersion(mMarkerFile); + marker_log_stream << "Exec marker file existed but was not locked; rewritten."; + } + } + initLoggingAndGetLastDuration(); + + std::string marker_log_msg(marker_log_stream.str()); + LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; + + if (mSecondInstance) + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; + } + else if (marker_is_same_version) + { + // the file existed, is ours, and matched our version, so we can report on what it says + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + } + else + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; + } + } + else // marker did not exist... last exec (if any) did not freeze + { + initLoggingAndGetLastDuration(); + // Create the marker file for this execution & lock it; it will be deleted on a clean exit + apr_status_t s; + s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); + + if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) + { + LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; + if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) + { + recordMarkerVersion(mMarkerFile); + LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; + } + } + else + { + LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; + } + } + + // now check for cases in which the exec marker may have been cleaned up by crash handlers + + // check for any last exec event report based on whether or not it happened during logout + // (the logout marker is created when logout begins) + std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); + if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(logout_marker_file)) + { + gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; + } + else + { + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(logout_marker_file); + } + // further refine based on whether or not a marker created during an llerr crash is found + std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); + if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(llerror_marker_file)) + { + if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(llerror_marker_file); + } + // and last refine based on whether or not a marker created during a non-llerr crash is found + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(error_marker_file)) + { + if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(error_marker_file); + } } void LLAppViewer::removeMarkerFiles() { - if (!mSecondInstance) - { - if (mMarkerFile.getFileHandle()) - { - mMarkerFile.close() ; - LLAPRFile::remove( mMarkerFileName ); - LL_DEBUGS("MarkerFile") << "removed exec marker '"<<mMarkerFileName<<"'"<< LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "marker '"<<mMarkerFileName<<"' not open"<< LL_ENDL; - } - - if (mLogoutMarkerFile.getFileHandle()) - { - mLogoutMarkerFile.close(); - LLAPRFile::remove( mLogoutMarkerFileName ); - LL_DEBUGS("MarkerFile") << "removed logout marker '"<<mLogoutMarkerFileName<<"'"<< LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL; - } - } - else - { - LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; - } + if (!mSecondInstance) + { + if (mMarkerFile.getFileHandle()) + { + mMarkerFile.close() ; + LLAPRFile::remove( mMarkerFileName ); + LL_DEBUGS("MarkerFile") << "removed exec marker '"<<mMarkerFileName<<"'"<< LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "marker '"<<mMarkerFileName<<"' not open"<< LL_ENDL; + } + + if (mLogoutMarkerFile.getFileHandle()) + { + mLogoutMarkerFile.close(); + LLAPRFile::remove( mLogoutMarkerFileName ); + LL_DEBUGS("MarkerFile") << "removed logout marker '"<<mLogoutMarkerFileName<<"'"<< LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL; + } + } + else + { + LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; + } } void LLAppViewer::removeDumpDir() @@ -3991,212 +3991,212 @@ void LLAppViewer::removeDumpDir() void LLAppViewer::forceQuit() { - LLApp::setQuitting(); + LLApp::setQuitting(); } //TODO: remove void LLAppViewer::fastQuit(S32 error_code) { - // finish pending transfers - flushLFSIO(); - // let sim know we're logging out - sendLogoutRequest(); - // flush network buffers by shutting down messaging system - end_messaging_system(); - // figure out the error code - S32 final_error_code = error_code ? error_code : (S32)isError(); - // this isn't a crash - removeMarkerFiles(); - // get outta here - _exit(final_error_code); + // finish pending transfers + flushLFSIO(); + // let sim know we're logging out + sendLogoutRequest(); + // flush network buffers by shutting down messaging system + end_messaging_system(); + // figure out the error code + S32 final_error_code = error_code ? error_code : (S32)isError(); + // this isn't a crash + removeMarkerFiles(); + // get outta here + _exit(final_error_code); } void LLAppViewer::requestQuit() { - LL_INFOS() << "requestQuit" << LL_ENDL; - - LLViewerRegion* region = gAgent.getRegion(); - - if( (LLStartUp::getStartupState() < STATE_STARTED) || !region ) - { - // If we have a region, make some attempt to send a logout request first. - // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes. - if(region) - { - sendLogoutRequest(); - } - - // Quit immediately - forceQuit(); - return; - } - - // Try to send metrics back to the grid - metricsSend(!gDisconnected); - - // Try to send last batch of avatar rez metrics. - if (!gDisconnected && isAgentAvatarValid()) - { - gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent. - } - - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - effectp->markDead() ;//remove it. - - // Attempt to close all floaters that might be - // editing things. - if (gFloaterView) - { - // application is quitting - gFloaterView->closeAllChildren(true); - } - - // Send preferences once, when exiting - bool include_preferences = true; - send_viewer_stats(include_preferences); - - gLogoutTimer.reset(); - mQuitRequested = true; + LL_INFOS() << "requestQuit" << LL_ENDL; + + LLViewerRegion* region = gAgent.getRegion(); + + if( (LLStartUp::getStartupState() < STATE_STARTED) || !region ) + { + // If we have a region, make some attempt to send a logout request first. + // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes. + if(region) + { + sendLogoutRequest(); + } + + // Quit immediately + forceQuit(); + return; + } + + // Try to send metrics back to the grid + metricsSend(!gDisconnected); + + // Try to send last batch of avatar rez metrics. + if (!gDisconnected && isAgentAvatarValid()) + { + gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent. + } + + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + effectp->markDead() ;//remove it. + + // Attempt to close all floaters that might be + // editing things. + if (gFloaterView) + { + // application is quitting + gFloaterView->closeAllChildren(true); + } + + // Send preferences once, when exiting + bool include_preferences = true; + send_viewer_stats(include_preferences); + + gLogoutTimer.reset(); + mQuitRequested = true; } static bool finish_quit(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLAppViewer::instance()->requestQuit(); - } - return false; + if (option == 0) + { + LLAppViewer::instance()->requestQuit(); + } + return false; } static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit); void LLAppViewer::userQuit() { - LL_INFOS() << "User requested quit" << LL_ENDL; - if (gDisconnected - || !gViewerWindow - || !gViewerWindow->getProgressView() - || gViewerWindow->getProgressView()->getVisible()) - { - requestQuit(); - } - else - { - LLNotificationsUtil::add("ConfirmQuit"); - } + LL_INFOS() << "User requested quit" << LL_ENDL; + if (gDisconnected + || !gViewerWindow + || !gViewerWindow->getProgressView() + || gViewerWindow->getProgressView()->getVisible()) + { + requestQuit(); + } + else + { + LLNotificationsUtil::add("ConfirmQuit"); + } } static bool finish_early_exit(const LLSD& notification, const LLSD& response) { - LLAppViewer::instance()->forceQuit(); - return false; + LLAppViewer::instance()->forceQuit(); + return false; } void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) { - LL_WARNS() << "app_early_exit: " << name << LL_ENDL; - gDoDisconnect = TRUE; - LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); + LL_WARNS() << "app_early_exit: " << name << LL_ENDL; + gDoDisconnect = TRUE; + LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); } // case where we need the viewer to exit without any need for notifications void LLAppViewer::earlyExitNoNotify() { - LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL; - gDoDisconnect = TRUE; - finish_early_exit( LLSD(), LLSD() ); + LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL; + gDoDisconnect = TRUE; + finish_early_exit( LLSD(), LLSD() ); } void LLAppViewer::abortQuit() { LL_INFOS() << "abortQuit()" << LL_ENDL; - mQuitRequested = false; + mQuitRequested = false; } void LLAppViewer::migrateCacheDirectory() { #if LL_WINDOWS || LL_DARWIN - // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from - // /library/application support/SecondLife/cache This should clear/delete the old dir. - - // As of 1.23 the Windows cache moved from - // C:\Documents and Settings\James\Application Support\SecondLife\cache - // to - // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife - // - // The Windows Vista equivalent is from - // C:\Users\James\AppData\Roaming\SecondLife\cache - // to - // C:\Users\James\AppData\Local\SecondLife - // - // Note the absence of \cache on the second path. James. - - // Only do this once per fresh install of this version. - if (gSavedSettings.getBOOL("MigrateCacheDirectory")) - { - gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); - - std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); - std::string new_cache_dir = gDirUtilp->getCacheDir(true); - - if (gDirUtilp->fileExists(old_cache_dir)) - { - LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; - - // Migrate inventory cache to avoid pain to inventory database after mass update - S32 file_count = 0; - std::string file_name; - std::string mask = "*.*"; - - LLDirIterator iter(old_cache_dir, mask); - while (iter.next(file_name)) - { - if (file_name == "." || file_name == "..") continue; - std::string source_path = gDirUtilp->add(old_cache_dir, file_name); - std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); - if (!LLFile::rename(source_path, dest_path)) - { - file_count++; - } - } - LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; - - // Nuke the old cache - gDirUtilp->setCacheDir(old_cache_dir); - purgeCache(); - gDirUtilp->setCacheDir(new_cache_dir); + // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from + // /library/application support/SecondLife/cache This should clear/delete the old dir. + + // As of 1.23 the Windows cache moved from + // C:\Documents and Settings\James\Application Support\SecondLife\cache + // to + // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife + // + // The Windows Vista equivalent is from + // C:\Users\James\AppData\Roaming\SecondLife\cache + // to + // C:\Users\James\AppData\Local\SecondLife + // + // Note the absence of \cache on the second path. James. + + // Only do this once per fresh install of this version. + if (gSavedSettings.getBOOL("MigrateCacheDirectory")) + { + gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); + + std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); + std::string new_cache_dir = gDirUtilp->getCacheDir(true); + + if (gDirUtilp->fileExists(old_cache_dir)) + { + LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; + + // Migrate inventory cache to avoid pain to inventory database after mass update + S32 file_count = 0; + std::string file_name; + std::string mask = "*.*"; + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) + { + if (file_name == "." || file_name == "..") continue; + std::string source_path = gDirUtilp->add(old_cache_dir, file_name); + std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); + if (!LLFile::rename(source_path, dest_path)) + { + file_count++; + } + } + LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; + + // Nuke the old cache + gDirUtilp->setCacheDir(old_cache_dir); + purgeCache(); + gDirUtilp->setCacheDir(new_cache_dir); #if LL_DARWIN - // Clean up Mac files not deleted by removing *.* - std::string ds_store = old_cache_dir + "/.DS_Store"; - if (gDirUtilp->fileExists(ds_store)) - { - LLFile::remove(ds_store); - } + // Clean up Mac files not deleted by removing *.* + std::string ds_store = old_cache_dir + "/.DS_Store"; + if (gDirUtilp->fileExists(ds_store)) + { + LLFile::remove(ds_store); + } #endif - if (LLFile::rmdir(old_cache_dir) != 0) - { - LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; - } - } - } + if (LLFile::rmdir(old_cache_dir) != 0) + { + LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; + } + } + } #endif // LL_WINDOWS || LL_DARWIN } //static U32 LLAppViewer::getTextureCacheVersion() { - // Viewer texture cache version, change if the texture cache format changes. - // 2021-03-10 Bumping up by one to help obviate texture cache issues with - // Simple Cache Viewer - see SL-14985 for more information - //const U32 TEXTURE_CACHE_VERSION = 8; - const U32 TEXTURE_CACHE_VERSION = 9; + // Viewer texture cache version, change if the texture cache format changes. + // 2021-03-10 Bumping up by one to help obviate texture cache issues with + // Simple Cache Viewer - see SL-14985 for more information + //const U32 TEXTURE_CACHE_VERSION = 8; + const U32 TEXTURE_CACHE_VERSION = 9; - return TEXTURE_CACHE_VERSION ; + return TEXTURE_CACHE_VERSION ; } //static @@ -4211,92 +4211,92 @@ U32 LLAppViewer::getDiskCacheVersion() //static U32 LLAppViewer::getObjectCacheVersion() { - // Viewer object cache version, change if object update - // format changes. JC - const U32 INDRA_OBJECT_CACHE_VERSION = 17; + // Viewer object cache version, change if object update + // format changes. JC + const U32 INDRA_OBJECT_CACHE_VERSION = 17; - return INDRA_OBJECT_CACHE_VERSION; + return INDRA_OBJECT_CACHE_VERSION; } bool LLAppViewer::initCache() { - mPurgeCache = false; - BOOL read_only = mSecondInstance ? TRUE : FALSE; - LLAppViewer::getTextureCache()->setReadOnly(read_only) ; - LLVOCache::initParamSingleton(read_only); + mPurgeCache = false; + BOOL read_only = mSecondInstance ? TRUE : FALSE; + LLAppViewer::getTextureCache()->setReadOnly(read_only) ; + LLVOCache::initParamSingleton(read_only); - // initialize the new disk cache using saved settings - const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); + // initialize the new disk cache using saved settings + const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); - const U32 MB = 1024 * 1024; + const U32 MB = 1024 * 1024; const uintmax_t MIN_CACHE_SIZE = 256 * MB; - const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; + const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB; const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); const F64 texture_cache_percent = 100.0 - disk_cache_percent; - // note that the maximum size of this cache is defined as a percentage of the - // total cache size - the 'CacheSize' pref - for all caches. + // note that the maximum size of this cache is defined as a percentage of the + // total cache size - the 'CacheSize' pref - for all caches. const uintmax_t disk_cache_size = uintmax_t(cache_total_size * disk_cache_percent / 100); - const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); + const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); - bool texture_cache_mismatch = false; + bool texture_cache_mismatch = false; bool remove_vfs_files = false; - if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) - { - texture_cache_mismatch = true; - if(!read_only) - { - gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); + if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) + { + texture_cache_mismatch = true; + if(!read_only) + { + gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); //texture cache version was bumped up in Simple Cache Viewer, and at this point old vfs files are not needed - remove_vfs_files = true; - } - } - - if(!read_only) - { - // Purge cache if user requested it - if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || - gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) - { - LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); - mPurgeCache = true; - // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad - texture_cache_mismatch = true; - } - - // We have moved the location of the cache directory over time. - migrateCacheDirectory(); - - // Setup and verify the cache location - std::string cache_location = gSavedSettings.getString("CacheLocation"); - std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); - if (new_cache_location != cache_location) - { - LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; - gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); - purgeCache(); // purge old cache - gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); - gSavedSettings.setString("CacheLocation", new_cache_location); - gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); - } - } - - if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) - { - LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; - gSavedSettings.setString("CacheLocation", ""); - gSavedSettings.setString("CacheLocationTopFolder", ""); - } - - const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); - LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); - - if (!read_only) - { + remove_vfs_files = true; + } + } + + if(!read_only) + { + // Purge cache if user requested it + if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || + gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) + { + LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); + mPurgeCache = true; + // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad + texture_cache_mismatch = true; + } + + // We have moved the location of the cache directory over time. + migrateCacheDirectory(); + + // Setup and verify the cache location + std::string cache_location = gSavedSettings.getString("CacheLocation"); + std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); + if (new_cache_location != cache_location) + { + LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; + gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); + purgeCache(); // purge old cache + gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); + gSavedSettings.setString("CacheLocation", new_cache_location); + gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); + } + } + + if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) + { + LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; + gSavedSettings.setString("CacheLocation", ""); + gSavedSettings.setString("CacheLocationTopFolder", ""); + } + + const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); + LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); + + if (!read_only) + { if (gSavedSettings.getS32("DiskCacheVersion") != LLAppViewer::getDiskCacheVersion()) { LLDiskCache::getInstance()->clearCache(); @@ -4308,166 +4308,166 @@ bool LLAppViewer::initCache() { LLDiskCache::getInstance()->removeOldVFSFiles(); } - + if (mPurgeCache) - { - LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); - purgeCache(); - - // clear the new C++ file system based cache - LLDiskCache::getInstance()->clearCache(); - } - else - { - // purge excessive files from the new file system based cache - LLDiskCache::getInstance()->purge(); - } - } - LLAppViewer::getPurgeDiskCacheThread()->start(); - - LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); - - // Init the texture cache + { + LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); + purgeCache(); + + // clear the new C++ file system based cache + LLDiskCache::getInstance()->clearCache(); + } + else + { + // purge excessive files from the new file system based cache + LLDiskCache::getInstance()->purge(); + } + } + LLAppViewer::getPurgeDiskCacheThread()->start(); + + LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); + + // Init the texture cache // Allocate the remaining percent which is not allocated to the disk cache const S64 texture_cache_size = S64(cache_total_size * texture_cache_percent / 100); LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); - LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); + LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); return true; } void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb) { - gMainloopWork.post(cb); + gMainloopWork.post(cb); } void LLAppViewer::loadKeyBindings() { - std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); - if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) - { - // Failed to load custom bindings, try default ones - key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); - if (!gViewerInput.loadBindingsXML(key_bindings_file)) - { + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) + { + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; - } - } + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; + } + } LLUrlRegistry::instance().setKeybindingHandler(&gViewerInput); } void LLAppViewer::purgeCache() { - LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; - LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); - LLViewerShaderMgr::instance()->clearShaderCache(); - std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); - if (LLFile::isdir(browser_cache)) - { - // cef does not support clear_cache and clear_cookies, so clear what we can manually. - gDirUtilp->deleteDirAndContents(browser_cache); - } - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*"); + LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; + LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); + LLViewerShaderMgr::instance()->clearShaderCache(); + std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); + if (LLFile::isdir(browser_cache)) + { + // cef does not support clear_cache and clear_cookies, so clear what we can manually. + gDirUtilp->deleteDirAndContents(browser_cache); + } + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*"); } //purge cache immediately, do not wait until the next login. void LLAppViewer::purgeCacheImmediate() { - LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; - LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); + LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; + LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); } std::string LLAppViewer::getSecondLifeTitle() const { - return LLTrans::getString("APP_NAME"); + return LLTrans::getString("APP_NAME"); } std::string LLAppViewer::getWindowTitle() const { - return gWindowTitle; + return gWindowTitle; } // Callback from a dialog indicating user was logged out. bool finish_disconnect(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (1 == option) - { + if (1 == option) + { LLAppViewer::instance()->forceQuit(); - } - return false; + } + return false; } // Callback from an early disconnect dialog, force an exit bool finish_forced_disconnect(const LLSD& notification, const LLSD& response) { - LLAppViewer::instance()->forceQuit(); - return false; + LLAppViewer::instance()->forceQuit(); + return false; } void LLAppViewer::forceDisconnect(const std::string& mesg) { - if (gDoDisconnect) - { - // Already popped up one of these dialogs, don't - // do this again. - return; - } - - // *TODO: Translate the message if possible - std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; - if ( big_reason.size() == 0 ) - { - big_reason = mesg; - } - - LLSD args; - gDoDisconnect = TRUE; - - if (LLStartUp::getStartupState() < STATE_STARTED) - { - // Tell users what happened - args["ERROR_MESSAGE"] = big_reason; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); - } - else - { - args["MESSAGE"] = big_reason; - LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); - } + if (gDoDisconnect) + { + // Already popped up one of these dialogs, don't + // do this again. + return; + } + + // *TODO: Translate the message if possible + std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; + if ( big_reason.size() == 0 ) + { + big_reason = mesg; + } + + LLSD args; + gDoDisconnect = TRUE; + + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // Tell users what happened + args["ERROR_MESSAGE"] = big_reason; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); + } + else + { + args["MESSAGE"] = big_reason; + LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); + } } void LLAppViewer::badNetworkHandler() { - // Dump the packet - gMessageSystem->dumpPacketToLog(); - - // Flush all of our caches on exit in the case of disconnect due to - // invalid packets. - - mPurgeCacheOnExit = TRUE; - - std::ostringstream message; - message << - "The viewer has detected mangled network data indicative\n" - "of a bad upstream network connection or an incomplete\n" - "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" - " \n" - "Try uninstalling and reinstalling to see if this resolves \n" - "the issue. \n" - " \n" - "If the problem continues, see the Tech Support FAQ at: \n" - "www.secondlife.com/support"; - forceDisconnect(message.str()); - - LLApp::instance()->writeMiniDump(); + // Dump the packet + gMessageSystem->dumpPacketToLog(); + + // Flush all of our caches on exit in the case of disconnect due to + // invalid packets. + + mPurgeCacheOnExit = TRUE; + + std::ostringstream message; + message << + "The viewer has detected mangled network data indicative\n" + "of a bad upstream network connection or an incomplete\n" + "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" + " \n" + "Try uninstalling and reinstalling to see if this resolves \n" + "the issue. \n" + " \n" + "If the problem continues, see the Tech Support FAQ at: \n" + "www.secondlife.com/support"; + forceDisconnect(message.str()); + + LLApp::instance()->writeMiniDump(); } // This routine may get called more than once during the shutdown process. @@ -4475,93 +4475,93 @@ void LLAppViewer::badNetworkHandler() // is destroyed. void LLAppViewer::saveFinalSnapshot() { - if (!mSavedFinalSnapshot) - { - gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); - gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); - gViewerWindow->setCursor(UI_CURSOR_WAIT); - gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch - gSavedSettings.setBOOL("ShowParcelOwners", FALSE); - idle(); - - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenLastFilename(); - // use full pixel dimensions of viewer window (not post-scale dimensions) - gViewerWindow->saveSnapshot(snap_filename, - gViewerWindow->getWindowWidthRaw(), - gViewerWindow->getWindowHeightRaw(), - FALSE, - gSavedSettings.getBOOL("RenderHUDInSnapshot"), - TRUE, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - mSavedFinalSnapshot = TRUE; - - if (gAgent.isInHomeRegion()) - { - LLVector3d home; - if (gAgent.getHomePosGlobal(&home) && dist_vec(home, gAgent.getPositionGlobal()) < 10) - { - // We are at home position or close to it, see if we need to create home screenshot - // Notes: - // 1. It might be beneficial to also replace home if file is too old - // 2. This is far from best way/place to update screenshot since location might be not fully loaded, - // but we don't have many options - std::string snap_home = gDirUtilp->getLindenUserDir(); - snap_home += gDirUtilp->getDirDelimiter(); - snap_home += LLStartUp::getScreenHomeFilename(); - if (!gDirUtilp->fileExists(snap_home)) - { - // We are at home position yet no home image exist, fix it - LLFile::copy(snap_filename, snap_home); - } - } - } - } + if (!mSavedFinalSnapshot) + { + gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); + gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); + gViewerWindow->setCursor(UI_CURSOR_WAIT); + gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch + gSavedSettings.setBOOL("ShowParcelOwners", FALSE); + idle(); + + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenLastFilename(); + // use full pixel dimensions of viewer window (not post-scale dimensions) + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + TRUE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + mSavedFinalSnapshot = TRUE; + + if (gAgent.isInHomeRegion()) + { + LLVector3d home; + if (gAgent.getHomePosGlobal(&home) && dist_vec(home, gAgent.getPositionGlobal()) < 10) + { + // We are at home position or close to it, see if we need to create home screenshot + // Notes: + // 1. It might be beneficial to also replace home if file is too old + // 2. This is far from best way/place to update screenshot since location might be not fully loaded, + // but we don't have many options + std::string snap_home = gDirUtilp->getLindenUserDir(); + snap_home += gDirUtilp->getDirDelimiter(); + snap_home += LLStartUp::getScreenHomeFilename(); + if (!gDirUtilp->fileExists(snap_home)) + { + // We are at home position yet no home image exist, fix it + LLFile::copy(snap_filename, snap_home); + } + } + } + } } void LLAppViewer::loadNameCache() { - // display names cache - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - LL_INFOS("AvNameCache") << filename << LL_ENDL; - llifstream name_cache_stream(filename.c_str()); - if(name_cache_stream.is_open()) - { - if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) + // display names cache + std::string filename = + gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + LL_INFOS("AvNameCache") << filename << LL_ENDL; + llifstream name_cache_stream(filename.c_str()); + if(name_cache_stream.is_open()) + { + if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) { LL_WARNS("AppInit") << "removing invalid '" << filename << "'" << LL_ENDL; name_cache_stream.close(); LLFile::remove(filename); } - } + } - if (!gCacheName) return; + if (!gCacheName) return; - std::string name_cache; - name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); - llifstream cache_file(name_cache.c_str()); - if(cache_file.is_open()) - { - if(gCacheName->importFile(cache_file)) return; - } + std::string name_cache; + name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); + llifstream cache_file(name_cache.c_str()); + if(cache_file.is_open()) + { + if(gCacheName->importFile(cache_file)) return; + } } void LLAppViewer::saveNameCache() { - // display names cache - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - llofstream name_cache_stream(filename.c_str()); - if(name_cache_stream.is_open()) - { - LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); + // display names cache + std::string filename = + gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + llofstream name_cache_stream(filename.c_str()); + if(name_cache_stream.is_open()) + { + LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); } // real names cache - if (gCacheName) + if (gCacheName) { std::string name_cache; name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); @@ -4570,24 +4570,24 @@ void LLAppViewer::saveNameCache() { gCacheName->exportFile(cache_file); } - } + } } -/*! @brief This class is an LLFrameTimer that can be created with - an elapsed time that starts counting up from the given value - rather than 0.0. +/*! @brief This class is an LLFrameTimer that can be created with + an elapsed time that starts counting up from the given value + rather than 0.0. - Otherwise it behaves the same way as LLFrameTimer. + Otherwise it behaves the same way as LLFrameTimer. */ class LLFrameStatsTimer : public LLFrameTimer { public: - LLFrameStatsTimer(F64 elapsed_already = 0.0) - : LLFrameTimer() - { - mStartTime -= elapsed_already; - } + LLFrameStatsTimer(F64 elapsed_already = 0.0) + : LLFrameTimer() + { + mStartTime -= elapsed_already; + } }; static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio"); @@ -4613,118 +4613,118 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); void LLAppViewer::idle() { LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - pingMainloopTimeout("Main:Idle"); + pingMainloopTimeout("Main:Idle"); - // Update frame timers - static LLTimer idle_timer; + // Update frame timers + static LLTimer idle_timer; - LLFrameTimer::updateFrameTime(); - LLFrameTimer::updateFrameCount(); - LLEventTimer::updateClass(); + LLFrameTimer::updateFrameTime(); + LLFrameTimer::updateFrameCount(); + LLEventTimer::updateClass(); LLPerfStats::updateClass(); - // LLApp::stepFrame() performs the above three calls plus mRunner.run(). - // Not sure why we don't call stepFrame() here, except that LLRunner seems - // completely redundant with LLEventTimer. - LLNotificationsUI::LLToast::updateClass(); - LLSmoothInterpolation::updateInterpolants(); - LLMortician::updateClass(); - LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() - LLDirPickerThread::clearDead(); - F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); + // LLApp::stepFrame() performs the above three calls plus mRunner.run(). + // Not sure why we don't call stepFrame() here, except that LLRunner seems + // completely redundant with LLEventTimer. + LLNotificationsUI::LLToast::updateClass(); + LLSmoothInterpolation::updateInterpolants(); + LLMortician::updateClass(); + LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() + LLDirPickerThread::clearDead(); + F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); LLGLTFMaterialList::flushUpdates(); - // Service the WorkQueue we use for replies from worker threads. - // Use function statics for the timeslice setting so we only have to fetch - // and convert MainWorkTime once. - static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); - static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); - // MainWorkTime is specified in fractional milliseconds, but std::chrono - // uses integer representations. What if we want less than a microsecond? - // Use nanoseconds. We're very sure we will never need to specify a - // MainWorkTime that would be larger than we could express in - // std::chrono::nanoseconds. - static std::chrono::nanoseconds MainWorkTimeNanoSec{ - std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; - gMainloopWork.runFor(MainWorkTimeNanoSec); - - // Cap out-of-control frame times - // Too low because in menus, swapping, debugger, etc. - // Too high because idle called with no objects in view, etc. - const F32 MIN_FRAME_RATE = 1.f; - const F32 MAX_FRAME_RATE = 200.f; - - F32 frame_rate_clamped = 1.f / dt_raw; - frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); - gFrameDTClamped = 1.f / frame_rate_clamped; - - // Global frame timer - // Smoothly weight toward current frame - gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; - - F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); - if (qas > 0.f) - { - if (gRenderStartTime.getElapsedTimeF32() > qas) - { - LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; - LLAppViewer::instance()->forceQuit(); - } - } - - // Must wait until both have avatar object and mute list, so poll - // here. - LLIMProcessing::requestOfflineMessages(); - - /////////////////////////////////// - // - // Special case idle if still starting up - // - if (LLStartUp::getStartupState() < STATE_STARTED) - { - // Skip rest if idle startup returns false (essentially, no world yet) - gGLActive = TRUE; - if (!idle_startup()) - { - gGLActive = FALSE; - return; - } - gGLActive = FALSE; - } - - - F32 yaw = 0.f; // radians - - if (!gDisconnected) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); - // Update spaceserver timeinfo - LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); - - - ////////////////////////////////////// - // - // Update simulator agent state - // - - if (gSavedSettings.getBOOL("RotateRight")) - { - gAgent.moveYaw(-1.f); - } - - { + // Service the WorkQueue we use for replies from worker threads. + // Use function statics for the timeslice setting so we only have to fetch + // and convert MainWorkTime once. + static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); + static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); + // MainWorkTime is specified in fractional milliseconds, but std::chrono + // uses integer representations. What if we want less than a microsecond? + // Use nanoseconds. We're very sure we will never need to specify a + // MainWorkTime that would be larger than we could express in + // std::chrono::nanoseconds. + static std::chrono::nanoseconds MainWorkTimeNanoSec{ + std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; + gMainloopWork.runFor(MainWorkTimeNanoSec); + + // Cap out-of-control frame times + // Too low because in menus, swapping, debugger, etc. + // Too high because idle called with no objects in view, etc. + const F32 MIN_FRAME_RATE = 1.f; + const F32 MAX_FRAME_RATE = 200.f; + + F32 frame_rate_clamped = 1.f / dt_raw; + frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); + gFrameDTClamped = 1.f / frame_rate_clamped; + + // Global frame timer + // Smoothly weight toward current frame + gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; + + F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); + if (qas > 0.f) + { + if (gRenderStartTime.getElapsedTimeF32() > qas) + { + LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; + LLAppViewer::instance()->forceQuit(); + } + } + + // Must wait until both have avatar object and mute list, so poll + // here. + LLIMProcessing::requestOfflineMessages(); + + /////////////////////////////////// + // + // Special case idle if still starting up + // + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // Skip rest if idle startup returns false (essentially, no world yet) + gGLActive = TRUE; + if (!idle_startup()) + { + gGLActive = FALSE; + return; + } + gGLActive = FALSE; + } + + + F32 yaw = 0.f; // radians + + if (!gDisconnected) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); + // Update spaceserver timeinfo + LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); + + + ////////////////////////////////////// + // + // Update simulator agent state + // + + if (gSavedSettings.getBOOL("RotateRight")) + { + gAgent.moveYaw(-1.f); + } + + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Autopilot"); - // Handle automatic walking towards points - gAgentPilot.updateTarget(); - gAgent.autoPilot(&yaw); - } + // Handle automatic walking towards points + gAgentPilot.updateTarget(); + gAgent.autoPilot(&yaw); + } - static LLFrameTimer agent_update_timer; + static LLFrameTimer agent_update_timer; - // When appropriate, update agent location to the simulator. - F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); - F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; + // When appropriate, update agent location to the simulator. + F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); + F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; bool timed_out = agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND); BOOL force_send = // if there is something to send @@ -4735,111 +4735,111 @@ void LLAppViewer::idle() || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND)); // timing out doesn't warranty that an update will be sent, // just that it will be checked. - if (force_send || timed_out) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // Send avatar and camera info - mLastAgentControlFlags = gAgent.getControlFlags(); - mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; - send_agent_update(force_send); - agent_update_timer.reset(); - } - } - - ////////////////////////////////////// - // - // Manage statistics - // - // - { - // Initialize the viewer_stats_timer with an already elapsed time - // of SEND_STATS_PERIOD so that the initial stats report will - // be sent immediately. - static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); - - // Update session stats every large chunk of time - // *FIX: (?) SAMANTHA - if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) - { - LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; - bool include_preferences = false; - send_viewer_stats(include_preferences); - viewer_stats_timer.reset(); - } - - // Print the object debugging stats - static LLFrameTimer object_debug_timer; - if (object_debug_timer.getElapsedTimeF32() > 5.f) - { - object_debug_timer.reset(); - if (gObjectList.mNumDeadObjectUpdates) - { - LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; - gObjectList.mNumDeadObjectUpdates = 0; - } - if (gObjectList.mNumUnknownUpdates) - { - LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; - gObjectList.mNumUnknownUpdates = 0; - } - - } - } - - if (!gDisconnected) - { + if (force_send || timed_out) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + // Send avatar and camera info + mLastAgentControlFlags = gAgent.getControlFlags(); + mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; + send_agent_update(force_send); + agent_update_timer.reset(); + } + } + + ////////////////////////////////////// + // + // Manage statistics + // + // + { + // Initialize the viewer_stats_timer with an already elapsed time + // of SEND_STATS_PERIOD so that the initial stats report will + // be sent immediately. + static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); + + // Update session stats every large chunk of time + // *FIX: (?) SAMANTHA + if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) + { + LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; + bool include_preferences = false; + send_viewer_stats(include_preferences); + viewer_stats_timer.reset(); + } + + // Print the object debugging stats + static LLFrameTimer object_debug_timer; + if (object_debug_timer.getElapsedTimeF32() > 5.f) + { + object_debug_timer.reset(); + if (gObjectList.mNumDeadObjectUpdates) + { + LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; + gObjectList.mNumDeadObjectUpdates = 0; + } + if (gObjectList.mNumUnknownUpdates) + { + LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; + gObjectList.mNumUnknownUpdates = 0; + } + + } + } + + if (!gDisconnected) + { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Network"); - //////////////////////////////////////////////// - // - // Network processing - // - // NOTE: Starting at this point, we may still have pointers to "dead" objects - // floating throughout the various object lists. - // - idleNameCache(); - idleNetwork(); + //////////////////////////////////////////////// + // + // Network processing + // + // NOTE: Starting at this point, we may still have pointers to "dead" objects + // floating throughout the various object lists. + // + idleNameCache(); + idleNetwork(); - // Check for away from keyboard, kick idle agents. - idle_afk_check(); + // Check for away from keyboard, kick idle agents. + idle_afk_check(); - // Update statistics for this frame - update_statistics(); - } + // Update statistics for this frame + update_statistics(); + } - //////////////////////////////////////// - // - // Handle the regular UI idle callbacks as well as - // hover callbacks - // + //////////////////////////////////////// + // + // Handle the regular UI idle callbacks as well as + // hover callbacks + // #ifdef LL_DARWIN - if (!mQuitRequested) //MAINT-4243 + if (!mQuitRequested) //MAINT-4243 #endif - { -// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); + { +// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); - // Do event notifications if necessary. Yes, we may want to move this elsewhere. - gEventNotifier.update(); + // Do event notifications if necessary. Yes, we may want to move this elsewhere. + gEventNotifier.update(); - gIdleCallbacks.callFunctions(); - gInventory.idleNotifyObservers(); - LLAvatarTracker::instance().idleNotifyObservers(); - } + gIdleCallbacks.callFunctions(); + gInventory.idleNotifyObservers(); + LLAvatarTracker::instance().idleNotifyObservers(); + } - // Metrics logging (LLViewerAssetStats, etc.) - { - static LLTimer report_interval; + // Metrics logging (LLViewerAssetStats, etc.) + { + static LLTimer report_interval; - // *TODO: Add configuration controls for this - F32 seconds = report_interval.getElapsedTimeF32(); - if (seconds >= app_metrics_interval) - { - metricsSend(! gDisconnected); - report_interval.reset(); - } - } + // *TODO: Add configuration controls for this + F32 seconds = report_interval.getElapsedTimeF32(); + if (seconds >= app_metrics_interval) + { + metricsSend(! gDisconnected); + report_interval.reset(); + } + } // Update layonts, handle mouse events, tooltips, e t c @@ -4848,335 +4848,335 @@ void LLAppViewer::idle() // opening chat. gViewerWindow->updateUI(); - if (gDisconnected) + if (gDisconnected) { - return; + return; } - if (gTeleportDisplay) + if (gTeleportDisplay) { - return; + return; } - /////////////////////////////////////// - // Agent and camera movement - // - LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); + /////////////////////////////////////// + // Agent and camera movement + // + LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); - { - // After agent and camera moved, figure out if we need to - // deselect objects. - LLSelectMgr::getInstance()->deselectAllIfTooFar(); + { + // After agent and camera moved, figure out if we need to + // deselect objects. + LLSelectMgr::getInstance()->deselectAllIfTooFar(); - } + } - { - // Handle pending gesture processing - LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); - LLGestureMgr::instance().update(); + { + // Handle pending gesture processing + LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); + LLGestureMgr::instance().update(); - gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); - } + gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); + } - { - LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); + { + LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); if (!(logoutRequestSent() && hasSavedFinalSnapshot())) - { - gObjectList.update(gAgent); - } - } - - ////////////////////////////////////// - // - // Deletes objects... - // Has to be done after doing idleUpdates (which can kill objects) - // - - { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP); - { - gObjectList.cleanDeadObjects(); - } - { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); - LLDrawable::cleanupDeadDrawables(); - } - } - - // - // After this point, in theory we should never see a dead object - // in the various object/drawable lists. - // - - ////////////////////////////////////// - // - // Update/send HUD effects - // - // At this point, HUD effects may clean up some references to - // dead objects. - // - - { - LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); - LLSelectMgr::getInstance()->updateEffects(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDManager::getInstance()->sendEffects(); - } - - //////////////////////////////////////// - // - // Unpack layer data that we've received - // - - { - LL_RECORD_BLOCK_TIME(FTM_NETWORK); - gVLManager.unpackData(); - } - - ///////////////////////// - // - // Update surfaces, and surface textures as well. - // - - LLWorld::getInstance()->updateVisibilities(); - { - const F32 max_region_update_time = .001f; // 1ms - LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); - LLWorld::getInstance()->updateRegions(max_region_update_time); - } - - ///////////////////////// - // - // Update weather effects - // - - // Update wind vector - LLVector3 wind_position_region; - static LLVector3 average_wind; - - LLViewerRegion *regionp; - regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position - if (regionp) - { - gWindVec = regionp->mWind.getVelocity(wind_position_region); - - // Compute average wind and use to drive motion of water - - average_wind = regionp->mWind.getAverage(); - gSky.setWind(average_wind); - //LLVOWater::setWind(average_wind); - } - else - { - gWindVec.setVec(0.0f, 0.0f, 0.0f); - } - - ////////////////////////////////////// - // - // Sort and cull in the new renderer are moved to pipeline.cpp - // Here, particles are updated and drawables are moved. - // - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); - gPipeline.updateMove(); - } - - LLWorld::getInstance()->updateParticles(); - - if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) - { - gAgentPilot.moveCamera(); - } - else if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - LLViewerJoystick::getInstance()->moveFlycam(); - } - else - { - if (LLToolMgr::getInstance()->inBuildMode()) - { - LLViewerJoystick::getInstance()->moveObjects(); - } - - gAgentCamera.updateCamera(); - } - - // update media focus - LLViewerMediaFocus::getInstance()->update(); - - // Update marketplace - LLMarketplaceInventoryImporter::update(); - LLMarketplaceInventoryNotifications::update(); - - // objects and camera should be in sync, do LOD calculations now - { - LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); - gObjectList.updateApparentAngles(gAgent); - } - - // Update AV render info - LLAvatarRenderInfoAccountant::getInstance()->idle(); - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); - - if (gAudiop) - { - audio_update_volume(false); - audio_update_listener(); - audio_update_wind(false); - - // this line actually commits the changes we've made to source positions, etc. - gAudiop->idle(); - } - } - - // Handle shutdown process, for example, - // wait for floaters to close, send quit message, - // forcibly quit if it has taken too long - if (mQuitRequested) - { - gGLActive = TRUE; - idleShutdown(); - } + { + gObjectList.update(gAgent); + } + } + + ////////////////////////////////////// + // + // Deletes objects... + // Has to be done after doing idleUpdates (which can kill objects) + // + + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP); + { + gObjectList.cleanDeadObjects(); + } + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); + LLDrawable::cleanupDeadDrawables(); + } + } + + // + // After this point, in theory we should never see a dead object + // in the various object/drawable lists. + // + + ////////////////////////////////////// + // + // Update/send HUD effects + // + // At this point, HUD effects may clean up some references to + // dead objects. + // + + { + LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); + LLSelectMgr::getInstance()->updateEffects(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDManager::getInstance()->sendEffects(); + } + + //////////////////////////////////////// + // + // Unpack layer data that we've received + // + + { + LL_RECORD_BLOCK_TIME(FTM_NETWORK); + gVLManager.unpackData(); + } + + ///////////////////////// + // + // Update surfaces, and surface textures as well. + // + + LLWorld::getInstance()->updateVisibilities(); + { + const F32 max_region_update_time = .001f; // 1ms + LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); + LLWorld::getInstance()->updateRegions(max_region_update_time); + } + + ///////////////////////// + // + // Update weather effects + // + + // Update wind vector + LLVector3 wind_position_region; + static LLVector3 average_wind; + + LLViewerRegion *regionp; + regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position + if (regionp) + { + gWindVec = regionp->mWind.getVelocity(wind_position_region); + + // Compute average wind and use to drive motion of water + + average_wind = regionp->mWind.getAverage(); + gSky.setWind(average_wind); + //LLVOWater::setWind(average_wind); + } + else + { + gWindVec.setVec(0.0f, 0.0f, 0.0f); + } + + ////////////////////////////////////// + // + // Sort and cull in the new renderer are moved to pipeline.cpp + // Here, particles are updated and drawables are moved. + // + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); + gPipeline.updateMove(); + } + + LLWorld::getInstance()->updateParticles(); + + if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) + { + gAgentPilot.moveCamera(); + } + else if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + LLViewerJoystick::getInstance()->moveFlycam(); + } + else + { + if (LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveObjects(); + } + + gAgentCamera.updateCamera(); + } + + // update media focus + LLViewerMediaFocus::getInstance()->update(); + + // Update marketplace + LLMarketplaceInventoryImporter::update(); + LLMarketplaceInventoryNotifications::update(); + + // objects and camera should be in sync, do LOD calculations now + { + LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); + gObjectList.updateApparentAngles(gAgent); + } + + // Update AV render info + LLAvatarRenderInfoAccountant::getInstance()->idle(); + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); + + if (gAudiop) + { + audio_update_volume(false); + audio_update_listener(); + audio_update_wind(false); + + // this line actually commits the changes we've made to source positions, etc. + gAudiop->idle(); + } + } + + // Handle shutdown process, for example, + // wait for floaters to close, send quit message, + // forcibly quit if it has taken too long + if (mQuitRequested) + { + gGLActive = TRUE; + idleShutdown(); + } } void LLAppViewer::idleShutdown() { - // Wait for all modal alerts to get resolved - if (LLModalDialog::activeCount() > 0) - { - return; - } - - // close IM interface - if(gIMMgr) - { - gIMMgr->disconnectAllSessions(); - } - - // Wait for all floaters to get resolved - if (gFloaterView - && !gFloaterView->allChildrenClosed()) - { - return; - } - - - - - // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup() - // *TODO: ugly - static bool saved_teleport_history = false; - if (!saved_teleport_history) - { - saved_teleport_history = true; - LLTeleportHistory::getInstance()->dump(); - LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this - return; - } - - static bool saved_snapshot = false; - if (!saved_snapshot) - { - saved_snapshot = true; - saveFinalSnapshot(); - return; - } - - const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f; - - S32 pending_uploads = gAssetStorage->getNumPendingUploads(); - if (pending_uploads > 0 - && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME - && !logoutRequestSent()) - { - static S32 total_uploads = 0; - // Sometimes total upload count can change during logout. - total_uploads = llmax(total_uploads, pending_uploads); - gViewerWindow->setShowProgress(TRUE); - S32 finished_uploads = total_uploads - pending_uploads; - F32 percent = 100.f * finished_uploads / total_uploads; - gViewerWindow->setProgressPercent(percent); - gViewerWindow->setProgressString(LLTrans::getString("SavingSettings")); - return; - } - - if (gPendingMetricsUploads > 0 - && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME - && !logoutRequestSent()) - { + // Wait for all modal alerts to get resolved + if (LLModalDialog::activeCount() > 0) + { + return; + } + + // close IM interface + if(gIMMgr) + { + gIMMgr->disconnectAllSessions(); + } + + // Wait for all floaters to get resolved + if (gFloaterView + && !gFloaterView->allChildrenClosed()) + { + return; + } + + + + + // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup() + // *TODO: ugly + static bool saved_teleport_history = false; + if (!saved_teleport_history) + { + saved_teleport_history = true; + LLTeleportHistory::getInstance()->dump(); + LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this + return; + } + + static bool saved_snapshot = false; + if (!saved_snapshot) + { + saved_snapshot = true; + saveFinalSnapshot(); + return; + } + + const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f; + + S32 pending_uploads = gAssetStorage->getNumPendingUploads(); + if (pending_uploads > 0 + && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME + && !logoutRequestSent()) + { + static S32 total_uploads = 0; + // Sometimes total upload count can change during logout. + total_uploads = llmax(total_uploads, pending_uploads); + gViewerWindow->setShowProgress(TRUE); + S32 finished_uploads = total_uploads - pending_uploads; + F32 percent = 100.f * finished_uploads / total_uploads; + gViewerWindow->setProgressPercent(percent); + gViewerWindow->setProgressString(LLTrans::getString("SavingSettings")); + return; + } + + if (gPendingMetricsUploads > 0 + && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME + && !logoutRequestSent()) + { gViewerWindow->setShowProgress(TRUE); gViewerWindow->setProgressPercent(100.f); gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); - return; - } - - // All floaters are closed. Tell server we want to quit. - if( !logoutRequestSent() ) - { - sendLogoutRequest(); - - // Wait for a LogoutReply message - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressPercent(100.f); - gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); - return; - } - - // Make sure that we quit if we haven't received a reply from the server. - if( logoutRequestSent() - && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime ) - { - forceQuit(); - return; - } + return; + } + + // All floaters are closed. Tell server we want to quit. + if( !logoutRequestSent() ) + { + sendLogoutRequest(); + + // Wait for a LogoutReply message + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressPercent(100.f); + gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); + return; + } + + // Make sure that we quit if we haven't received a reply from the server. + if( logoutRequestSent() + && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime ) + { + forceQuit(); + return; + } } void LLAppViewer::sendLogoutRequest() { - if(!mLogoutRequestSent && gMessageSystem) - { - //Set internal status variables and marker files before actually starting the logout process - gLogoutInProgress = TRUE; - if (!mSecondInstance) - { - mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); - - mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB); - if (mLogoutMarkerFile.getFileHandle()) - { - LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL; - recordMarkerVersion(mLogoutMarkerFile); - } - else - { - LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "Did not logout marker file because this is a second instance" << LL_ENDL; - } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_LogoutRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - - gLogoutTimer.reset(); - gLogoutMaxTime = LOGOUT_REQUEST_TIME; - mLogoutRequestSent = TRUE; - - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->leaveChannel(); - } - } + if(!mLogoutRequestSent && gMessageSystem) + { + //Set internal status variables and marker files before actually starting the logout process + gLogoutInProgress = TRUE; + if (!mSecondInstance) + { + mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); + + mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB); + if (mLogoutMarkerFile.getFileHandle()) + { + LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL; + recordMarkerVersion(mLogoutMarkerFile); + } + else + { + LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Did not logout marker file because this is a second instance" << LL_ENDL; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LogoutRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + + gLogoutTimer.reset(); + gLogoutMaxTime = LOGOUT_REQUEST_TIME; + mLogoutRequestSent = TRUE; + + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->leaveChannel(); + } + } } void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) @@ -5222,19 +5222,19 @@ void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) void LLAppViewer::idleNameCache() { - // Neither old nor new name cache can function before agent has a region - LLViewerRegion* region = gAgent.getRegion(); + // Neither old nor new name cache can function before agent has a region + LLViewerRegion* region = gAgent.getRegion(); if (!region) { return; } - // deal with any queued name requests and replies. - gCacheName->processPending(); + // deal with any queued name requests and replies. + gCacheName->processPending(); - // Can't run the new cache until we have the list of capabilities - // for the agent region, and can therefore decide whether to use - // display names or fall back to the old name system. + // Can't run the new cache until we have the list of capabilities + // for the agent region, and can therefore decide whether to use + // display names or fall back to the old name system. if (!region->capabilitiesReceived()) { return; @@ -5264,141 +5264,141 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ void LLAppViewer::idleNetwork() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - pingMainloopTimeout("idleNetwork"); - - gObjectList.mNumNewObjects = 0; - S32 total_decoded = 0; - - if (!gSavedSettings.getBOOL("SpeedTest")) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode - - LLTimer check_message_timer; - // Read all available packets from network - const S64 frame_count = gFrameCount; // U32->S64 - F32 total_time = 0.0f; - - { - LockMessageChecker lmc(gMessageSystem); - while (lmc.checkAllMessages(frame_count, gServicePump)) - { - if (gDoDisconnect) - { - // We're disconnecting, don't process any more messages from the server - // We're usually disconnecting due to either network corruption or a - // server going down, so this is OK. - break; - } - - total_decoded++; - gPacketsIn++; - - if (total_decoded > MESSAGE_MAX_PER_FRAME) - { - break; - } + pingMainloopTimeout("idleNetwork"); + + gObjectList.mNumNewObjects = 0; + S32 total_decoded = 0; + + if (!gSavedSettings.getBOOL("SpeedTest")) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode + + LLTimer check_message_timer; + // Read all available packets from network + const S64 frame_count = gFrameCount; // U32->S64 + F32 total_time = 0.0f; + + { + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(frame_count, gServicePump)) + { + if (gDoDisconnect) + { + // We're disconnecting, don't process any more messages from the server + // We're usually disconnecting due to either network corruption or a + // server going down, so this is OK. + break; + } + + total_decoded++; + gPacketsIn++; + + if (total_decoded > MESSAGE_MAX_PER_FRAME) + { + break; + } #ifdef TIME_THROTTLE_MESSAGES - // Prevent slow packets from completely destroying the frame rate. - // This usually happens due to clumps of avatars taking huge amount - // of network processing time (which needs to be fixed, but this is - // a good limit anyway). - total_time = check_message_timer.getElapsedTimeF32(); - if (total_time >= CheckMessagesMaxTime) - break; + // Prevent slow packets from completely destroying the frame rate. + // This usually happens due to clumps of avatars taking huge amount + // of network processing time (which needs to be fixed, but this is + // a good limit anyway). + total_time = check_message_timer.getElapsedTimeF32(); + if (total_time >= CheckMessagesMaxTime) + break; #endif - } + } - // Handle per-frame message system processing. - lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); - } + // Handle per-frame message system processing. + lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); + } #ifdef TIME_THROTTLE_MESSAGES - if (total_time >= CheckMessagesMaxTime) - { - // Increase CheckMessagesMaxTime so that we will eventually catch up - CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames - } - else - { - // Reset CheckMessagesMaxTime to default value - CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; - } + if (total_time >= CheckMessagesMaxTime) + { + // Increase CheckMessagesMaxTime so that we will eventually catch up + CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames + } + else + { + // Reset CheckMessagesMaxTime to default value + CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; + } #endif - // we want to clear the control after sending out all necessary agent updates - gAgent.resetControlFlags(); - - // Decode enqueued messages... - S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded; - - if( remaining_possible_decodes <= 0 ) - { - LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; - } - - if (gPrintMessagesThisFrame) - { - LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; - gPrintMessagesThisFrame = FALSE; - } - } - add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); - - // Retransmit unacknowledged packets. - gXferManager->retransmitUnackedPackets(); - gAssetStorage->checkForTimeouts(); - gViewerThrottle.updateDynamicThrottle(); - - // Check that the circuit between the viewer and the agent's current - // region is still alive - LLViewerRegion *agent_region = gAgent.getRegion(); - if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) - { - LLUUID this_region_id = agent_region->getRegionID(); - bool this_region_alive = agent_region->isAlive(); - if ((mAgentRegionLastAlive && !this_region_alive) // newly dead - && (mAgentRegionLastID == this_region_id)) // same region - { - forceDisconnect(LLTrans::getString("AgentLostConnection")); - } - mAgentRegionLastID = this_region_id; - mAgentRegionLastAlive = this_region_alive; - } + // we want to clear the control after sending out all necessary agent updates + gAgent.resetControlFlags(); + + // Decode enqueued messages... + S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded; + + if( remaining_possible_decodes <= 0 ) + { + LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; + } + + if (gPrintMessagesThisFrame) + { + LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; + gPrintMessagesThisFrame = FALSE; + } + } + add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); + + // Retransmit unacknowledged packets. + gXferManager->retransmitUnackedPackets(); + gAssetStorage->checkForTimeouts(); + gViewerThrottle.updateDynamicThrottle(); + + // Check that the circuit between the viewer and the agent's current + // region is still alive + LLViewerRegion *agent_region = gAgent.getRegion(); + if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) + { + LLUUID this_region_id = agent_region->getRegionID(); + bool this_region_alive = agent_region->isAlive(); + if ((mAgentRegionLastAlive && !this_region_alive) // newly dead + && (mAgentRegionLastID == this_region_id)) // same region + { + forceDisconnect(LLTrans::getString("AgentLostConnection")); + } + mAgentRegionLastID = this_region_id; + mAgentRegionLastAlive = this_region_alive; + } } void LLAppViewer::disconnectViewer() { - if (gDisconnected) - { - return; - } - // - // Cleanup after quitting. - // - // Save snapshot for next time, if we made it through initialization - - LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; - - // Dump our frame statistics - - // Remember if we were flying - gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); - - // Un-minimize all windows so they don't get saved minimized - if (gFloaterView) - { - gFloaterView->restoreAll(); - } - - if (LLSelectMgr::instanceExists()) - { - LLSelectMgr::getInstance()->deselectAll(); - } - - // save inventory if appropriate + if (gDisconnected) + { + return; + } + // + // Cleanup after quitting. + // + // Save snapshot for next time, if we made it through initialization + + LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; + + // Dump our frame statistics + + // Remember if we were flying + gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); + + // Un-minimize all windows so they don't get saved minimized + if (gFloaterView) + { + gFloaterView->restoreAll(); + } + + if (LLSelectMgr::instanceExists()) + { + LLSelectMgr::getInstance()->deselectAll(); + } + + // save inventory if appropriate if (gInventory.isInventoryUsable() && gAgent.getID().notNull()) // Shouldn't be null at this stage { @@ -5413,44 +5413,44 @@ void LLAppViewer::disconnectViewer() } } - saveNameCache(); - if (LLExperienceCache::instanceExists()) - { - // TODO: LLExperienceCache::cleanup() logic should be moved to - // cleanupSingleton(). - LLExperienceCache::instance().cleanup(); - } + saveNameCache(); + if (LLExperienceCache::instanceExists()) + { + // TODO: LLExperienceCache::cleanup() logic should be moved to + // cleanupSingleton(). + LLExperienceCache::instance().cleanup(); + } - // close inventory interface, close all windows - LLSidepanelInventory::cleanup(); + // close inventory interface, close all windows + LLSidepanelInventory::cleanup(); - gAgentWearables.cleanup(); - gAgentCamera.cleanup(); - // Also writes cached agent settings to gSavedSettings - gAgent.cleanup(); + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + // Also writes cached agent settings to gSavedSettings + gAgent.cleanup(); - // This is where we used to call gObjectList.destroy() and then delete gWorldp. - // Now we just ask the LLWorld singleton to cleanly shut down. - if(LLWorld::instanceExists()) - { - LLWorld::getInstance()->resetClass(); - } - LLVOCache::deleteSingleton(); + // This is where we used to call gObjectList.destroy() and then delete gWorldp. + // Now we just ask the LLWorld singleton to cleanly shut down. + if(LLWorld::instanceExists()) + { + LLWorld::getInstance()->resetClass(); + } + LLVOCache::deleteSingleton(); - // call all self-registered classes - LLDestroyClassList::instance().fireCallbacks(); + // call all self-registered classes + LLDestroyClassList::instance().fireCallbacks(); - cleanup_xfer_manager(); - gDisconnected = TRUE; + cleanup_xfer_manager(); + gDisconnected = TRUE; - // Pass the connection state to LLUrlEntryParcel not to attempt - // parcel info requests while disconnected. - LLUrlEntryParcel::setDisconnected(gDisconnected); + // Pass the connection state to LLUrlEntryParcel not to attempt + // parcel info requests while disconnected. + LLUrlEntryParcel::setDisconnected(gDisconnected); } void LLAppViewer::forceErrorLLError() { - LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; + LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; } void LLAppViewer::forceErrorLLErrorMsg() @@ -5463,7 +5463,7 @@ void LLAppViewer::forceErrorLLErrorMsg() void LLAppViewer::forceErrorBreakpoint() { - LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; #ifdef LL_WINDOWS DebugBreak(); #else @@ -5474,7 +5474,7 @@ void LLAppViewer::forceErrorBreakpoint() void LLAppViewer::forceErrorBadMemoryAccess() { - LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; S32* crash = NULL; *crash = 0xDEADBEEF; return; @@ -5482,7 +5482,7 @@ void LLAppViewer::forceErrorBadMemoryAccess() void LLAppViewer::forceErrorInfiniteLoop() { - LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; // Loop is intentionally complicated to fool basic loop detection LLTimer timer_total; LLTimer timer_expiry; @@ -5501,7 +5501,7 @@ void LLAppViewer::forceErrorInfiniteLoop() void LLAppViewer::forceErrorSoftwareException() { - LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; LLTHROW(LLException("User selected Force Software Exception")); } @@ -5514,8 +5514,8 @@ void LLAppViewer::forceErrorOSSpecificException() void LLAppViewer::forceErrorDriverCrash() { - LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; - glDeleteTextures(1, NULL); + LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; + glDeleteTextures(1, NULL); } void LLAppViewer::forceErrorCoroutineCrash() @@ -5547,120 +5547,120 @@ void LLAppViewer::forceErrorThreadCrash() void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) { - if(!mMainloopTimeout) - { - mMainloopTimeout = new LLWatchdogTimeout(); - resumeMainloopTimeout(state, secs); - } + if(!mMainloopTimeout) + { + mMainloopTimeout = new LLWatchdogTimeout(); + resumeMainloopTimeout(state, secs); + } } void LLAppViewer::destroyMainloopTimeout() { - if(mMainloopTimeout) - { - delete mMainloopTimeout; - mMainloopTimeout = NULL; - } + if(mMainloopTimeout) + { + delete mMainloopTimeout; + mMainloopTimeout = NULL; + } } void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) { - if(mMainloopTimeout) - { - if(secs < 0.0f) - { - static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); - secs = mainloop_timeout; - } - - mMainloopTimeout->setTimeout(secs); - mMainloopTimeout->start(state); - } + if(mMainloopTimeout) + { + if(secs < 0.0f) + { + static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; + } + + mMainloopTimeout->setTimeout(secs); + mMainloopTimeout->start(state); + } } void LLAppViewer::pauseMainloopTimeout() { - if(mMainloopTimeout) - { - mMainloopTimeout->stop(); - } + if(mMainloopTimeout) + { + mMainloopTimeout->stop(); + } } void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) { LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - if(mMainloopTimeout) - { - if(secs < 0.0f) - { - static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); - secs = mainloop_timeout; - } - - mMainloopTimeout->setTimeout(secs); - mMainloopTimeout->ping(state); - } + if(mMainloopTimeout) + { + if(secs < 0.0f) + { + static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; + } + + mMainloopTimeout->setTimeout(secs); + mMainloopTimeout->ping(state); + } } void LLAppViewer::handleLoginComplete() { - gLoggedInTime.start(); - initMainloopTimeout("Mainloop Init"); - - // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if ( parcel && parcel->getMusicURL()[0]) - { - gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); - } - if ( parcel && parcel->getMediaURL()[0]) - { - gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); - } - - gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); - gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); - gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); - gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - - if(gAgent.getRegion()) - { - gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); - gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); - } - - if(LLAppViewer::instance()->mMainloopTimeout) - { - gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); - } - - mOnLoginCompleted(); - - writeDebugInfo(); - - // we logged in successfully, so save settings on logout - LL_INFOS() << "Login successful, per account settings will be saved on log out." << LL_ENDL; - mSavePerAccountSettings=true; + gLoggedInTime.start(); + initMainloopTimeout("Mainloop Init"); + + // Store some data to DebugInfo in case of a freeze. + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if ( parcel && parcel->getMusicURL()[0]) + { + gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); + } + if ( parcel && parcel->getMediaURL()[0]) + { + gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); + } + + gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); + + if(gAgent.getRegion()) + { + gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); + gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); + } + + if(LLAppViewer::instance()->mMainloopTimeout) + { + gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); + } + + mOnLoginCompleted(); + + writeDebugInfo(); + + // we logged in successfully, so save settings on logout + LL_INFOS() << "Login successful, per account settings will be saved on log out." << LL_ENDL; + mSavePerAccountSettings=true; } //virtual void LLAppViewer::setMasterSystemAudioMute(bool mute) { - gSavedSettings.setBOOL("MuteAudio", mute); + gSavedSettings.setBOOL("MuteAudio", mute); } //virtual bool LLAppViewer::getMasterSystemAudioMute() { - return gSavedSettings.getBOOL("MuteAudio"); + return gSavedSettings.getBOOL("MuteAudio"); } //---------------------------------------------------------------------------- @@ -5676,10 +5676,10 @@ bool LLAppViewer::getMasterSystemAudioMute() */ void LLAppViewer::metricsUpdateRegion(U64 region_handle) { - if (0 != region_handle) - { - LLViewerAssetStatsFF::set_region(region_handle); - } + if (0 != region_handle) + { + LLViewerAssetStatsFF::set_region(region_handle); + } } /** @@ -5688,35 +5688,35 @@ void LLAppViewer::metricsUpdateRegion(U64 region_handle) */ void LLAppViewer::metricsSend(bool enable_reporting) { - if (! gViewerAssetStats) - return; + if (! gViewerAssetStats) + return; - if (LLAppViewer::sTextureFetch) - { - LLViewerRegion * regionp = gAgent.getRegion(); + if (LLAppViewer::sTextureFetch) + { + LLViewerRegion * regionp = gAgent.getRegion(); - if (enable_reporting && regionp) - { - std::string caps_url = regionp->getCapability("ViewerMetrics"); + if (enable_reporting && regionp) + { + std::string caps_url = regionp->getCapability("ViewerMetrics"); LLSD sd = gViewerAssetStats->asLLSD(true); - // Send a report request into 'thread1' to get the rest of the data - // and provide some additional parameters while here. - LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, - gAgentSessionID, - gAgentID, - sd); - } - else - { - LLAppViewer::sTextureFetch->commandDataBreak(); - } - } - - // Reset even if we can't report. Rather than gather up a huge chunk of - // data, we'll keep to our sampling interval and retain the data - // resolution in time. - gViewerAssetStats->restart(); + // Send a report request into 'thread1' to get the rest of the data + // and provide some additional parameters while here. + LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, + gAgentSessionID, + gAgentID, + sd); + } + else + { + LLAppViewer::sTextureFetch->commandDataBreak(); + } + } + + // Reset even if we can't report. Rather than gather up a huge chunk of + // data, we'll keep to our sampling interval and retain the data + // resolution in time. + gViewerAssetStats->restart(); } diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 68952c96c5..e654caf1b2 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ #include "llframetimer.h" #include "lltrans.h" #include "llviewercontrol.h" -#include "llwindow.h" // beforeDialog() +#include "llwindow.h" // beforeDialog() #if LL_SDL #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers @@ -76,149 +76,149 @@ LLFilePicker LLFilePicker::sInstance; // Implementation // LLFilePicker::LLFilePicker() - : mCurrentFile(0), - mLocked(false) + : mCurrentFile(0), + mLocked(false) { - reset(); + reset(); #if LL_WINDOWS - mOFN.lStructSize = sizeof(OPENFILENAMEW); - mOFN.hwndOwner = NULL; // Set later - mOFN.hInstance = NULL; - mOFN.lpstrCustomFilter = NULL; - mOFN.nMaxCustFilter = 0; - mOFN.lpstrFile = NULL; // set in open and close - mOFN.nMaxFile = LL_MAX_PATH; - mOFN.lpstrFileTitle = NULL; - mOFN.nMaxFileTitle = 0; - mOFN.lpstrInitialDir = NULL; - mOFN.lpstrTitle = NULL; - mOFN.Flags = 0; // set in open and close - mOFN.nFileOffset = 0; - mOFN.nFileExtension = 0; - mOFN.lpstrDefExt = NULL; - mOFN.lCustData = 0L; - mOFN.lpfnHook = NULL; - mOFN.lpTemplateName = NULL; - mFilesW[0] = '\0'; + mOFN.lStructSize = sizeof(OPENFILENAMEW); + mOFN.hwndOwner = NULL; // Set later + mOFN.hInstance = NULL; + mOFN.lpstrCustomFilter = NULL; + mOFN.nMaxCustFilter = 0; + mOFN.lpstrFile = NULL; // set in open and close + mOFN.nMaxFile = LL_MAX_PATH; + mOFN.lpstrFileTitle = NULL; + mOFN.nMaxFileTitle = 0; + mOFN.lpstrInitialDir = NULL; + mOFN.lpstrTitle = NULL; + mOFN.Flags = 0; // set in open and close + mOFN.nFileOffset = 0; + mOFN.nFileExtension = 0; + mOFN.lpstrDefExt = NULL; + mOFN.lCustData = 0L; + mOFN.lpfnHook = NULL; + mOFN.lpTemplateName = NULL; + mFilesW[0] = '\0'; #elif LL_DARWIN - mPickOptions = 0; + mPickOptions = 0; #endif } LLFilePicker::~LLFilePicker() { - // nothing + // nothing } -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLFilePicker::check_local_file_access_enabled() { - // if local file browsing is turned off, return without opening dialog - bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled"); - if ( ! local_file_system_browsing_enabled ) - { - mFiles.clear(); - return false; - } - - return true; + // if local file browsing is turned off, return without opening dialog + bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled"); + if ( ! local_file_system_browsing_enabled ) + { + mFiles.clear(); + return false; + } + + return true; } const std::string LLFilePicker::getFirstFile() { - mCurrentFile = 0; - return getNextFile(); + mCurrentFile = 0; + return getNextFile(); } const std::string LLFilePicker::getNextFile() { - if (mCurrentFile >= getFileCount()) - { - mLocked = false; - return std::string(); - } - else - { - return mFiles[mCurrentFile++]; - } + if (mCurrentFile >= getFileCount()) + { + mLocked = false; + return std::string(); + } + else + { + return mFiles[mCurrentFile++]; + } } const std::string LLFilePicker::getCurFile() { - if (mCurrentFile >= getFileCount()) - { - mLocked = false; - return std::string(); - } - else - { - return mFiles[mCurrentFile]; - } + if (mCurrentFile >= getFileCount()) + { + mLocked = false; + return std::string(); + } + else + { + return mFiles[mCurrentFile]; + } } void LLFilePicker::reset() { - mLocked = false; - mFiles.clear(); - mCurrentFile = 0; + mLocked = false; + mFiles.clear(); + mCurrentFile = 0; } #if LL_WINDOWS BOOL LLFilePicker::setupFilter(ELoadFilter filter) { - BOOL res = TRUE; - switch (filter) - { + BOOL res = TRUE; + switch (filter) + { case FFLOAD_ALL: case FFLOAD_EXE: - mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ - SOUND_FILTER \ - IMAGE_FILTER \ - ANIM_FILTER \ - MATERIAL_FILTER \ - L"\0"; - break; - case FFLOAD_WAV: - mOFN.lpstrFilter = SOUND_FILTER \ - L"\0"; - break; - case FFLOAD_IMAGE: - mOFN.lpstrFilter = IMAGE_FILTER \ - L"\0"; - break; - case FFLOAD_ANIM: - mOFN.lpstrFilter = ANIM_FILTER \ - L"\0"; - break; - case FFLOAD_GLTF: - mOFN.lpstrFilter = GLTF_FILTER \ - L"\0"; - break; - case FFLOAD_COLLADA: - mOFN.lpstrFilter = COLLADA_FILTER \ - L"\0"; - break; - case FFLOAD_XML: - mOFN.lpstrFilter = XML_FILTER \ - L"\0"; - break; - case FFLOAD_SLOBJECT: - mOFN.lpstrFilter = SLOBJECT_FILTER \ - L"\0"; - break; - case FFLOAD_RAW: - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFLOAD_MODEL: - mOFN.lpstrFilter = MODEL_FILTER \ - L"\0"; - break; + mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ + SOUND_FILTER \ + IMAGE_FILTER \ + ANIM_FILTER \ + MATERIAL_FILTER \ + L"\0"; + break; + case FFLOAD_WAV: + mOFN.lpstrFilter = SOUND_FILTER \ + L"\0"; + break; + case FFLOAD_IMAGE: + mOFN.lpstrFilter = IMAGE_FILTER \ + L"\0"; + break; + case FFLOAD_ANIM: + mOFN.lpstrFilter = ANIM_FILTER \ + L"\0"; + break; + case FFLOAD_GLTF: + mOFN.lpstrFilter = GLTF_FILTER \ + L"\0"; + break; + case FFLOAD_COLLADA: + mOFN.lpstrFilter = COLLADA_FILTER \ + L"\0"; + break; + case FFLOAD_XML: + mOFN.lpstrFilter = XML_FILTER \ + L"\0"; + break; + case FFLOAD_SLOBJECT: + mOFN.lpstrFilter = SLOBJECT_FILTER \ + L"\0"; + break; + case FFLOAD_RAW: + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFLOAD_MODEL: + mOFN.lpstrFilter = MODEL_FILTER \ + L"\0"; + break; case FFLOAD_MATERIAL: mOFN.lpstrFilter = MATERIAL_FILTER \ L"\0"; @@ -229,74 +229,74 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) IMAGE_FILTER \ L"\0"; break; - case FFLOAD_SCRIPT: - mOFN.lpstrFilter = SCRIPT_FILTER \ - L"\0"; - break; - case FFLOAD_DICTIONARY: - mOFN.lpstrFilter = DICTIONARY_FILTER \ - L"\0"; - break; + case FFLOAD_SCRIPT: + mOFN.lpstrFilter = SCRIPT_FILTER \ + L"\0"; + break; + case FFLOAD_DICTIONARY: + mOFN.lpstrFilter = DICTIONARY_FILTER \ + L"\0"; + break; case FFLOAD_LUA: mOFN.lpstrFilter = LUA_FILTER \ L"\0"; break; - default: - res = FALSE; - break; - } - return res; + default: + res = FALSE; + break; + } + return res; } BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; - mOFN.nFilterIndex = 1; - - setupFilter(filter); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - reset(); - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - - if (blocking) - { - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - } - - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + mOFN.lpstrFile = mFilesW; + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; + mOFN.nFilterIndex = 1; + + setupFilter(filter); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + reset(); + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + + return success; } BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, @@ -310,79 +310,79 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nFilterIndex = 1; - mOFN.nMaxFile = FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | - OFN_EXPLORER | OFN_ALLOWMULTISELECT; - - setupFilter(filter); - - reset(); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); // pauses until ok or cancel. - if( success ) - { - // The getopenfilename api doesn't tell us if we got more than - // one file, so we have to test manually by checking string - // lengths. - if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - else - { - mLocked = true; - WCHAR* tptrw = mFilesW; - std::string dirname; - while(1) - { - if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' - break; - if (*tptrw == 0) - tptrw++; // shouldn't happen? - std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); - if (dirname.empty()) - dirname = filename + "\\"; - else - mFiles.push_back(dirname + filename); - tptrw += wcslen(tptrw); - } - } - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + mOFN.lpstrFile = mFilesW; + mOFN.nFilterIndex = 1; + mOFN.nMaxFile = FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | + OFN_EXPLORER | OFN_ALLOWMULTISELECT; + + setupFilter(filter); + + reset(); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); // pauses until ok or cancel. + if( success ) + { + // The getopenfilename api doesn't tell us if we got more than + // one file, so we have to test manually by checking string + // lengths. + if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + else + { + mLocked = true; + WCHAR* tptrw = mFilesW; + std::string dirname; + while(1) + { + if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' + break; + if (*tptrw == 0) + tptrw++; // shouldn't happen? + std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); + if (dirname.empty()) + dirname = filename + "\\"; + else + mFiles.push_back(dirname + filename); + tptrw += wcslen(tptrw); + } + } + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, @@ -396,222 +396,222 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - mOFN.lpstrFile = mFilesW; - if (!filename.empty()) - { - llutf16string tstring = utf8str_to_utf16str(filename); - wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ - else - { - mFilesW[0] = '\0'; - } - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - - switch( filter ) - { - case FFSAVE_ALL: - mOFN.lpstrDefExt = NULL; - mOFN.lpstrFilter = - L"All Files (*.*)\0*.*\0" \ - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ - L"\0"; - break; - case FFSAVE_WAV: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"wav"; - mOFN.lpstrFilter = - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"\0"; - break; - case FFSAVE_TGA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"tga"; - mOFN.lpstrFilter = - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - case FFSAVE_BMP: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"bmp"; - mOFN.lpstrFilter = - L"Bitmap Images (*.bmp)\0*.bmp\0" \ - L"\0"; - break; - case FFSAVE_PNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"\0"; - break; - case FFSAVE_TGAPNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - //PNG by default - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - - case FFSAVE_JPEG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"jpg"; - mOFN.lpstrFilter = - L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ - L"\0"; - break; - case FFSAVE_AVI: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"avi"; - mOFN.lpstrFilter = - L"AVI Movie File (*.avi)\0*.avi\0" \ - L"\0"; - break; - case FFSAVE_ANIM: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"xaf"; - mOFN.lpstrFilter = - L"XAF Anim File (*.xaf)\0*.xaf\0" \ - L"\0"; - break; - case FFSAVE_GLTF: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"glb"; - mOFN.lpstrFilter = - L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ - L"\0"; - break; - case FFSAVE_XML: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - - mOFN.lpstrDefExt = L"xml"; - mOFN.lpstrFilter = - L"XML File (*.xml)\0*.xml\0" \ - L"\0"; - break; - case FFSAVE_COLLADA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"collada"; - mOFN.lpstrFilter = - L"COLLADA File (*.collada)\0*.collada\0" \ - L"\0"; - break; - case FFSAVE_RAW: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"raw"; - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFSAVE_J2C: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"j2c"; - mOFN.lpstrFilter = - L"Compressed Images (*.j2c)\0*.j2c\0" \ - L"\0"; - break; - case FFSAVE_SCRIPT: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"txt"; - mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; - break; - default: - return FALSE; - } - - - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; - - reset(); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - { - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - try - { - success = GetSaveFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - } - catch (...) - { - LOG_UNHANDLED_EXCEPTION(""); - } - gKeyboard->resetKeys(); - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + mOFN.lpstrFile = mFilesW; + if (!filename.empty()) + { + llutf16string tstring = utf8str_to_utf16str(filename); + wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ + else + { + mFilesW[0] = '\0'; + } + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + + switch( filter ) + { + case FFSAVE_ALL: + mOFN.lpstrDefExt = NULL; + mOFN.lpstrFilter = + L"All Files (*.*)\0*.*\0" \ + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ + L"\0"; + break; + case FFSAVE_WAV: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"wav"; + mOFN.lpstrFilter = + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"\0"; + break; + case FFSAVE_TGA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"tga"; + mOFN.lpstrFilter = + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + case FFSAVE_BMP: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"bmp"; + mOFN.lpstrFilter = + L"Bitmap Images (*.bmp)\0*.bmp\0" \ + L"\0"; + break; + case FFSAVE_PNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"\0"; + break; + case FFSAVE_TGAPNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + //PNG by default + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + + case FFSAVE_JPEG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"jpg"; + mOFN.lpstrFilter = + L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ + L"\0"; + break; + case FFSAVE_AVI: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"avi"; + mOFN.lpstrFilter = + L"AVI Movie File (*.avi)\0*.avi\0" \ + L"\0"; + break; + case FFSAVE_ANIM: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"xaf"; + mOFN.lpstrFilter = + L"XAF Anim File (*.xaf)\0*.xaf\0" \ + L"\0"; + break; + case FFSAVE_GLTF: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"glb"; + mOFN.lpstrFilter = + L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ + L"\0"; + break; + case FFSAVE_XML: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + + mOFN.lpstrDefExt = L"xml"; + mOFN.lpstrFilter = + L"XML File (*.xml)\0*.xml\0" \ + L"\0"; + break; + case FFSAVE_COLLADA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"collada"; + mOFN.lpstrFilter = + L"COLLADA File (*.collada)\0*.collada\0" \ + L"\0"; + break; + case FFSAVE_RAW: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"raw"; + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFSAVE_J2C: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"j2c"; + mOFN.lpstrFilter = + L"Compressed Images (*.j2c)\0*.j2c\0" \ + L"\0"; + break; + case FFSAVE_SCRIPT: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"txt"; + mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; + break; + default: + return FALSE; + } + + + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; + + reset(); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + { + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + try + { + success = GetSaveFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(""); + } + gKeyboard->resetKeys(); + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -690,25 +690,25 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF LL_WARNS() << "Unsupported format." << LL_ENDL; } - return allowedv; + return allowedv; } -bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) +bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) { - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return false; - } - - gViewerWindow->getWindow()->beforeDialog(); - + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } + + gViewerWindow->getWindow()->beforeDialog(); + std::unique_ptr<std::vector<std::string>> allowed_types = navOpenFilterProc(filter); - + std::unique_ptr<std::vector<std::string>> filev = doLoadDialog(allowed_types.get(), mPickOptions); - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); if (filev && filev->size() > 0) @@ -716,8 +716,8 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) mFiles.insert(mFiles.end(), filev->begin(), filev->end()); return true; } - - return false; + + return false; } bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, @@ -729,14 +729,14 @@ bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, { return false; } - + std::unique_ptr<std::vector<std::string>> allowed_types=navOpenFilterProc(filter); - + doLoadDialogModeless(allowed_types.get(), mPickOptions, callback, userdata); - + return true; } @@ -790,13 +790,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "\?\?\?\?"; extension = "glb"; break; - + case LLFilePicker::FFSAVE_XML: type = "\?\?\?\?"; creator = "\?\?\?\?"; extension = "xml"; break; - + case LLFilePicker::FFSAVE_RAW: type = "\?\?\?\?"; creator = "\?\?\?\?"; @@ -808,13 +808,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "prvw"; extension = "j2c"; break; - + case LLFilePicker::FFSAVE_SCRIPT: type = "LSL "; creator = "\?\?\?\?"; extension = "lsl"; break; - + case LLFilePicker::FFSAVE_ALL: default: type = "\?\?\?\?"; @@ -824,34 +824,34 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, } } -bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) { - // Setup the type, creator, and extension - std::string extension, type, creator; - + // Setup the type, creator, and extension + std::string extension, type, creator; + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; - - gViewerWindow->getWindow()->beforeDialog(); - // Run the dialog - std::unique_ptr<std::string> filev = doSaveDialog(&namestring, + gViewerWindow->getWindow()->beforeDialog(); + + // Run the dialog + std::unique_ptr<std::string> filev = doSaveDialog(&namestring, &type, &creator, &extension, mPickOptions); - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); - if ( filev && !filev->empty() ) - { + if ( filev && !filev->empty() ) + { mFiles.push_back(*filev); - return true; + return true; } - - return false; + + return false; } bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, @@ -861,9 +861,9 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; @@ -880,57 +880,57 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; + if( mLocked ) + return FALSE; - BOOL success = FALSE; + BOOL success = FALSE; - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); - reset(); - mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - - if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. + + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY ); mPickOptions &= ~F_FILE; } - if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful - { + if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful + { mPickOptions |= F_NAV_SUPPORT; - } - - if (blocking) // always true for linux/mac - { - // Modal, so pause agent - send_agent_pause(); - } - - - success = doNavChooseDialog(filter); - - if (success) - { - if (!getFileCount()) - success = false; - } - - if (blocking) - { - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - } - - return success; + } + + if (blocking) // always true for linux/mac + { + // Modal, so pause agent + send_agent_pause(); + } + + + success = doNavChooseDialog(filter); + + if (success) + { + if (!getFileCount()) + success = false; + } + + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + + return success; } @@ -948,10 +948,10 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { @@ -969,47 +969,47 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - + if( mLocked ) + return FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + BOOL success = FALSE; - reset(); - + reset(); + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; - if (blocking) // always true for linux/mac - { - // Modal, so pause agent - send_agent_pause(); - } - - success = doNavChooseDialog(filter); - - if (blocking) - { - send_agent_resume(); - } - - if (success) - { - if (!getFileCount()) - success = false; - if (getFileCount() > 1) - mLocked = true; - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if (blocking) // always true for linux/mac + { + // Modal, so pause agent + send_agent_pause(); + } + + success = doNavChooseDialog(filter); + + if (blocking) + { + send_agent_resume(); + } + + if (success) + { + if (!getFileCount()) + success = false; + if (getFileCount() > 1) + mLocked = true; + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } @@ -1027,7 +1027,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, } reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1038,42 +1038,42 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { - if( mLocked ) - return false; - BOOL success = false; + if( mLocked ) + return false; + BOOL success = false; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return false; - } + reset(); - reset(); - mPickOptions &= ~F_MULTIPLE; - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } success = doNavSaveDialog(filter, filename); if (success) - { - if (!getFileCount()) - success = false; - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + { + if (!getFileCount()) + success = false; + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -1083,7 +1083,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, { if( mLocked ) return false; - + // if local file browsing is turned off, return without opening dialog if ( check_local_file_access_enabled() == false ) { @@ -1091,7 +1091,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; return doNavSaveDialogModeless(filter, filename, callback, userdata); @@ -1105,414 +1105,414 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, // static void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) { - // We need to run g_filename_to_utf8 in the user's locale - std::string saved_locale(setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, ""); - - LLFilePicker* picker = (LLFilePicker*) user_data; - GError *error = NULL; - gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, - -1, NULL, NULL, &error); - if (error) - { - // *FIXME. - // This condition should really be notified to the user, e.g. - // through a message box. Just logging it is inappropriate. - - // g_filename_display_name is ideal, but >= glib 2.6, so: - // a hand-rolled hacky makeASCII which disallows control chars - std::string display_name; - for (const gchar *str = (const gchar *)data; *str; str++) - { - display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); - } - LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; - } - - if (filename_utf8) - { - picker->mFiles.push_back(std::string(filename_utf8)); - LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; - g_free(filename_utf8); - } - - setlocale(LC_ALL, saved_locale.c_str()); + // We need to run g_filename_to_utf8 in the user's locale + std::string saved_locale(setlocale(LC_ALL, NULL)); + setlocale(LC_ALL, ""); + + LLFilePicker* picker = (LLFilePicker*) user_data; + GError *error = NULL; + gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, + -1, NULL, NULL, &error); + if (error) + { + // *FIXME. + // This condition should really be notified to the user, e.g. + // through a message box. Just logging it is inappropriate. + + // g_filename_display_name is ideal, but >= glib 2.6, so: + // a hand-rolled hacky makeASCII which disallows control chars + std::string display_name; + for (const gchar *str = (const gchar *)data; *str; str++) + { + display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); + } + LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; + } + + if (filename_utf8) + { + picker->mFiles.push_back(std::string(filename_utf8)); + LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; + g_free(filename_utf8); + } + + setlocale(LC_ALL, saved_locale.c_str()); } // static void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) { - LLFilePicker* picker = (LLFilePicker*)user_data; - - LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); - g_slist_foreach(file_list, (GFunc)g_free, NULL); - g_slist_free (file_list); - } - - // let's save the extension of the last added file(considering current filter) - GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); - if(gfilter) - { - std::string filter = gtk_file_filter_get_name(gfilter); - - if(filter == LLTrans::getString("png_image_files")) - { - picker->mCurrentExtension = ".png"; - } - else if(filter == LLTrans::getString("targa_image_files")) - { - picker->mCurrentExtension = ".tga"; - } - } - - // set the default path for this usage context. - const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); - if (cur_folder != NULL) - { - picker->mContextToPathMap[picker->mCurContextName] = cur_folder; - } - - gtk_widget_destroy(widget); - gtk_main_quit(); + LLFilePicker* picker = (LLFilePicker*)user_data; + + LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; + + if (response == GTK_RESPONSE_ACCEPT) + { + GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); + g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); + g_slist_foreach(file_list, (GFunc)g_free, NULL); + g_slist_free (file_list); + } + + // let's save the extension of the last added file(considering current filter) + GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); + if(gfilter) + { + std::string filter = gtk_file_filter_get_name(gfilter); + + if(filter == LLTrans::getString("png_image_files")) + { + picker->mCurrentExtension = ".png"; + } + else if(filter == LLTrans::getString("targa_image_files")) + { + picker->mCurrentExtension = ".tga"; + } + } + + // set the default path for this usage context. + const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); + if (cur_folder != NULL) + { + picker->mContextToPathMap[picker->mCurContextName] = cur_folder; + } + + gtk_widget_destroy(widget); + gtk_main_quit(); } GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) { #ifndef LL_MESA_HEADLESS - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - GtkFileChooserAction pickertype = - is_save? - (is_folder? - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : - GTK_FILE_CHOOSER_ACTION_SAVE) : - (is_folder? - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : - GTK_FILE_CHOOSER_ACTION_OPEN); - - win = gtk_file_chooser_dialog_new(NULL, NULL, - pickertype, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - is_folder ? - GTK_STOCK_APPLY : - (is_save ? - GTK_STOCK_SAVE : - GTK_STOCK_OPEN), - GTK_RESPONSE_ACCEPT, - (gchar *)NULL); - mCurContextName = context; - - // get the default path for this usage context if it's been - // seen before. - std::map<std::string,std::string>::iterator - this_path = mContextToPathMap.find(context); - if (this_path != mContextToPathMap.end()) - { - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(win), - this_path->second.c_str()); - } + if (LLWindowSDL::ll_try_gtk_init()) + { + GtkWidget *win = NULL; + GtkFileChooserAction pickertype = + is_save? + (is_folder? + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : + GTK_FILE_CHOOSER_ACTION_SAVE) : + (is_folder? + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : + GTK_FILE_CHOOSER_ACTION_OPEN); + + win = gtk_file_chooser_dialog_new(NULL, NULL, + pickertype, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + is_folder ? + GTK_STOCK_APPLY : + (is_save ? + GTK_STOCK_SAVE : + GTK_STOCK_OPEN), + GTK_RESPONSE_ACCEPT, + (gchar *)NULL); + mCurContextName = context; + + // get the default path for this usage context if it's been + // seen before. + std::map<std::string,std::string>::iterator + this_path = mContextToPathMap.find(context); + if (this_path != mContextToPathMap.end()) + { + gtk_file_chooser_set_current_folder + (GTK_FILE_CHOOSER(win), + this_path->second.c_str()); + } # if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK raw X11 window, which should try - // to keep it on top etc. - Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); - if (None != XWindowID) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } - else - { - LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; - } + // Make GTK tell the window manager to associate this + // dialog with our non-GTK raw X11 window, which should try + // to keep it on top etc. + Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); + if (None != XWindowID) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, + gdkwin); + } + else + { + LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; + } # endif //LL_X11 - g_signal_connect (GTK_FILE_CHOOSER(win), - "response", - G_CALLBACK(LLFilePicker::chooser_responder), - this); + g_signal_connect (GTK_FILE_CHOOSER(win), + "response", + G_CALLBACK(LLFilePicker::chooser_responder), + this); - gtk_window_set_modal(GTK_WINDOW(win), TRUE); + gtk_window_set_modal(GTK_WINDOW(win), TRUE); - /* GTK 2.6: if (is_folder) - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), - TRUE); */ + /* GTK 2.6: if (is_folder) + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), + TRUE); */ - return GTK_WINDOW(win); - } - else - { - return NULL; - } + return GTK_WINDOW(win); + } + else + { + return NULL; + } #else - return NULL; + return NULL; #endif //LL_MESA_HEADLESS } static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, - GtkWindow *picker, - std::string filtername) -{ - gtk_file_filter_set_name(gfilter, filtername.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter); - GtkFileFilter *allfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(allfilter, "*"); - gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); + GtkWindow *picker, + std::string filtername) +{ + gtk_file_filter_set_name(gfilter, filtername.c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter); + GtkFileFilter *allfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(allfilter, "*"); + gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); } static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, - std::string pattern, - std::string filtername) + std::string pattern, + std::string filtername) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, pattern.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, pattern.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, - std::string mime, - std::string filtername) + std::string mime, + std::string filtername) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_mime_type(gfilter, mime.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_mime_type(gfilter, mime.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", - LLTrans::getString("sound_files") + " (*.wav)"); + return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", + LLTrans::getString("sound_files") + " (*.wav)"); } static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.bvh"); - gtk_file_filter_add_pattern(gfilter, "*.anim"); - std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.bvh"); + gtk_file_filter_add_pattern(gfilter, "*.anim"); + std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", - LLTrans::getString("xml_files") + " (*.xml)"); + return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", + LLTrans::getString("xml_files") + " (*.xml)"); } static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", - LLTrans::getString("scene_files") + " (*.dae)"); + return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", + LLTrans::getString("scene_files") + " (*.dae)"); } static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.tga"); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); + std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } - + static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("script_files") + " (*.lsl)"); + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, + LLTrans::getString("script_files") + " (*.lsl)"); } static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, + LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); } static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter_tga = gtk_file_filter_new(); - GtkFileFilter *gfilter_png = gtk_file_filter_new(); - - gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); - gtk_file_filter_add_mime_type(gfilter_png, "image/png"); - std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; - gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); - gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); - - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_png); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_tga); - return caption; + GtkFileFilter *gfilter_tga = gtk_file_filter_new(); + GtkFileFilter *gfilter_png = gtk_file_filter_new(); + + gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); + gtk_file_filter_add_mime_type(gfilter_png, "image/png"); + std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; + gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); + gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); + + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter_png); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter_tga); + return caption; } BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(true, false, "savefile"); - - if (picker) - { - std::string suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) - { - case FFSAVE_WAV: - caption += add_wav_filter_to_gtkchooser(picker); - suggest_ext = ".wav"; - break; - case FFSAVE_TGA: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); - suggest_ext = ".tga"; - break; - case FFSAVE_BMP: - caption += add_simple_mime_filter_to_gtkchooser - (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); - suggest_ext = ".bmp"; - break; - case FFSAVE_PNG: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); - suggest_ext = ".png"; - break; - case FFSAVE_TGAPNG: - caption += add_save_texture_filter_to_gtkchooser(picker); - suggest_ext = ".png"; - break; - case FFSAVE_AVI: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "video/x-msvideo", - LLTrans::getString("avi_movie_file") + " (*.avi)"); - suggest_ext = ".avi"; - break; - case FFSAVE_ANIM: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); - suggest_ext = ".xaf"; - break; - case FFSAVE_XML: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); - suggest_ext = ".xml"; - break; - case FFSAVE_RAW: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); - suggest_ext = ".raw"; - break; - case FFSAVE_J2C: - // *TODO: Should this be 'image/j2c' ? - caption += add_simple_mime_filter_to_gtkchooser - (picker, "images/jp2", - LLTrans::getString("compressed_image_files") + " (*.j2c)"); - suggest_ext = ".j2c"; - break; - case FFSAVE_SCRIPT: - caption += add_script_filter_to_gtkchooser(picker); - suggest_ext = ".lsl"; - break; - default:; - break; - } - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - if (filename.empty()) - { - suggest_name += suggest_ext; - - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), - suggest_name.c_str()); - } - else - { - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), filename.c_str()); - } - - gtk_widget_show_all(GTK_WIDGET(picker)); - - gtk_main(); - - rtn = (getFileCount() == 1); - - if(rtn && filter == FFSAVE_TGAPNG) - { - std::string selected_file = mFiles.back(); - mFiles.pop_back(); - mFiles.push_back(selected_file + mCurrentExtension); - } - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + gViewerWindow->getWindow()->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(true, false, "savefile"); + + if (picker) + { + std::string suggest_name = "untitled"; + std::string suggest_ext = ""; + std::string caption = LLTrans::getString("save_file_verb") + " "; + switch (filter) + { + case FFSAVE_WAV: + caption += add_wav_filter_to_gtkchooser(picker); + suggest_ext = ".wav"; + break; + case FFSAVE_TGA: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); + suggest_ext = ".tga"; + break; + case FFSAVE_BMP: + caption += add_simple_mime_filter_to_gtkchooser + (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); + suggest_ext = ".bmp"; + break; + case FFSAVE_PNG: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); + suggest_ext = ".png"; + break; + case FFSAVE_TGAPNG: + caption += add_save_texture_filter_to_gtkchooser(picker); + suggest_ext = ".png"; + break; + case FFSAVE_AVI: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "video/x-msvideo", + LLTrans::getString("avi_movie_file") + " (*.avi)"); + suggest_ext = ".avi"; + break; + case FFSAVE_ANIM: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); + suggest_ext = ".xaf"; + break; + case FFSAVE_XML: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); + suggest_ext = ".xml"; + break; + case FFSAVE_RAW: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); + suggest_ext = ".raw"; + break; + case FFSAVE_J2C: + // *TODO: Should this be 'image/j2c' ? + caption += add_simple_mime_filter_to_gtkchooser + (picker, "images/jp2", + LLTrans::getString("compressed_image_files") + " (*.j2c)"); + suggest_ext = ".j2c"; + break; + case FFSAVE_SCRIPT: + caption += add_script_filter_to_gtkchooser(picker); + suggest_ext = ".lsl"; + break; + default:; + break; + } + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + if (filename.empty()) + { + suggest_name += suggest_ext; + + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), + suggest_name.c_str()); + } + else + { + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), filename.c_str()); + } + + gtk_widget_show_all(GTK_WIDGET(picker)); + + gtk_main(); + + rtn = (getFileCount() == 1); + + if(rtn && filter == FFSAVE_TGAPNG) + { + std::string selected_file = mFiles.back(); + mFiles.pop_back(); + mFiles.push_back(selected_file + mCurrentExtension); + } + } + + gViewerWindow->getWindow()->afterDialog(); + + return rtn; } BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - std::string caption = LLTrans::getString("load_file_verb") + " "; - std::string filtername = ""; - switch (filter) - { - case FFLOAD_WAV: - filtername = add_wav_filter_to_gtkchooser(picker); - break; - case FFLOAD_ANIM: - filtername = add_anim_filter_to_gtkchooser(picker); - break; - case FFLOAD_XML: - filtername = add_xml_filter_to_gtkchooser(picker); - break; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + gViewerWindow->getWindow()->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(false, false, "openfile"); + + if (picker) + { + std::string caption = LLTrans::getString("load_file_verb") + " "; + std::string filtername = ""; + switch (filter) + { + case FFLOAD_WAV: + filtername = add_wav_filter_to_gtkchooser(picker); + break; + case FFLOAD_ANIM: + filtername = add_anim_filter_to_gtkchooser(picker); + break; + case FFLOAD_XML: + filtername = add_xml_filter_to_gtkchooser(picker); + break; case FFLOAD_GLTF: filtername = dead_code_should_blow_up_here(picker); break; @@ -1520,64 +1520,64 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) filtername = add_collada_filter_to_gtkchooser(picker); break; case FFLOAD_IMAGE: - filtername = add_imageload_filter_to_gtkchooser(picker); - break; - case FFLOAD_SCRIPT: - filtername = add_script_filter_to_gtkchooser(picker); - break; - case FFLOAD_DICTIONARY: - filtername = add_dictionary_filter_to_gtkchooser(picker); - break; - default:; - break; - } - - caption += filtername; - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + filtername = add_imageload_filter_to_gtkchooser(picker); + break; + case FFLOAD_SCRIPT: + filtername = add_script_filter_to_gtkchooser(picker); + break; + case FFLOAD_DICTIONARY: + filtername = add_dictionary_filter_to_gtkchooser(picker); + break; + default:; + break; + } + + caption += filtername; + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + + rtn = (getFileCount() == 1); + } + + gViewerWindow->getWindow()->afterDialog(); + + return rtn; } BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - BOOL rtn = FALSE; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + gViewerWindow->getWindow()->beforeDialog(); - gViewerWindow->getWindow()->beforeDialog(); + reset(); - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); + GtkWindow* picker = buildFilePicker(false, false, "openfile"); - if (picker) - { - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), - TRUE); + if (picker) + { + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), + TRUE); - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); + gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - rtn = !mFiles.empty(); - } + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + rtn = !mFiles.empty(); + } - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); - return rtn; + return rtn; } # else // LL_GTK @@ -1587,23 +1587,23 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - - LL_INFOS() << "getSaveFile suggested filename is [" << filename - << "]" << LL_ENDL; - if (!filename.empty()) - { - mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); - return TRUE; - } - return FALSE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + + LL_INFOS() << "getSaveFile suggested filename is [" << filename + << "]" << LL_ENDL; + if (!filename.empty()) + { + mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); + return TRUE; + } + return FALSE; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -1617,27 +1617,27 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - - // HACK: Static filenames for 'open' until we implement filepicker - std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; - switch (filter) - { - case FFLOAD_WAV: filename += ".wav"; break; - case FFLOAD_IMAGE: filename += ".tga"; break; - case FFLOAD_ANIM: filename += ".bvh"; break; - default: break; - } - mFiles.push_back(filename); - LL_INFOS() << "getOpenFile: Will try to open file: " << filename << LL_ENDL; - return TRUE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + + // HACK: Static filenames for 'open' until we implement filepicker + std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; + switch (filter) + { + case FFLOAD_WAV: filename += ".wav"; break; + case FFLOAD_IMAGE: filename += ".tga"; break; + case FFLOAD_ANIM: filename += ".bvh"; break; + default: break; + } + mFiles.push_back(filename); + LL_INFOS() << "getOpenFile: Will try to open file: " << filename << LL_ENDL; + return TRUE; } BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, @@ -1650,15 +1650,15 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - return FALSE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + return FALSE; } BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, @@ -1675,20 +1675,20 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) { - reset(); - return FALSE; + reset(); + return FALSE; } BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) { - reset(); - return FALSE; + reset(); + return FALSE; } BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - reset(); - return FALSE; + reset(); + return FALSE; } #endif // LL_LINUX diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index f00f076d1c..c4380dcd19 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.h * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,119 +64,119 @@ extern "C" { class LLFilePicker { #ifdef LL_GTK - friend class LLDirPicker; - friend void chooser_responder(GtkWidget *, gint, gpointer); + friend class LLDirPicker; + friend void chooser_responder(GtkWidget *, gint, gpointer); #endif // LL_GTK public: - // calling this before main() is undefined - static LLFilePicker& instance( void ) { return sInstance; } - - enum ELoadFilter - { - FFLOAD_ALL = 1, - FFLOAD_WAV = 2, - FFLOAD_IMAGE = 3, - FFLOAD_ANIM = 4, - FFLOAD_GLTF = 5, - FFLOAD_XML = 6, - FFLOAD_SLOBJECT = 7, - FFLOAD_RAW = 8, - FFLOAD_MODEL = 9, - FFLOAD_COLLADA = 10, - FFLOAD_SCRIPT = 11, - FFLOAD_DICTIONARY = 12, + // calling this before main() is undefined + static LLFilePicker& instance( void ) { return sInstance; } + + enum ELoadFilter + { + FFLOAD_ALL = 1, + FFLOAD_WAV = 2, + FFLOAD_IMAGE = 3, + FFLOAD_ANIM = 4, + FFLOAD_GLTF = 5, + FFLOAD_XML = 6, + FFLOAD_SLOBJECT = 7, + FFLOAD_RAW = 8, + FFLOAD_MODEL = 9, + FFLOAD_COLLADA = 10, + FFLOAD_SCRIPT = 11, + FFLOAD_DICTIONARY = 12, FFLOAD_DIRECTORY = 13, // To call from lldirpicker. FFLOAD_EXE = 14, // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin FFLOAD_MATERIAL = 15, FFLOAD_MATERIAL_TEXTURE = 16, FFLOAD_LUA = 17, - }; - - enum ESaveFilter - { - FFSAVE_ALL = 1, - FFSAVE_WAV = 3, - FFSAVE_TGA = 4, - FFSAVE_BMP = 5, - FFSAVE_AVI = 6, - FFSAVE_ANIM = 7, - FFSAVE_GLTF = 8, - FFSAVE_XML = 9, - FFSAVE_COLLADA = 10, - FFSAVE_RAW = 11, - FFSAVE_J2C = 12, - FFSAVE_PNG = 13, - FFSAVE_JPEG = 14, - FFSAVE_SCRIPT = 15, - FFSAVE_TGAPNG = 16 - }; - - // open the dialog. This is a modal operation - BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); + }; + + enum ESaveFilter + { + FFSAVE_ALL = 1, + FFSAVE_WAV = 3, + FFSAVE_TGA = 4, + FFSAVE_BMP = 5, + FFSAVE_AVI = 6, + FFSAVE_ANIM = 7, + FFSAVE_GLTF = 8, + FFSAVE_XML = 9, + FFSAVE_COLLADA = 10, + FFSAVE_RAW = 11, + FFSAVE_J2C = 12, + FFSAVE_PNG = 13, + FFSAVE_JPEG = 14, + FFSAVE_SCRIPT = 15, + FFSAVE_TGAPNG = 16 + }; + + // open the dialog. This is a modal operation + BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); BOOL getSaveFileModeless(ESaveFilter filter, const std::string& filename, void (*callback)(bool, std::string&, void*), void *userdata); - BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); // Todo: implement getOpenFileModeless and getMultipleOpenFilesModeless // for windows and use directly instead of ugly LLFilePickerThread BOOL getOpenFileModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata); // MAC only. - BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); BOOL getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata ); // MAC only - // Get the filename(s) found. getFirstFile() sets the pointer to - // the start of the structure and allows the start of iteration. - const std::string getFirstFile(); + // Get the filename(s) found. getFirstFile() sets the pointer to + // the start of the structure and allows the start of iteration. + const std::string getFirstFile(); + + // getNextFile() increments the internal representation and + // returns the next file specified by the user. Returns NULL when + // no more files are left. Further calls to getNextFile() are + // undefined. + const std::string getNextFile(); - // getNextFile() increments the internal representation and - // returns the next file specified by the user. Returns NULL when - // no more files are left. Further calls to getNextFile() are - // undefined. - const std::string getNextFile(); + // This utility function extracts the current file name without + // doing any incrementing. + const std::string getCurFile(); - // This utility function extracts the current file name without - // doing any incrementing. - const std::string getCurFile(); + // Returns the index of the current file. + S32 getCurFileNum() const { return mCurrentFile; } - // Returns the index of the current file. - S32 getCurFileNum() const { return mCurrentFile; } + S32 getFileCount() const { return (S32)mFiles.size(); } - S32 getFileCount() const { return (S32)mFiles.size(); } + // see lldir.h : getBaseFileName and getDirName to extract base or directory names - // see lldir.h : getBaseFileName and getDirName to extract base or directory names - - // clear any lists of buffers or whatever, and make sure the file - // picker isn't locked. - void reset(); + // clear any lists of buffers or whatever, and make sure the file + // picker isn't locked. + void reset(); private: - enum - { - SINGLE_FILENAME_BUFFER_SIZE = 1024, - //FILENAME_BUFFER_SIZE = 65536 - FILENAME_BUFFER_SIZE = 65000 - }; - - // utility function to check if access to local file system via file browser - // is enabled and if not, tidy up and indicate we're not allowed to do this. - bool check_local_file_access_enabled(); - + enum + { + SINGLE_FILENAME_BUFFER_SIZE = 1024, + //FILENAME_BUFFER_SIZE = 65536 + FILENAME_BUFFER_SIZE = 65000 + }; + + // utility function to check if access to local file system via file browser + // is enabled and if not, tidy up and indicate we're not allowed to do this. + bool check_local_file_access_enabled(); + #if LL_WINDOWS - OPENFILENAMEW mOFN; // for open and save dialogs - WCHAR mFilesW[FILENAME_BUFFER_SIZE]; + OPENFILENAMEW mOFN; // for open and save dialogs + WCHAR mFilesW[FILENAME_BUFFER_SIZE]; - BOOL setupFilter(ELoadFilter filter); + BOOL setupFilter(ELoadFilter filter); #endif #if LL_DARWIN S32 mPickOptions; - std::vector<std::string> mFileVector; - - bool doNavChooseDialog(ELoadFilter filter); - bool doNavChooseDialogModeless(ELoadFilter filter, + std::vector<std::string> mFileVector; + + bool doNavChooseDialog(ELoadFilter filter); + bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector<std::string>&, void*), void *userdata); - bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); + bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); std::unique_ptr<std::vector<std::string>> navOpenFilterProc(ELoadFilter filter); bool doNavSaveDialogModeless(ESaveFilter filter, const std::string& filename, @@ -185,31 +185,31 @@ private: #endif #if LL_GTK - static void add_to_selectedfiles(gpointer data, gpointer user_data); - static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); - // we remember the last path that was accessed for a particular usage - std::map <std::string, std::string> mContextToPathMap; - std::string mCurContextName; - // we also remember the extension of the last added file. - std::string mCurrentExtension; + static void add_to_selectedfiles(gpointer data, gpointer user_data); + static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); + // we remember the last path that was accessed for a particular usage + std::map <std::string, std::string> mContextToPathMap; + std::string mCurContextName; + // we also remember the extension of the last added file. + std::string mCurrentExtension; #endif - std::vector<std::string> mFiles; - S32 mCurrentFile; - bool mLocked; + std::vector<std::string> mFiles; + S32 mCurrentFile; + bool mLocked; + + static LLFilePicker sInstance; - static LLFilePicker sInstance; - protected: #if LL_GTK GtkWindow* buildFilePicker(bool is_save, bool is_folder, - std::string context = "generic"); + std::string context = "generic"); #endif public: - // don't call these directly please. - LLFilePicker(); - ~LLFilePicker(); + // don't call these directly please. + LLFilePicker(); + ~LLFilePicker(); }; #endif diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 6fd11dd1c7..60571d6247 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llfloaterluadebug.cpp * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -72,7 +72,7 @@ BOOL LLFloaterLUADebug::postBuild() return TRUE; } -LLFloaterLUADebug::~LLFloaterLUADebug() +LLFloaterLUADebug::~LLFloaterLUADebug() {} void LLFloaterLUADebug::onExecuteClicked() @@ -80,7 +80,7 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); - cleanLuaState(); + cleanLuaState(); LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) { completion(count, result); @@ -94,17 +94,17 @@ void LLFloaterLUADebug::onBtnBrowse() void LLFloaterLUADebug::onBtnRun() { - std::vector<std::string> filenames; - std::string filepath = mScriptPath->getText(); - if (!filepath.empty()) - { - filenames.push_back(filepath); - runSelectedScript(filenames); - } + std::vector<std::string> filenames; + std::string filepath = mScriptPath->getText(); + if (!filepath.empty()) + { + filenames.push_back(filepath); + runSelectedScript(filenames); + } } void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames) -{ +{ mResultOutput->setValue(""); std::string filepath = filenames[0]; @@ -145,9 +145,9 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) } } -void LLFloaterLUADebug::cleanLuaState() -{ - if(getChild<LLCheckBoxCtrl>("clean_lua_state")->get()) +void LLFloaterLUADebug::cleanLuaState() +{ + if(getChild<LLCheckBoxCtrl>("clean_lua_state")->get()) { //Reinit to clean lua_State mState.initLuaState(); diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index e1df6a4b1f..751990b3b6 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloatersettingsdebug.cpp * @brief floater for debugging internal viewer settings * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,12 +37,12 @@ #include "llclipboard.h" -LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) +LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) : LLFloater(key), mSettingList(NULL) { - mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); - mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); + mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); + mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); } LLFloaterSettingsDebug::~LLFloaterSettingsDebug() @@ -68,7 +68,7 @@ BOOL LLFloaterSettingsDebug::postBuild() gSavedSettings.getControl("DebugSettingsHideDefault")->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateList, this, false)); - return TRUE; + return TRUE; } void LLFloaterSettingsDebug::draw() @@ -80,7 +80,7 @@ void LLFloaterSettingsDebug::draw() updateControl(controlp); } - LLFloater::draw(); + LLFloater::draw(); } void LLFloaterSettingsDebug::onCommitSettings() @@ -92,78 +92,78 @@ void LLFloaterSettingsDebug::onCommitSettings() } LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata(); - if (!controlp) - { - return; - } - - LLVector3 vector; - LLVector3d vectord; - LLQuaternion quat; - LLRect rect; - LLColor4 col4; - LLColor3 col3; - LLColor4U col4U; - LLColor4 color_with_alpha; - - switch(controlp->type()) - { - case TYPE_U32: - controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); - break; - case TYPE_S32: - controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); - break; - case TYPE_F32: - controlp->set(LLSD(getChild<LLUICtrl>("val_spinner_1")->getValue().asReal())); - break; - case TYPE_BOOLEAN: - controlp->set(getChild<LLUICtrl>("boolean_combo")->getValue()); - break; - case TYPE_STRING: - controlp->set(LLSD(getChild<LLUICtrl>("val_text")->getValue().asString())); - break; - case TYPE_VEC3: - vector.mV[VX] = (F32)getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); - vector.mV[VY] = (F32)getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - vector.mV[VZ] = (F32)getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - controlp->set(vector.getValue()); - break; - case TYPE_VEC3D: - vectord.mdV[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); - vectord.mdV[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - vectord.mdV[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - controlp->set(vectord.getValue()); - break; - case TYPE_QUAT: - quat.mQ[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); - quat.mQ[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - quat.mQ[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - quat.mQ[VS] = getChild<LLUICtrl>("val_spinner_4")->getValue().asReal();; - controlp->set(quat.getValue()); - break; - case TYPE_RECT: - rect.mLeft = getChild<LLUICtrl>("val_spinner_1")->getValue().asInteger(); - rect.mRight = getChild<LLUICtrl>("val_spinner_2")->getValue().asInteger(); - rect.mBottom = getChild<LLUICtrl>("val_spinner_3")->getValue().asInteger(); - rect.mTop = getChild<LLUICtrl>("val_spinner_4")->getValue().asInteger(); - controlp->set(rect.getValue()); - break; - case TYPE_COL4: - col3.setValue(getChild<LLUICtrl>("val_color_swatch")->getValue()); - col4 = LLColor4(col3, (F32)getChild<LLUICtrl>("val_spinner_4")->getValue().asReal()); - controlp->set(col4.getValue()); - break; - case TYPE_COL3: - controlp->set(getChild<LLUICtrl>("val_color_swatch")->getValue()); - //col3.mV[VRED] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_1")->getValue().asC(); - //col3.mV[VGREEN] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - //col3.mV[VBLUE] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - //controlp->set(col3.getValue()); - break; - default: - break; - } + if (!controlp) + { + return; + } + + LLVector3 vector; + LLVector3d vectord; + LLQuaternion quat; + LLRect rect; + LLColor4 col4; + LLColor3 col3; + LLColor4U col4U; + LLColor4 color_with_alpha; + + switch(controlp->type()) + { + case TYPE_U32: + controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); + break; + case TYPE_S32: + controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); + break; + case TYPE_F32: + controlp->set(LLSD(getChild<LLUICtrl>("val_spinner_1")->getValue().asReal())); + break; + case TYPE_BOOLEAN: + controlp->set(getChild<LLUICtrl>("boolean_combo")->getValue()); + break; + case TYPE_STRING: + controlp->set(LLSD(getChild<LLUICtrl>("val_text")->getValue().asString())); + break; + case TYPE_VEC3: + vector.mV[VX] = (F32)getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + vector.mV[VY] = (F32)getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + vector.mV[VZ] = (F32)getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + controlp->set(vector.getValue()); + break; + case TYPE_VEC3D: + vectord.mdV[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + vectord.mdV[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + vectord.mdV[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + controlp->set(vectord.getValue()); + break; + case TYPE_QUAT: + quat.mQ[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + quat.mQ[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + quat.mQ[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + quat.mQ[VS] = getChild<LLUICtrl>("val_spinner_4")->getValue().asReal();; + controlp->set(quat.getValue()); + break; + case TYPE_RECT: + rect.mLeft = getChild<LLUICtrl>("val_spinner_1")->getValue().asInteger(); + rect.mRight = getChild<LLUICtrl>("val_spinner_2")->getValue().asInteger(); + rect.mBottom = getChild<LLUICtrl>("val_spinner_3")->getValue().asInteger(); + rect.mTop = getChild<LLUICtrl>("val_spinner_4")->getValue().asInteger(); + controlp->set(rect.getValue()); + break; + case TYPE_COL4: + col3.setValue(getChild<LLUICtrl>("val_color_swatch")->getValue()); + col4 = LLColor4(col3, (F32)getChild<LLUICtrl>("val_spinner_4")->getValue().asReal()); + controlp->set(col4.getValue()); + break; + case TYPE_COL3: + controlp->set(getChild<LLUICtrl>("val_color_swatch")->getValue()); + //col3.mV[VRED] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_1")->getValue().asC(); + //col3.mV[VGREEN] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + //col3.mV[VBLUE] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + //controlp->set(col3.getValue()); + break; + default: + break; + } updateDefaultColumn(controlp); } @@ -186,27 +186,27 @@ void LLFloaterSettingsDebug::onClickDefault() // we've switched controls, or doing per-frame update, so update spinners, etc. void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) { - LLSpinCtrl* spinner1 = getChild<LLSpinCtrl>("val_spinner_1"); - LLSpinCtrl* spinner2 = getChild<LLSpinCtrl>("val_spinner_2"); - LLSpinCtrl* spinner3 = getChild<LLSpinCtrl>("val_spinner_3"); - LLSpinCtrl* spinner4 = getChild<LLSpinCtrl>("val_spinner_4"); - LLColorSwatchCtrl* color_swatch = getChild<LLColorSwatchCtrl>("val_color_swatch"); - - if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) - { - LL_WARNS() << "Could not find all desired controls by name" - << LL_ENDL; - return; - } + LLSpinCtrl* spinner1 = getChild<LLSpinCtrl>("val_spinner_1"); + LLSpinCtrl* spinner2 = getChild<LLSpinCtrl>("val_spinner_2"); + LLSpinCtrl* spinner3 = getChild<LLSpinCtrl>("val_spinner_3"); + LLSpinCtrl* spinner4 = getChild<LLSpinCtrl>("val_spinner_4"); + LLColorSwatchCtrl* color_swatch = getChild<LLColorSwatchCtrl>("val_color_swatch"); + + if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) + { + LL_WARNS() << "Could not find all desired controls by name" + << LL_ENDL; + return; + } hideUIControls(); - if (controlp && !isSettingHidden(controlp)) - { - eControlType type = controlp->type(); + if (controlp && !isSettingHidden(controlp)) + { + eControlType type = controlp->type(); - //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame - getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); + //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame + getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); getChildView("default_btn")->setVisible(true); mSettingName->setVisible(true); mSettingName->setText(controlp->getName()); @@ -224,259 +224,259 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) mComment->setText(controlp->getComment()); } - spinner1->setMaxValue(F32_MAX); - spinner2->setMaxValue(F32_MAX); - spinner3->setMaxValue(F32_MAX); - spinner4->setMaxValue(F32_MAX); - spinner1->setMinValue(-F32_MAX); - spinner2->setMinValue(-F32_MAX); - spinner3->setMinValue(-F32_MAX); - spinner4->setMinValue(-F32_MAX); - if (!spinner1->hasFocus()) - { - spinner1->setIncrement(0.1f); - } - if (!spinner2->hasFocus()) - { - spinner2->setIncrement(0.1f); - } - if (!spinner3->hasFocus()) - { - spinner3->setIncrement(0.1f); - } - if (!spinner4->hasFocus()) - { - spinner4->setIncrement(0.1f); - } - - LLSD sd = controlp->get(); - switch(type) - { - case TYPE_U32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setValue(sd); - spinner1->setMinValue((F32)U32_MIN); - spinner1->setMaxValue((F32)U32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); - } - break; - case TYPE_S32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setValue(sd); - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); - } - break; - case TYPE_F32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(sd); - } - break; - case TYPE_BOOLEAN: - if (!getChild<LLUICtrl>("boolean_combo")->hasFocus()) - { - if (sd.asBoolean()) - { - getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("true")); - } - else - { - getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("")); - } - } - break; - case TYPE_STRING: - getChildView("val_text")->setVisible( TRUE); - if (!getChild<LLUICtrl>("val_text")->hasFocus()) - { - getChild<LLUICtrl>("val_text")->setValue(sd); - } - break; - case TYPE_VEC3: - { - LLVector3 v; - v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); - } - break; - } - case TYPE_VEC3D: - { - LLVector3d v; - v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); - } - break; - } - case TYPE_QUAT: - { - LLQuaternion q; - q.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("S")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(4); - spinner1->setValue(q.mQ[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(4); - spinner2->setValue(q.mQ[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(4); - spinner3->setValue(q.mQ[VZ]); - } - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(4); - spinner4->setValue(q.mQ[VS]); - } - break; - } - case TYPE_RECT: - { - LLRect r; - r.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("Left")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Right")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Bottom")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Top")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(0); - spinner1->setValue(r.mLeft); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(0); - spinner2->setValue(r.mRight); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(0); - spinner3->setValue(r.mBottom); - } - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(0); - spinner4->setValue(r.mTop); - } - - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - - spinner2->setMinValue((F32)S32_MIN); - spinner2->setMaxValue((F32)S32_MAX); - spinner2->setIncrement(1.f); - - spinner3->setMinValue((F32)S32_MIN); - spinner3->setMaxValue((F32)S32_MAX); - spinner3->setIncrement(1.f); - - spinner4->setMinValue((F32)S32_MIN); - spinner4->setMaxValue((F32)S32_MAX); - spinner4->setIncrement(1.f); - break; - } - case TYPE_COL4: - { - LLColor4 clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - // only set if changed so color picker doesn't update - if(clr != LLColor4(color_swatch->getValue())) - { - color_swatch->set(LLColor4(sd), TRUE, FALSE); - } - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Alpha")); - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(3); - spinner4->setMinValue(0.0); - spinner4->setMaxValue(1.f); - spinner4->setValue(clr.mV[VALPHA]); - } - break; - } - case TYPE_COL3: - { - LLColor3 clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - color_swatch->setValue(sd); - break; - } - default: - mComment->setText(std::string("unknown")); - break; - } - } + spinner1->setMaxValue(F32_MAX); + spinner2->setMaxValue(F32_MAX); + spinner3->setMaxValue(F32_MAX); + spinner4->setMaxValue(F32_MAX); + spinner1->setMinValue(-F32_MAX); + spinner2->setMinValue(-F32_MAX); + spinner3->setMinValue(-F32_MAX); + spinner4->setMinValue(-F32_MAX); + if (!spinner1->hasFocus()) + { + spinner1->setIncrement(0.1f); + } + if (!spinner2->hasFocus()) + { + spinner2->setIncrement(0.1f); + } + if (!spinner3->hasFocus()) + { + spinner3->setIncrement(0.1f); + } + if (!spinner4->hasFocus()) + { + spinner4->setIncrement(0.1f); + } + + LLSD sd = controlp->get(); + switch(type) + { + case TYPE_U32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setValue(sd); + spinner1->setMinValue((F32)U32_MIN); + spinner1->setMaxValue((F32)U32_MAX); + spinner1->setIncrement(1.f); + spinner1->setPrecision(0); + } + break; + case TYPE_S32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setValue(sd); + spinner1->setMinValue((F32)S32_MIN); + spinner1->setMaxValue((F32)S32_MAX); + spinner1->setIncrement(1.f); + spinner1->setPrecision(0); + } + break; + case TYPE_F32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(sd); + } + break; + case TYPE_BOOLEAN: + if (!getChild<LLUICtrl>("boolean_combo")->hasFocus()) + { + if (sd.asBoolean()) + { + getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("true")); + } + else + { + getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("")); + } + } + break; + case TYPE_STRING: + getChildView("val_text")->setVisible( TRUE); + if (!getChild<LLUICtrl>("val_text")->hasFocus()) + { + getChild<LLUICtrl>("val_text")->setValue(sd); + } + break; + case TYPE_VEC3: + { + LLVector3 v; + v.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(v[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(3); + spinner2->setValue(v[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(3); + spinner3->setValue(v[VZ]); + } + break; + } + case TYPE_VEC3D: + { + LLVector3d v; + v.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(v[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(3); + spinner2->setValue(v[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(3); + spinner3->setValue(v[VZ]); + } + break; + } + case TYPE_QUAT: + { + LLQuaternion q; + q.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("S")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(4); + spinner1->setValue(q.mQ[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(4); + spinner2->setValue(q.mQ[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(4); + spinner3->setValue(q.mQ[VZ]); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(4); + spinner4->setValue(q.mQ[VS]); + } + break; + } + case TYPE_RECT: + { + LLRect r; + r.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("Left")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Right")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Bottom")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("Top")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(0); + spinner1->setValue(r.mLeft); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(0); + spinner2->setValue(r.mRight); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(0); + spinner3->setValue(r.mBottom); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(0); + spinner4->setValue(r.mTop); + } + + spinner1->setMinValue((F32)S32_MIN); + spinner1->setMaxValue((F32)S32_MAX); + spinner1->setIncrement(1.f); + + spinner2->setMinValue((F32)S32_MIN); + spinner2->setMaxValue((F32)S32_MAX); + spinner2->setIncrement(1.f); + + spinner3->setMinValue((F32)S32_MIN); + spinner3->setMaxValue((F32)S32_MAX); + spinner3->setIncrement(1.f); + + spinner4->setMinValue((F32)S32_MIN); + spinner4->setMaxValue((F32)S32_MAX); + spinner4->setIncrement(1.f); + break; + } + case TYPE_COL4: + { + LLColor4 clr; + clr.setValue(sd); + color_swatch->setVisible(TRUE); + // only set if changed so color picker doesn't update + if(clr != LLColor4(color_swatch->getValue())) + { + color_swatch->set(LLColor4(sd), TRUE, FALSE); + } + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("Alpha")); + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(3); + spinner4->setMinValue(0.0); + spinner4->setMaxValue(1.f); + spinner4->setValue(clr.mV[VALPHA]); + } + break; + } + case TYPE_COL3: + { + LLColor3 clr; + clr.setValue(sd); + color_swatch->setVisible(TRUE); + color_swatch->setValue(sd); + break; + } + default: + mComment->setText(std::string("unknown")); + break; + } + } } @@ -500,7 +500,7 @@ void LLFloaterSettingsDebug::updateList(bool skip_selection) LLFloaterSettingsDebug* floater; std::string selected_setting; bool skip_selection; - f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection) + f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection) : setting_list(list), floater(floater), selected_setting(setting), skip_selection(skip_selection) {} virtual void apply(const std::string& name, LLControlVariable* control) { diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index 6ff3e344b4..e52d5ac863 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloatersettingsdebug.h * @brief floater for debugging internal viewer settings * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,30 +33,30 @@ class LLScrollListCtrl; class LLTextBox; -class LLFloaterSettingsDebug -: public LLFloater +class LLFloaterSettingsDebug +: public LLFloater { - friend class LLFloaterReg; + friend class LLFloaterReg; public: - virtual BOOL postBuild(); - virtual void draw(); + virtual BOOL postBuild(); + virtual void draw(); - void updateControl(LLControlVariable* control); + void updateControl(LLControlVariable* control); - void onCommitSettings(); - void onClickDefault(); + void onCommitSettings(); + void onClickDefault(); void onClickCopy(); bool matchesSearchFilter(std::string setting_name); bool isSettingHidden(LLControlVariable* control); private: - // key - selects which settings to show, one of: - // "all", "base", "account", "skin" - LLFloaterSettingsDebug(const LLSD& key); - virtual ~LLFloaterSettingsDebug(); + // key - selects which settings to show, one of: + // "all", "base", "account", "skin" + LLFloaterSettingsDebug(const LLSD& key); + virtual ~LLFloaterSettingsDebug(); void updateList(bool skip_selection = false); void onSettingSelect(); @@ -66,9 +66,9 @@ private: void hideUIControls(); LLScrollListCtrl* mSettingList; - + protected: - class LLTextEditor* mComment; + class LLTextEditor* mComment; LLTextBox* mSettingName; LLButton* mCopyBtn; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 7d1252ee31..f0dcdf01c1 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llinventoryfunctions.cpp * @brief Implementation of the inventory view and associated stuff. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -152,19 +152,19 @@ S32 count_stock_folders(LLInventoryModel::cat_array_t& categories) // Helper funtion : Count the number of items (not folders) in the descending hierarchy S32 count_descendants_items(const LLUUID& cat_id) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + S32 count = item_array->size(); - + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { - LLViewerInventoryCategory* category = *iter; + LLViewerInventoryCategory* category = *iter; count += count_descendants_items(category->getUUID()); } - + return count; } @@ -179,7 +179,7 @@ bool contains_nocopy_items(const LLUUID& id) LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(id,cat_array,item_array); - + // Check all the items: returns true upon encountering a nocopy item for (LLInventoryModel::item_array_t::iterator iter = item_array->begin(); iter != item_array->end(); iter++) { @@ -190,7 +190,7 @@ bool contains_nocopy_items(const LLUUID& id) return true; } } - + // Check all the sub folders recursively for (LLInventoryModel::cat_array_t::iterator iter = cat_array->begin(); iter != cat_array->end(); iter++) { @@ -203,14 +203,14 @@ bool contains_nocopy_items(const LLUUID& id) } else { - LLInventoryItem* item = gInventory.getItem(id); + LLInventoryItem* item = gInventory.getItem(id); LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item; if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { return true; } } - + // Exit without meeting a nocopy item return false; } @@ -218,21 +218,21 @@ bool contains_nocopy_items(const LLUUID& id) // Generates a string containing the path to the item specified by id. void append_path(const LLUUID& id, std::string& path) { - std::string temp; - const LLInventoryObject* obj = gInventory.getObject(id); - LLUUID parent_id; - if(obj) parent_id = obj->getParentUUID(); - std::string forward_slash("/"); - while(obj) - { - obj = gInventory.getCategory(parent_id); - if(obj) - { - temp.assign(forward_slash + obj->getName() + temp); - parent_id = obj->getParentUUID(); - } - } - path.append(temp); + std::string temp; + const LLInventoryObject* obj = gInventory.getObject(id); + LLUUID parent_id; + if(obj) parent_id = obj->getParentUUID(); + std::string forward_slash("/"); + while(obj) + { + obj = gInventory.getCategory(parent_id); + if(obj) + { + temp.assign(forward_slash + obj->getName() + temp); + parent_id = obj->getParentUUID(); + } + } + path.append(temp); } // Generates a string containing the path name of the object. @@ -273,10 +273,10 @@ void update_marketplace_folder_hierarchy(const LLUUID cat_id) gInventory.addChangedMask(LLInventoryObserver::LABEL, cat_id); // Update all descendent folders down - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { @@ -291,9 +291,9 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc // When changing the marketplace status of an item, we usually have to change the status of all // folders in the same listing. This is because the display of each folder is affected by the // overall status of the whole listing. - // Consequently, the only way to correctly update an item anywhere in the marketplace is to + // Consequently, the only way to correctly update an item anywhere in the marketplace is to // update the whole listing from its listing root. - // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth + // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth // is limited to 4. // We also take care of degenerated cases so we don't update all folders in the inventory by mistake. @@ -303,7 +303,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc { return; } - + // Grab marketplace listing data for this item S32 depth = depth_nesting_in_marketplace(cur_uuid); if (depth > 0) @@ -312,7 +312,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc LLUUID listing_uuid = nested_parent_id(cur_uuid, depth); LLViewerInventoryCategory* listing_cat = gInventory.getCategory(listing_uuid); bool listing_cat_loaded = listing_cat != NULL && listing_cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; - + // Verify marketplace data consistency for this listing if (perform_consistency_enforcement && listing_cat_loaded @@ -336,7 +336,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc LLMarketplaceData::instance().activateListing(listing_uuid, false,1); } } - + // Check if the count on hand needs to be updated on SLM if (perform_consistency_enforcement && listing_cat_loaded @@ -377,10 +377,10 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc void update_all_marketplace_count(const LLUUID& cat_id) { // Get all descendent folders down - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { @@ -412,19 +412,19 @@ void update_all_marketplace_count() void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) { - LLViewerInventoryCategory* cat; + LLViewerInventoryCategory* cat; - if (!model || - !get_is_category_renameable(model, cat_id) || - (cat = model->getCategory(cat_id)) == NULL || - cat->getName() == new_name) - { - return; - } + if (!model || + !get_is_category_renameable(model, cat_id) || + (cat = model->getCategory(cat_id)) == NULL || + cat->getName() == new_name) + { + return; + } - LLSD updates; - updates["name"] = new_name; - update_inventory_category(cat_id, updates, NULL); + LLSD updates; + updates["name"] = new_name; + update_inventory_category(cat_id, updates, NULL); } void copy_inventory_category(LLInventoryModel* model, @@ -448,7 +448,7 @@ void copy_inventory_category(LLInventoryModel* model, bool move_no_copy_items, inventory_func_type callback) { - // Create the initial folder + // Create the initial folder inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID &new_id) { copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items); @@ -457,7 +457,7 @@ void copy_inventory_category(LLInventoryModel* model, callback(new_id); } }; - gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); + gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); } void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) @@ -469,21 +469,21 @@ void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items) { - model->notifyObservers(); + model->notifyObservers(); - // We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... - LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); + // We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... + LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); - // Get the content of the folder - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(), cat_array, item_array); + // Get the content of the folder + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(), cat_array, item_array); - // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder - if (root_copy_id.isNull()) - { - LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); - } + // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder + if (root_copy_id.isNull()) + { + LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); + } LLPointer<LLInventoryCallback> cb; if (root_copy_id.isNull()) @@ -495,348 +495,348 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); } - // Copy all the items - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; - - if (item->getIsLinkType()) - { - link_inventory_object(new_cat_uuid, item->getLinkedUUID(), cb); - } - else if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) - { - // If the item is nocopy, we do nothing or, optionally, move it - if (move_no_copy_items) - { - // Reparent the item - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; - gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); - } + // Copy all the items + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; + + if (item->getIsLinkType()) + { + link_inventory_object(new_cat_uuid, item->getLinkedUUID(), cb); + } + else if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // If the item is nocopy, we do nothing or, optionally, move it + if (move_no_copy_items) + { + // Reparent the item + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; + gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); + } if (root_copy_id.isNull()) { // Decrement the count in root_id since that one item won't be copied over LLMarketplaceData::instance().decrementValidationWaiting(root_id); } - } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - new_cat_uuid, - std::string(), - cb); - } - } - - // Copy all the folders - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLViewerInventoryCategory* category = *iter; - if (category->getUUID() != root_id) - { - copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); - } - } + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + new_cat_uuid, + std::string(), + cb); + } + } + + // Copy all the folders + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLViewerInventoryCategory* category = *iter; + if (category->getUUID() != root_id) + { + copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); + } + } } class LLInventoryCollectAllItems : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + return true; + } }; BOOL get_is_parent_to_worn_item(const LLUUID& id) { - const LLViewerInventoryCategory* cat = gInventory.getCategory(id); - if (!cat) - { - return FALSE; - } + const LLViewerInventoryCategory* cat = gInventory.getCategory(id); + if (!cat) + { + return FALSE; + } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryCollectAllItems collect_all; - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryCollectAllItems collect_all; + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); - for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) - { - const LLViewerInventoryItem * const item = *it; + for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) + { + const LLViewerInventoryItem * const item = *it; - llassert(item->getIsLinkType()); + llassert(item->getIsLinkType()); - LLUUID linked_id = item->getLinkedUUID(); - const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id); + LLUUID linked_id = item->getLinkedUUID(); + const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id); - if (linked_item) - { - LLUUID parent_id = linked_item->getParentUUID(); + if (linked_item) + { + LLUUID parent_id = linked_item->getParentUUID(); - while (!parent_id.isNull()) - { - LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id); + while (!parent_id.isNull()) + { + LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id); - if (cat == parent_cat) - { - return TRUE; - } + if (cat == parent_cat) + { + return TRUE; + } - parent_id = parent_cat->getParentUUID(); - } - } - } + parent_id = parent_cat->getParentUUID(); + } + } + } - return FALSE; + return FALSE; } BOOL get_is_item_worn(const LLUUID& id) { - const LLViewerInventoryItem* item = gInventory.getItem(id); - if (!item) - return FALSE; + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + return FALSE; if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID())) { return FALSE; } - // Consider the item as worn if it has links in COF. - if (LLAppearanceMgr::instance().isLinkedInCOF(id)) - { - return TRUE; - } - - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - { - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) - return TRUE; - break; - } - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(gAgentWearables.isWearingItem(item->getLinkedUUID())) - return TRUE; - break; - case LLAssetType::AT_GESTURE: - if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID())) - return TRUE; - break; - default: - break; - } - return FALSE; + // Consider the item as worn if it has links in COF. + if (LLAppearanceMgr::instance().isLinkedInCOF(id)) + { + return TRUE; + } + + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + { + if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) + return TRUE; + break; + } + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if(gAgentWearables.isWearingItem(item->getLinkedUUID())) + return TRUE; + break; + case LLAssetType::AT_GESTURE: + if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID())) + return TRUE; + break; + default: + break; + } + return FALSE; } BOOL get_can_item_be_worn(const LLUUID& id) { - const LLViewerInventoryItem* item = gInventory.getItem(id); - if (!item) - return FALSE; - - if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) - { - // an item having links in COF (i.e. a worn item) - return FALSE; - } - - if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) - { - // a non-link object in COF (should not normally happen) - return FALSE; - } - - const LLUUID trash_id = gInventory.findCategoryUUIDForType( - LLFolderType::FT_TRASH); - - // item can't be worn if base obj in trash, see EXT-7015 - if (gInventory.isObjectDescendentOf(item->getLinkedUUID(), - trash_id)) - { - return false; - } - - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - { - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) - { - // Already being worn - return FALSE; - } - else - { - // Not being worn yet. - return TRUE; - } - break; - } - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(gAgentWearables.isWearingItem(item->getLinkedUUID())) - { - // Already being worn - return FALSE; - } - else - { - // Not being worn yet. - return TRUE; - } - break; - default: - break; - } - return FALSE; + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + return FALSE; + + if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) + { + // an item having links in COF (i.e. a worn item) + return FALSE; + } + + if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) + { + // a non-link object in COF (should not normally happen) + return FALSE; + } + + const LLUUID trash_id = gInventory.findCategoryUUIDForType( + LLFolderType::FT_TRASH); + + // item can't be worn if base obj in trash, see EXT-7015 + if (gInventory.isObjectDescendentOf(item->getLinkedUUID(), + trash_id)) + { + return false; + } + + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + { + if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) + { + // Already being worn + return FALSE; + } + else + { + // Not being worn yet. + return TRUE; + } + break; + } + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if(gAgentWearables.isWearingItem(item->getLinkedUUID())) + { + // Already being worn + return FALSE; + } + else + { + // Not being worn yet. + return TRUE; + } + break; + default: + break; + } + return FALSE; } BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) { - if (!model) - { - return FALSE; - } - - // Can't delete an item that's in the library. - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } - - // Disable delete from COF folder; have users explicitly choose "detach/take off", - // unless the item is not worn but in the COF (i.e. is bugged). - if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) - { - if (get_is_item_worn(id)) - { - return FALSE; - } - } - - const LLInventoryObject *obj = model->getItem(id); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - if (get_is_item_worn(id)) - { - return FALSE; - } - return TRUE; + if (!model) + { + return FALSE; + } + + // Can't delete an item that's in the library. + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } + + // Disable delete from COF folder; have users explicitly choose "detach/take off", + // unless the item is not worn but in the COF (i.e. is bugged). + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) + { + if (get_is_item_worn(id)) + { + return FALSE; + } + } + + const LLInventoryObject *obj = model->getItem(id); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } + if (get_is_item_worn(id)) + { + return FALSE; + } + return TRUE; } bool get_is_item_editable(const LLUUID& inv_item_id) { - if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) - { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - return gAgentWearables.isWearableModifiable(inv_item_id); - case LLAssetType::AT_OBJECT: - return true; - default: + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gAgentWearables.isWearableModifiable(inv_item_id); + case LLAssetType::AT_OBJECT: + return true; + default: return false;; - } - } - return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; + } + } + return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; } void handle_item_edit(const LLUUID& inv_item_id) { - if (get_is_item_editable(inv_item_id)) - { - if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) - { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - LLAgentWearables::editWearable(inv_item_id); - break; - case LLAssetType::AT_OBJECT: - handle_attachment_edit(inv_item_id); - break; - default: - break; - } - } - else - { - handle_attachment_edit(inv_item_id); - } - } + if (get_is_item_editable(inv_item_id)) + { + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + LLAgentWearables::editWearable(inv_item_id); + break; + case LLAssetType::AT_OBJECT: + handle_attachment_edit(inv_item_id); + break; + default: + break; + } + } + else + { + handle_attachment_edit(inv_item_id); + } + } } BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) { - // NOTE: This function doesn't check the folder's children. - // See LLFolderBridge::isItemRemovable for a function that does - // consider the children. + // NOTE: This function doesn't check the folder's children. + // See LLFolderBridge::isItemRemovable for a function that does + // consider the children. - if (!model) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } - if (!isAgentAvatarValid()) return FALSE; + if (!isAgentAvatarValid()) return FALSE; - const LLInventoryCategory* category = model->getCategory(id); - if (!category) - { - return FALSE; - } + const LLInventoryCategory* category = model->getCategory(id); + if (!category) + { + return FALSE; + } - const LLFolderType::EType folder_type = category->getPreferredType(); - - if (LLFolderType::lookupIsProtectedType(folder_type)) - { - return FALSE; - } + const LLFolderType::EType folder_type = category->getPreferredType(); - // Can't delete the outfit that is currently being worn. - if (folder_type == LLFolderType::FT_OUTFIT) - { - const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); - if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) - { - return FALSE; - } - } + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + return FALSE; + } - return TRUE; + // Can't delete the outfit that is currently being worn. + if (folder_type == LLFolderType::FT_OUTFIT) + { + const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) + { + return FALSE; + } + } + + return TRUE; } BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) { - if (!model) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - LLViewerInventoryCategory* cat = model->getCategory(id); + LLViewerInventoryCategory* cat = model->getCategory(id); - if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && - cat->getOwnerID() == gAgent.getID()) - { - return TRUE; - } - return FALSE; + if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && + cat->getOwnerID() == gAgent.getID()) + { + return TRUE; + } + return FALSE; } void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id) @@ -844,13 +844,13 @@ void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id) LLSD params; params["id"] = item_uuid; params["object"] = object_id; - + LLFloaterReg::showInstance("item_properties", params); } void show_item_profile(const LLUUID& item_uuid) { - LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); + LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); LLFloaterReg::showInstance("item_properties", LLSD().with("id", linked_uuid)); } @@ -877,7 +877,7 @@ void show_item_original(const LLUUID& item_uuid) LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); @@ -920,20 +920,20 @@ void show_item_original(const LLUUID& item_uuid) void reset_inventory_filter() { - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - if (sidepanel_inventory) - { - LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); - if (main_inventory) - { - main_inventory->onFilterEdit(""); - } - } + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory) + { + LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); + if (main_inventory) + { + main_inventory->onFilterEdit(""); + } + } } void open_marketplace_listings() { - LLFloaterReg::showInstance("marketplace_listings"); + LLFloaterReg::showInstance("marketplace_listings"); } ///---------------------------------------------------------------------------- @@ -960,7 +960,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid) { return -1; } - + // Iterate through the parents till we hit the marketplace listings root // Note that the marketplace listings root itself will return 0 S32 depth = 0; @@ -1062,13 +1062,13 @@ S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) } } } - + // In all other cases, the stock count is the min of stock folders count found in the descendents // "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder in the hierarchy has a count that cannot be evaluated at this time (folder not up to date) - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); + // "COMPUTE_STOCK_INFINITE" denotes a folder that doesn't countain any stock folders in its descendents S32 curr_count = COMPUTE_STOCK_INFINITE; @@ -1083,147 +1083,147 @@ S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) curr_count = count; } } - + return curr_count; } // local helper bool can_move_to_marketplace(LLInventoryItem* inv_item, std::string& tooltip_msg, bool resolve_links) { - // Collapse links directly to items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); // Linked items and folders cannot be put for sale if (linked_category || linked_item) { - tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); + tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); return false; } - + // A category is always considered as passing... if (linked_category != NULL) - { + { return true; - } - + } + // Take the linked item if necessary if (linked_item != NULL) - { - inv_item = linked_item; - } - + { + inv_item = linked_item; + } + // Check that the agent has transfer permission on the item: this is required as a resident cannot // put on sale items she cannot transfer. Proceed with move if we have permission. - bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); - if (!allow_transfer) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); - return false; - } - + bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + if (!allow_transfer) + { + tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); + return false; + } + // Check worn/not worn status: worn items cannot be put on the marketplace - bool worn = get_is_item_worn(inv_item->getUUID()); - if (worn) - { - tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); - return false; - } + bool worn = get_is_item_worn(inv_item->getUUID()); + if (worn) + { + tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); + return false; + } // Check library status: library items cannot be put on the marketplace - if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) + if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - return false; + tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + return false; } // Check type: for the moment, calling cards cannot be put on the marketplace - bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); - if (calling_card) - { - tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); - return false; - } - - return true; + bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); + if (calling_card) + { + tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); + return false; + } + + return true; } // local helper // Returns the max tree length (in folder nodes) down from the argument folder int get_folder_levels(LLInventoryCategory* inv_cat) { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - - int max_child_levels = 0; - - for (S32 i=0; i < cats->size(); ++i) - { - LLInventoryCategory* category = cats->at(i); - max_child_levels = llmax(max_child_levels, get_folder_levels(category)); - } - - return 1 + max_child_levels; + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + int max_child_levels = 0; + + for (S32 i=0; i < cats->size(); ++i) + { + LLInventoryCategory* category = cats->at(i); + max_child_levels = llmax(max_child_levels, get_folder_levels(category)); + } + + return 1 + max_child_levels; } // local helper // Returns the distance (in folder nodes) between the ancestor and its descendant. Returns -1 if not related. int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) { - int depth = 0; - - if (ancestor_id == descendant_id) return depth; - - const LLInventoryCategory* category = gInventory.getCategory(descendant_id); - - while (category) - { - LLUUID parent_id = category->getParentUUID(); - - if (parent_id.isNull()) break; - - depth++; - - if (parent_id == ancestor_id) return depth; - - category = gInventory.getCategory(parent_id); - } - - LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; - return -1; + int depth = 0; + + if (ancestor_id == descendant_id) return depth; + + const LLInventoryCategory* category = gInventory.getCategory(descendant_id); + + while (category) + { + LLUUID parent_id = category->getParentUUID(); + + if (parent_id.isNull()) break; + + depth++; + + if (parent_id == ancestor_id) return depth; + + category = gInventory.getCategory(parent_id); + } + + LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; + return -1; } // local helper // Returns true if all items within the argument folder are fit for sale, false otherwise bool has_correct_permissions_for_sale(LLInventoryCategory* cat, std::string& error_msg) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - - LLInventoryModel::item_array_t item_array_copy = *item_array; - - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + + LLInventoryModel::item_array_t item_array_copy = *item_array; + + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; if (!can_move_to_marketplace(item, error_msg, false)) { return false; } - } - - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLInventoryCategory* category = *iter; - if (!has_correct_permissions_for_sale(category, error_msg)) + } + + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + if (!has_correct_permissions_for_sale(category, error_msg)) { return false; } - } + } return true; } @@ -1246,18 +1246,18 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve { accept = can_move_to_marketplace(inv_item, tooltip_msg, true); } - + // Check that the total amount of items won't violate the max limit on the marketplace if (accept) { // If the dest folder is a stock folder, we do not count the incoming items toward the total (stock items are seen as one) int existing_item_count = (move_in_stock ? 0 : bundle_size); - + // If the dest folder is a stock folder, we do assume that the incoming items are also stock items (they should anyway) int existing_stock_count = (move_in_stock ? bundle_size : 0); - + int existing_folder_count = 0; - + // Get the version folder: that's where the counts start from const LLViewerInventoryCategory * version_folder = ((root_folder && (root_folder != dest_folder)) ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); @@ -1271,13 +1271,13 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve LLInventoryModel::cat_array_t existing_categories; LLInventoryModel::item_array_t existing_items; - + gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - + existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_stock_count += count_stock_items(existing_items); existing_folder_count += existing_categories.size(); - + // If the incoming item is a nocopy (stock) item, we need to consider that it will create a stock folder if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && !move_in_stock) { @@ -1285,7 +1285,7 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve existing_folder_count += 1; } } - + if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) { LLStringUtil::format_map_t args; @@ -1321,7 +1321,7 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size, bool check_items, bool from_paste) { bool accept = true; - + // Compute the nested folders level we'll add into with that incoming folder int incoming_folder_depth = get_folder_levels(inv_cat); // Compute the nested folders level we're inserting ourselves in @@ -1330,7 +1330,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn // Get the version folder: that's where the folders and items counts start from const LLViewerInventoryCategory * version_folder = (insertion_point_folder_depth >= 2 ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); - + // Compare the whole with the nested folders depth limit // Note: substract 2 as we leave root and version folder out of the count threshold if ((incoming_folder_depth + insertion_point_folder_depth - 2) > (S32)(gSavedSettings.getU32("InventoryOutboxMaxFolderDepth"))) @@ -1341,20 +1341,20 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels", args); accept = false; } - + if (accept) { LLInventoryModel::cat_array_t descendent_categories; LLInventoryModel::item_array_t descendent_items; gInventory.collectDescendents(inv_cat->getUUID(), descendent_categories, descendent_items, FALSE); - + int dragged_folder_count = descendent_categories.size() + bundle_size; // Note: We assume that we're moving a bunch of folders in. That might be wrong... int dragged_item_count = count_copyable_items(descendent_items) + count_stock_folders(descendent_categories); int dragged_stock_count = count_stock_items(descendent_items); int existing_item_count = 0; int existing_stock_count = 0; int existing_folder_count = 0; - + if (version_folder) { if (!from_paste && gInventory.isObjectDescendentOf(inv_cat->getUUID(), version_folder->getUUID())) @@ -1364,21 +1364,21 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn dragged_item_count = 0; dragged_stock_count = 0; } - + // Tally the total number of categories and items inside the root folder LLInventoryModel::cat_array_t existing_categories; LLInventoryModel::item_array_t existing_items; gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - + existing_folder_count += existing_categories.size(); existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_stock_count += count_stock_items(existing_items); } - + const int total_folder_count = existing_folder_count + dragged_folder_count; const int total_item_count = existing_item_count + dragged_item_count; const int total_stock_count = existing_stock_count + dragged_stock_count; - + if (total_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) { LLStringUtil::format_map_t args; @@ -1403,7 +1403,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args); accept = false; } - + // Now check that each item in the folder can be moved in the marketplace if (accept && check_items) { @@ -1418,7 +1418,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn } } } - + return accept; } @@ -1429,33 +1429,33 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol S32 depth = depth_nesting_in_marketplace(dest_folder); if (depth < 0) { - LLSD subs; - subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); - LLNotificationsUtil::add("MerchantPasteFailed", subs); + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } // We will collapse links into items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); - - if (linked_category != NULL) - { + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); + + if (linked_category != NULL) + { // Move the linked folder directly - return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); - } - else - { + return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); + } + else + { // Grab the linked item if any - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); viewer_inv_item = (linked_item != NULL ? linked_item : viewer_inv_item); - + // If we want to copy but the item is no copy, fail silently (this is a common case that doesn't warrant notification) if (copy && !viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { return false; } - + // Check that the agent has transfer permission on the item: this is required as a resident cannot // put on sale items she cannot transfer. Proceed with move if we have permission. std::string error_msg; @@ -1585,7 +1585,7 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol return false; } } - + open_marketplace_listings(); return true; } @@ -1607,7 +1607,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } - + // Get the parent folder of the moved item : we may have to update it LLUUID src_folder = inv_cat->getParentUUID(); @@ -1638,14 +1638,14 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } - + open_marketplace_listings(); return true; } bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCategory* cat2) { - return cat1->getName().compare(cat2->getName()) < 0; + return cat1->getName().compare(cat2->getName()) < 0; } // Make all relevant business logic checks on the marketplace listings starting with the folder as argument. @@ -1667,7 +1667,7 @@ void validate_marketplacelistings( { // Get the type and the depth of the folder LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat); - const LLFolderType::EType folder_type = cat->getPreferredType(); + const LLFolderType::EType folder_type = cat->getPreferredType(); if (depth < 0) { // If the depth argument was not provided, evaluate the depth directly @@ -1680,7 +1680,7 @@ void validate_marketplacelistings( depth = 1; fix_hierarchy = false; } - + // Set the indentation for print output (typically, audit button in marketplace folder floater) std::string indent; for (int i = 1; i < depth; i++) @@ -1703,7 +1703,7 @@ void validate_marketplacelistings( } } } - + // Check out that stock folders are at the right level if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth <= 2)) { @@ -1752,28 +1752,28 @@ void validate_marketplacelistings( } } } - + // Item sorting and validation : sorting and moving the various stock items is complicated as the set of constraints is high // We need to: // * separate non stock items, stock items per types in different folders // * have stock items nested at depth 2 at least // * never ever move the non-stock items - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - + + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + // We use a composite (type,permission) key on that map to store UUIDs of items of same (type,permissions) std::map<U32, std::vector<LLUUID> > items_vector; // Parse the items and create vectors of item UUIDs sorting copyable items and stock items of various types bool has_bad_items = false; - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) item; - + // Test but skip items that shouldn't be there to start with, raise an error message for those std::string error_msg; if (!can_move_to_marketplace(item, error_msg, false)) @@ -1797,13 +1797,13 @@ void validate_marketplacelistings( } U32 key = (((U32)(type) & 0xFF) << 24) | (perms & 0xFFFFFF); items_vector[key].push_back(viewer_inv_item->getUUID()); - } - + } + // How many types of items? Which type is it if only one? S32 count = items_vector.size(); U32 default_key = (U32)(LLInventoryType::IT_COUNT) << 24; // This is the key for any normal copyable item U32 unique_key = (count == 1 ? items_vector.begin()->first : default_key); // The key in the case of one item type only - + // If we have no items in there (only folders or empty), analyze a bit further if ((count == 0) && !has_bad_items) { @@ -2029,7 +2029,7 @@ void validate_marketplacelistings( } } } - + // Clean up if (viewer_cat->getDescendentCount() == 0) { @@ -2051,15 +2051,15 @@ void validate_marketplacelistings( // Recursion : Perform the same validation on each nested folder gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; // Sort the folders in alphabetical order first std::sort(cat_array_copy.begin(), cat_array_copy.end(), sort_alpha); - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLInventoryCategory* category = *iter; - validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); - } + + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); + } update_marketplace_category(cat->getUUID(), true, true); if (notify_observers) @@ -2071,22 +2071,22 @@ void validate_marketplacelistings( void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) { - LLInventoryItem* inv_item = gInventory.getItem(item_id); - if (inv_item) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); + LLInventoryItem* inv_item = gInventory.getItem(item_id); + if (inv_item) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } } void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids) @@ -2114,7 +2114,7 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { if (sidepanel_inventory->getActivePanel()) @@ -2301,7 +2301,7 @@ std::string get_localized_folder_name(LLUUID cat_uuid) LLTrans::findString(localized_root_name, std::string("InvFolder ") + cat->getName(), LLSD()); } } - + return localized_root_name; } @@ -2531,62 +2531,62 @@ LLMarketplaceValidator::ValidationRequest::ValidationRequest( // static bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryItem* item) { - if (!item) - return false; + if (!item) + return false; - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if (!get_is_item_worn(item->getUUID())) - return true; - break; - default: - return true; - break; - } - return false; + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if (!get_is_item_worn(item->getUUID())) + return true; + break; + default: + return true; + break; + } + return false; } bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return TRUE; - } - if(item) - { - if(item->getType() == mType) return TRUE; - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return TRUE; + } + if(item) + { + if(item->getType() == mType) return TRUE; + } + return FALSE; } bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return FALSE; - } - if(item) - { - if(item->getType() == mType) return FALSE; - else return TRUE; - } - return TRUE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return FALSE; + } + if(item) + { + if(item->getType() == mType) return FALSE; + else return TRUE; + } + return TRUE; } bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return TRUE; - } - if(item) - { - if(item->getActualType() == mType) return TRUE; - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return TRUE; + } + if(item) + { + if(item->getActualType() == mType) return TRUE; + } + return FALSE; } bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -2597,133 +2597,133 @@ bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryIt bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); - if (!vitem) return false; - return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem) return false; + return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); } bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) - { - return TRUE; - } - } - if(item) - { - if(item->getType() == mType) - { - LLPermissions perm = item->getPermissions(); - if ((perm.getMaskBase() & mPerm) == mPerm) - { - return TRUE; - } - } - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) + { + return TRUE; + } + } + if(item) + { + if(item->getType() == mType) + { + LLPermissions perm = item->getPermissions(); + if ((perm.getMaskBase() & mPerm) == mPerm) + { + return TRUE; + } + } + } + return FALSE; } bool LLBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (!item->getCreatorUUID().isNull()) - && (item->getCreatorUUID() != gAgent.getID())) - { - return true; - } - } - return false; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (!item->getCreatorUUID().isNull()) + && (item->getCreatorUUID() != gAgent.getID())) + { + return true; + } + } + return false; } bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (item->getCreatorUUID().notNull()) - && (item->getCreatorUUID() != gAgent.getID())) - { - mSeen.insert(item->getCreatorUUID()); - return true; - } - } - return false; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (item->getCreatorUUID().notNull()) + && (item->getCreatorUUID() != gAgent.getID())) + { + mSeen.insert(item->getCreatorUUID()); + return true; + } + } + return false; } bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (item->getCreatorUUID() == mBuddyID)) - { - return TRUE; - } - } - return FALSE; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (item->getCreatorUUID() == mBuddyID)) + { + return TRUE; + } + } + return FALSE; } bool LLNameCategoryCollector::operator()( - LLInventoryCategory* cat, LLInventoryItem* item) + LLInventoryCategory* cat, LLInventoryItem* item) { - if(cat) - { - if (!LLStringUtil::compareInsensitive(mName, cat->getName())) - { - return true; - } - } - return false; + if(cat) + { + if (!LLStringUtil::compareInsensitive(mName, cat->getName())) + { + return true; + } + } + return false; } bool LLNameItemCollector::operator()( - LLInventoryCategory* cat, LLInventoryItem* item) + LLInventoryCategory* cat, LLInventoryItem* item) { - if(item) - { - if (!LLStringUtil::compareInsensitive(mName, item->getName())) - { - return true; - } - } - return false; + if(item) + { + if (!LLStringUtil::compareInsensitive(mName, item->getName())) + { + return true; + } + } + return false; } bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - // Valid COF items are: - // - links to wearables (body parts or clothing) - // - links to attachments - // - links to gestures - // - links to ensemble folders - LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); - if (linked_item) - { - LLAssetType::EType type = linked_item->getType(); - return (type == LLAssetType::AT_CLOTHING || - type == LLAssetType::AT_BODYPART || - type == LLAssetType::AT_GESTURE || - type == LLAssetType::AT_OBJECT); - } - else - { - LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); - // BAP remove AT_NONE support after ensembles are fully working? - return (linked_category && - ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || - (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); - } + LLInventoryItem* item) +{ + // Valid COF items are: + // - links to wearables (body parts or clothing) + // - links to attachments + // - links to gestures + // - links to ensemble folders + LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); + if (linked_item) + { + LLAssetType::EType type = linked_item->getType(); + return (type == LLAssetType::AT_CLOTHING || + type == LLAssetType::AT_BODYPART || + type == LLAssetType::AT_GESTURE || + type == LLAssetType::AT_OBJECT); + } + else + { + LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); + // BAP remove AT_NONE support after ensembles are fully working? + return (linked_category && + ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || + (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); + } } bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat, @@ -2740,68 +2740,68 @@ bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat, } bool LLFindWearables::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((item->getType() == LLAssetType::AT_CLOTHING) - || (item->getType() == LLAssetType::AT_BODYPART)) - { - return TRUE; - } - } - return FALSE; + if(item) + { + if((item->getType() == LLAssetType::AT_CLOTHING) + || (item->getType() == LLAssetType::AT_BODYPART)) + { + return TRUE; + } + } + return FALSE; } LLFindWearablesEx::LLFindWearablesEx(bool is_worn, bool include_body_parts) -: mIsWorn(is_worn) -, mIncludeBodyParts(include_body_parts) +: mIsWorn(is_worn) +, mIncludeBodyParts(include_body_parts) {} bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); - if (!vitem) return false; + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem) return false; - // Skip non-wearables. - if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) - { - return false; - } + // Skip non-wearables. + if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) + { + return false; + } - // Skip body parts if requested. - if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) - { - return false; - } + // Skip body parts if requested. + if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) + { + return false; + } - // Skip broken links. - if (vitem->getIsBrokenLink()) - { - return false; - } + // Skip broken links. + if (vitem->getIsBrokenLink()) + { + return false; + } - return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; + return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; } bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if (!item) return false; - if (item->getType() != LLAssetType::AT_CLOTHING && - item->getType() != LLAssetType::AT_BODYPART) - { - return false; - } + if (!item) return false; + if (item->getType() != LLAssetType::AT_CLOTHING && + item->getType() != LLAssetType::AT_BODYPART) + { + return false; + } - LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); - if (!vitem || vitem->getWearableType() != mWearableType) return false; + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem || vitem->getWearableType() != mWearableType) return false; - return true; + return true; } void LLFindWearablesOfType::setType(LLWearableType::EType type) { - mWearableType = type; + mWearableType = type; } bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -2811,141 +2811,141 @@ bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if (item) - { - return !get_is_item_removable(&gInventory, item->getUUID()); - } - if (cat) - { - return !get_is_category_removable(&gInventory, cat->getUUID()); - } + if (item) + { + return !get_is_item_removable(&gInventory, item->getUUID()); + } + if (cat) + { + return !get_is_category_removable(&gInventory, cat->getUUID()); + } - LL_WARNS() << "Not a category and not an item?" << LL_ENDL; - return false; + LL_WARNS() << "Not a category and not an item?" << LL_ENDL; + return false; } ///---------------------------------------------------------------------------- -/// LLAssetIDMatches +/// LLAssetIDMatches ///---------------------------------------------------------------------------- bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - return (item && item->getAssetUUID() == mAssetID); + return (item && item->getAssetUUID() == mAssetID); } ///---------------------------------------------------------------------------- -/// LLLinkedItemIDMatches +/// LLLinkedItemIDMatches ///---------------------------------------------------------------------------- bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - return (item && - (item->getIsLinkType()) && - (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. + return (item && + (item->getIsLinkType()) && + (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. } void LLSaveFolderState::setApply(BOOL apply) { - mApply = apply; - // before generating new list of open folders, clear the old one - if(!apply) - { - clearOpenFolders(); - } + mApply = apply; + // before generating new list of open folders, clear the old one + if(!apply) + { + clearOpenFolders(); + } } void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getViewModelItem(); - if(!bridge) return; - - if(mApply) - { - // we're applying the open state - LLUUID id(bridge->getUUID()); - if(mOpenFolders.find(id) != mOpenFolders.end()) - { - if (!folder->isOpen()) - { - folder->setOpen(TRUE); - } - } - else - { - // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected() && folder->isOpen()) - { - folder->setOpen(FALSE); - } - } - } - else - { - // we're recording state at this point - if(folder->isOpen()) - { - mOpenFolders.insert(bridge->getUUID()); - } - } + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getViewModelItem(); + if(!bridge) return; + + if(mApply) + { + // we're applying the open state + LLUUID id(bridge->getUUID()); + if(mOpenFolders.find(id) != mOpenFolders.end()) + { + if (!folder->isOpen()) + { + folder->setOpen(TRUE); + } + } + else + { + // keep selected filter in its current state, this is less jarring to user + if (!folder->isSelected() && folder->isOpen()) + { + folder->setOpen(FALSE); + } + } + } + else + { + // we're recording state at this point + if(folder->isOpen()) + { + mOpenFolders.insert(bridge->getUUID()); + } + } } void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) { - if (item->passedFilter()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (item->passedFilter()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) { - if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - // if this folder didn't pass the filter, and none of its descendants did - else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter()) - { - folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); - } + if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + // if this folder didn't pass the filter, and none of its descendants did + else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter()) + { + folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); + } } void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) { - if (item->passedFilter() && !mItemSelected) - { - item->getRoot()->setSelection(item, FALSE, FALSE); - if (item->getParentFolder()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - mItemSelected = TRUE; - } + if (item->passedFilter() && !mItemSelected) + { + item->getRoot()->setSelection(item, FALSE, FALSE); + if (item->getParentFolder()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + mItemSelected = TRUE; + } } void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) { - // Skip if folder or item already found, if not filtered or if no parent (root folder is not selectable) - if (!mFolderSelected && !mItemSelected && folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) - { - folder->getRoot()->setSelection(folder, FALSE, FALSE); - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - mFolderSelected = TRUE; - } + // Skip if folder or item already found, if not filtered or if no parent (root folder is not selectable) + if (!mFolderSelected && !mItemSelected && folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) + { + folder->getRoot()->setSelection(folder, FALSE, FALSE); + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + mFolderSelected = TRUE; + } } void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) { - if (item->getParentFolder() && item->isSelected()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (item->getParentFolder() && item->isSelected()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) { - if (folder->getParentFolder() && folder->isSelected()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (folder->getParentFolder() && folder->isSelected()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } // Callback for doToSelected if DAMA required... @@ -2975,34 +2975,34 @@ void LLInventoryAction::callback_copySelected(const LLSD& notification, const LL // case returns their corresponding uuids. bool get_selection_object_uuids(LLFolderView *root, uuid_vec_t& ids) { - uuid_vec_t results; - S32 non_object = 0; - LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); - for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) - { - LLObjectBridge *view_model = dynamic_cast<LLObjectBridge *>((*it)->getViewModelItem()); - - if(view_model && view_model->getUUID().notNull()) - { - results.push_back(view_model->getUUID()); - } - else - { - non_object++; - } - } - if (non_object == 0) - { - ids = results; - return true; - } - return false; + uuid_vec_t results; + S32 non_object = 0; + LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); + for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + LLObjectBridge *view_model = dynamic_cast<LLObjectBridge *>((*it)->getViewModelItem()); + + if(view_model && view_model->getUUID().notNull()) + { + results.push_back(view_model->getUUID()); + } + else + { + non_object++; + } + } + if (non_object == 0) + { + ids = results; + return true; + } + return false; } void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm) { - std::set<LLFolderViewItem*> selected_items = root->getSelectionList(); + std::set<LLFolderViewItem*> selected_items = root->getSelectionList(); if (selected_items.empty() && action != "wear" && action != "wear_add" @@ -3020,9 +3020,9 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } - + // Prompt the user and check for authorization for some marketplace active listing edits - if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) + if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) { std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); LLFolderViewModelItemInventory * viewModel = NULL; @@ -3079,138 +3079,138 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } } - + // Keep track of the marketplace folders that will need update of their status/name after the operation is performed buildMarketplaceFolders(root); - - if ("rename" == action) - { - root->startRenamingSelectedItem(); + + if ("rename" == action) + { + root->startRenamingSelectedItem(); // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - return; - } - - if ("delete" == action) - { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - bool marketplacelistings_item = false; - LLAllDescendentsPassedFilter f; - for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) - { - if (LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*it)) - { - folder->applyFunctorRecursively(f); - } - LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem()); - if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) - { - marketplacelistings_item = true; - break; - } - } - // Fall through to the generic confirmation if the user choose to ignore the specialized one - if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) - { - LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); - } - else - { - if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session - { - LLNotifications::instance().setIgnored("DeleteItems", false); - sDeleteConfirmationDisplayed = true; - } - - LLSD args; - args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); - LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); - } + return; + } + + if ("delete" == action) + { + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + bool marketplacelistings_item = false; + LLAllDescendentsPassedFilter f; + for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) + { + if (LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*it)) + { + folder->applyFunctorRecursively(f); + } + LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem()); + if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) + { + marketplacelistings_item = true; + break; + } + } + // Fall through to the generic confirmation if the user choose to ignore the specialized one + if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) + { + LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } + else + { + if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session + { + LLNotifications::instance().setIgnored("DeleteItems", false); + sDeleteConfirmationDisplayed = true; + } + + LLSD args; + args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); + LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } // Note: marketplace listings will be updated in the callback if delete confirmed - return; - } - if (("copy" == action) || ("cut" == action)) - { - // Clear the clipboard before we start adding things on it - LLClipboard::instance().reset(); - } - if ("replace_links" == action) - { - LLSD params; - if (root->getSelectedCount() == 1) - { - LLFolderViewItem* folder_item = root->getSelectedItems().front(); - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); - - if (bridge) - { - LLInventoryObject* obj = bridge->getInventoryObject(); - if (obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getActualType() != LLAssetType::AT_LINK_FOLDER) - { - params = LLSD(obj->getUUID()); - } - } - } - LLFloaterReg::showInstance("linkreplace", params); - return; - } - - static const std::string change_folder_string = "change_folder_type_"; - if (action.length() > change_folder_string.length() && - (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) - { - LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); - LLFolderViewModelItemInventory* inventory_item = static_cast<LLFolderViewModelItemInventory*>(root->getViewModelItem()); - LLViewerInventoryCategory *cat = model->getCategory(inventory_item->getUUID()); - if (!cat) return; - cat->changeType(new_folder_type); + return; + } + if (("copy" == action) || ("cut" == action)) + { + // Clear the clipboard before we start adding things on it + LLClipboard::instance().reset(); + } + if ("replace_links" == action) + { + LLSD params; + if (root->getSelectedCount() == 1) + { + LLFolderViewItem* folder_item = root->getSelectedItems().front(); + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); + + if (bridge) + { + LLInventoryObject* obj = bridge->getInventoryObject(); + if (obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getActualType() != LLAssetType::AT_LINK_FOLDER) + { + params = LLSD(obj->getUUID()); + } + } + } + LLFloaterReg::showInstance("linkreplace", params); + return; + } + + static const std::string change_folder_string = "change_folder_type_"; + if (action.length() > change_folder_string.length() && + (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) + { + LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); + LLFolderViewModelItemInventory* inventory_item = static_cast<LLFolderViewModelItemInventory*>(root->getViewModelItem()); + LLViewerInventoryCategory *cat = model->getCategory(inventory_item->getUUID()); + if (!cat) return; + cat->changeType(new_folder_type); // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - return; - } - - - LLMultiPreview* multi_previewp = NULL; - LLMultiItemProperties* multi_itempropertiesp = nullptr; - - if (("task_open" == action || "open" == action) && selected_items.size() > 1) - { - bool open_multi_preview = true; - - if ("open" == action) - { - for (std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) - { - LLFolderViewItem* folder_item = *set_iter; - if (folder_item) - { - LLInvFVBridge* bridge = dynamic_cast<LLInvFVBridge*>(folder_item->getViewModelItem()); - if (!bridge || !bridge->isMultiPreviewAllowed()) - { - open_multi_preview = false; - break; - } - } - } - } - - if (open_multi_preview) - { - multi_previewp = new LLMultiPreview(); - gFloaterView->addChild(multi_previewp); - - LLFloater::setFloaterHost(multi_previewp); - } - - } - else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) - { - multi_itempropertiesp = new LLMultiItemProperties("item_properties"); - gFloaterView->addChild(multi_itempropertiesp); - LLFloater::setFloaterHost(multi_itempropertiesp); - } - - std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); + return; + } + + + LLMultiPreview* multi_previewp = NULL; + LLMultiItemProperties* multi_itempropertiesp = nullptr; + + if (("task_open" == action || "open" == action) && selected_items.size() > 1) + { + bool open_multi_preview = true; + + if ("open" == action) + { + for (std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewItem* folder_item = *set_iter; + if (folder_item) + { + LLInvFVBridge* bridge = dynamic_cast<LLInvFVBridge*>(folder_item->getViewModelItem()); + if (!bridge || !bridge->isMultiPreviewAllowed()) + { + open_multi_preview = false; + break; + } + } + } + } + + if (open_multi_preview) + { + multi_previewp = new LLMultiPreview(); + gFloaterView->addChild(multi_previewp); + + LLFloater::setFloaterHost(multi_previewp); + } + + } + else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) + { + multi_itempropertiesp = new LLMultiItemProperties("item_properties"); + gFloaterView->addChild(multi_itempropertiesp); + LLFloater::setFloaterHost(multi_itempropertiesp); + } + + std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); // copy list of applicable items into a vector for bulk handling uuid_vec_t ids; @@ -3307,10 +3307,10 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } } - + LLSD args; args["DESC"] = LLTrans::getString("New Folder"); - + LLNotificationsUtil::add("CreateSubfolder", args, LLSD(), [ids](const LLSD& notification, const LLSD& response) { @@ -3358,22 +3358,22 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - - LLFloater::setFloaterHost(NULL); - if (multi_previewp) - { - multi_previewp->openFloater(LLSD()); - } - else if (multi_itempropertiesp) - { - multi_itempropertiesp->openFloater(LLSD()); - } + + LLFloater::setFloaterHost(NULL); + if (multi_previewp) + { + multi_previewp->openFloater(LLSD()); + } + else if (multi_itempropertiesp) + { + multi_itempropertiesp->openFloater(LLSD()); + } } void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model) { gSavedSettings.setString("TextureSaveLocation", filenames[0]); - + LLMultiPreview* multi_previewp = new LLMultiPreview(); gFloaterView->addChild(multi_previewp); @@ -3381,7 +3381,7 @@ void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& fil std::map<std::string, S32> tex_names_map; std::set<LLFolderViewItem*>::iterator set_iter; - + for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) { LLFolderViewItem* folder_item = *set_iter; @@ -3390,10 +3390,10 @@ void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& fil if(!bridge) continue; std::string tex_name = bridge->getName(); - if(!tex_names_map.insert(std::pair<std::string, S32>(tex_name, 0)).second) - { + if(!tex_names_map.insert(std::pair<std::string, S32>(tex_name, 0)).second) + { tex_names_map[tex_name]++; - bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); + bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); } bridge->performAction(model, "save_selected_as"); } @@ -3430,18 +3430,18 @@ void LLInventoryAction::removeItemFromDND(LLFolderView* root) void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0 && !root.isDead() && !root.get()->isDead()) - { - LLFolderView* folder_root = root.get(); - //Need to remove item from DND before item is removed from root folder view - //because once removed from root folder view the item is no longer a selected item - removeItemFromDND(folder_root); - folder_root->removeSelectedItems(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0 && !root.isDead() && !root.get()->isDead()) + { + LLFolderView* folder_root = root.get(); + //Need to remove item from DND before item is removed from root folder view + //because once removed from root folder view the item is no longer a selected item + removeItemFromDND(folder_root); + folder_root->removeSelectedItems(); - // Update the marketplace listings that have been affected by the operation - updateMarketplaceFolders(); - } + // Update the marketplace listings that have been affected by the operation + updateMarketplaceFolders(); + } } void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) @@ -3457,7 +3457,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.isNull()) { - return; + return; } std::set<LLFolderViewItem*> selected_items = root->getSelectionList(); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index edc83147f2..8edb51b5a8 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -1,4 +1,4 @@ -/** +/** * @file llinventoryfunctions.h * @brief Miscellaneous inventory-related functions and classes * class definition @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -184,10 +184,10 @@ private: class LLInventoryCollectFunctor { public: - virtual ~LLInventoryCollectFunctor(){}; - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; + virtual ~LLInventoryCollectFunctor(){}; + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; - static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); + static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -200,12 +200,12 @@ class LLViewerInventoryItem; class LLAssetIDMatches : public LLInventoryCollectFunctor { public: - LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} - virtual ~LLAssetIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - + LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} + virtual ~LLAssetIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + protected: - LLUUID mAssetID; + LLUUID mAssetID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -217,12 +217,12 @@ protected: class LLLinkedItemIDMatches : public LLInventoryCollectFunctor { public: - LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} - virtual ~LLLinkedItemIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - + LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} + virtual ~LLLinkedItemIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + protected: - LLUUID mBaseItemID; + LLUUID mBaseItemID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -235,12 +235,12 @@ protected: class LLIsType : public LLInventoryCollectFunctor { public: - LLIsType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -252,12 +252,12 @@ protected: class LLIsNotType : public LLInventoryCollectFunctor { public: - LLIsNotType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsNotType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsNotType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsNotType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -271,12 +271,12 @@ protected: class LLIsOfAssetType : public LLInventoryCollectFunctor { public: - LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsOfAssetType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsOfAssetType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -304,23 +304,23 @@ protected: class LLIsValidItemLink : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; class LLIsTypeWithPermissions : public LLInventoryCollectFunctor { public: - LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) - : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} - virtual ~LLIsTypeWithPermissions() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) + : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} + virtual ~LLIsTypeWithPermissions() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; - PermissionBit mPerm; - LLUUID mAgentID; - LLUUID mGroupID; + LLAssetType::EType mType; + PermissionBit mPerm; + LLUUID mAgentID; + LLUUID mGroupID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -332,10 +332,10 @@ protected: class LLBuddyCollector : public LLInventoryCollectFunctor { public: - LLBuddyCollector() {} - virtual ~LLBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLBuddyCollector() {} + virtual ~LLBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -347,13 +347,13 @@ public: class LLUniqueBuddyCollector : public LLInventoryCollectFunctor { public: - LLUniqueBuddyCollector() {} - virtual ~LLUniqueBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLUniqueBuddyCollector() {} + virtual ~LLUniqueBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::set<LLUUID> mSeen; + std::set<LLUUID> mSeen; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -365,12 +365,12 @@ protected: class LLParticularBuddyCollector : public LLInventoryCollectFunctor { public: - LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} - virtual ~LLParticularBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} + virtual ~LLParticularBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLUUID mBuddyID; + LLUUID mBuddyID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -381,12 +381,12 @@ protected: class LLNameCategoryCollector : public LLInventoryCollectFunctor { public: - LLNameCategoryCollector(const std::string& name) : mName(name) {} - virtual ~LLNameCategoryCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLNameCategoryCollector(const std::string& name) : mName(name) {} + virtual ~LLNameCategoryCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::string mName; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -397,12 +397,12 @@ protected: class LLNameItemCollector : public LLInventoryCollectFunctor { public: - LLNameItemCollector(const std::string& name) : mName(name) {} - virtual ~LLNameItemCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLNameItemCollector(const std::string& name) : mName(name) {} + virtual ~LLNameItemCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::string mName; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -413,11 +413,11 @@ protected: class LLFindCOFValidItems : public LLInventoryCollectFunctor { public: - LLFindCOFValidItems() {} - virtual ~LLFindCOFValidItems() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - + LLFindCOFValidItems() {} + virtual ~LLFindCOFValidItems() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -440,23 +440,23 @@ public: class LLFindByMask : public LLInventoryCollectFunctor { public: - LLFindByMask(U64 mask) - : mFilterMask(mask) - {} + LLFindByMask(U64 mask) + : mFilterMask(mask) + {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - //converting an inventory type to a bitmap filter mask - if(item && (mFilterMask & (1LL << item->getInventoryType())) ) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + //converting an inventory type to a bitmap filter mask + if(item && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } - return false; - } + return false; + } private: - U64 mFilterMask; + U64 mFilterMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -467,27 +467,27 @@ private: class LLFindNonLinksByMask : public LLInventoryCollectFunctor { public: - LLFindNonLinksByMask(U64 mask) - : mFilterMask(mask) - {} + LLFindNonLinksByMask(U64 mask) + : mFilterMask(mask) + {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } - return false; - } + return false; + } - void setFilterMask(U64 mask) - { - mFilterMask = mask; - } + void setFilterMask(U64 mask) + { + mFilterMask = mask; + } private: - U64 mFilterMask; + U64 mFilterMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -498,10 +498,10 @@ private: class LLFindWearables : public LLInventoryCollectFunctor { public: - LLFindWearables() {} - virtual ~LLFindWearables() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLFindWearables() {} + virtual ~LLFindWearables() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -512,24 +512,24 @@ public: class LLFindWearablesEx : public LLInventoryCollectFunctor { public: - LLFindWearablesEx(bool is_worn, bool include_body_parts = true); - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + LLFindWearablesEx(bool is_worn, bool include_body_parts = true); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); private: - bool mIncludeBodyParts; - bool mIsWorn; + bool mIncludeBodyParts; + bool mIsWorn; }; //Inventory collect functor collecting wearables of a specific wearable type class LLFindWearablesOfType : public LLInventoryCollectFunctor { public: - LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} - virtual ~LLFindWearablesOfType() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - void setType(LLWearableType::EType type); + LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} + virtual ~LLFindWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + void setType(LLWearableType::EType type); private: - LLWearableType::EType mWearableType; + LLWearableType::EType mWearableType; }; class LLIsTextureType : public LLInventoryCollectFunctor @@ -545,33 +545,33 @@ public: class LLFindActualWearablesOfType : public LLFindWearablesOfType { public: - LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} - virtual ~LLFindActualWearablesOfType() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if (item && item->getIsLinkType()) return false; - return LLFindWearablesOfType::operator()(cat, item); - } + LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} + virtual ~LLFindActualWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLFindWearablesOfType::operator()(cat, item); + } }; /* Filters out items of a particular asset type */ class LLIsTypeActual : public LLIsType { public: - LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} - virtual ~LLIsTypeActual() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if (item && item->getIsLinkType()) return false; - return LLIsType::operator()(cat, item); - } + LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} + virtual ~LLIsTypeActual() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLIsType::operator()(cat, item); + } }; // Collect non-removable folders and items. class LLFindNonRemovableObjects : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); }; /** Inventory Collector Functions @@ -585,27 +585,27 @@ class LLFolderView; class LLInventoryState { public: - // HACK: Until we can route this info through the instant message hierarchy - static BOOL sWearNewClothing; - static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction + // HACK: Until we can route this info through the instant message hierarchy + static BOOL sWearNewClothing; + static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction }; struct LLInventoryAction { - static void doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm = TRUE); - static void callback_doToSelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); - static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); - static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root); - static void removeItemFromDND(LLFolderView* root); + static void doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm = TRUE); + static void callback_doToSelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); + static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); + static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root); + static void removeItemFromDND(LLFolderView* root); static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model); static bool sDeleteConfirmationDisplayed; private: - static void buildMarketplaceFolders(LLFolderView* root); - static void updateMarketplaceFolders(); - static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed + static void buildMarketplaceFolders(LLFolderView* root); + static void updateMarketplaceFolders(); + static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed }; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 3a930684a4..6408d4eaf6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llinventorymodel.cpp * @brief Implementation of the inventory model used to track agent inventory. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,7 +50,7 @@ #include "llwindow.h" #include "llviewercontrol.h" #include "llviewernetwork.h" -#include "llpreview.h" +#include "llpreview.h" #include "llviewergenericmessage.h" #include "llviewermessage.h" #include "llviewerfoldertype.h" @@ -94,49 +94,49 @@ static const char * const LOG_INV("Inventory"); struct InventoryIDPtrLess { - bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const - { - return (i1->getUUID() < i2->getUUID()); - } + bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const + { + return (i1->getUUID() < i2->getUUID()); + } }; -class LLCanCache : public LLInventoryCollectFunctor +class LLCanCache : public LLInventoryCollectFunctor { public: - LLCanCache(LLInventoryModel* model) : mModel(model) {} - virtual ~LLCanCache() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + LLCanCache(LLInventoryModel* model) : mModel(model) {} + virtual ~LLCanCache() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); protected: - LLInventoryModel* mModel; - std::set<LLUUID> mCachedCatIDs; + LLInventoryModel* mModel; + std::set<LLUUID> mCachedCatIDs; }; bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - bool rv = false; - if(item) - { - if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) - { - rv = true; - } - } - else if(cat) - { - // HACK: downcast - LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; - if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = c->getDescendentCount(); - S32 descendents_actual = c->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - mCachedCatIDs.insert(c->getUUID()); - rv = true; - } - } - } - return rv; + bool rv = false; + if(item) + { + if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) + { + rv = true; + } + } + else if(cat) + { + // HACK: downcast + LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; + if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + S32 descendents_server = c->getDescendentCount(); + S32 descendents_actual = c->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + mCachedCatIDs.insert(c->getUUID()); + rv = true; + } + } + } + return rv; } struct InventoryCallbackInfo @@ -364,7 +364,7 @@ LLInventoryValidationInfo::LLInventoryValidationInfo() void LLInventoryValidationInfo::toOstream(std::ostream& os) const { - os << "mFatalErrorCount " << mFatalErrorCount + os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount << " mLoopCount " << mLoopCount << " mOrphanedCount " << mOrphanedCount; @@ -373,52 +373,52 @@ void LLInventoryValidationInfo::toOstream(std::ostream& os) const std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) { - v.toOstream(os); - return os; + v.toOstream(os); + return os; } void LLInventoryValidationInfo::asLLSD(LLSD& sd) const { - sd["fatal_error_count"] = mFatalErrorCount; + sd["fatal_error_count"] = mFatalErrorCount; sd["loop_count"] = mLoopCount; sd["orphaned_count"] = mOrphanedCount; - sd["initialized"] = mInitialized; - sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); - sd["fatal_no_root_folder"] = mFatalNoRootFolder; - sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder; - sd["fatal_qa_debug_mode"] = mFatalQADebugMode; - - sd["warning_count"] = mWarningCount; - if (mWarningCount>0) - { - sd["warnings"] = LLSD::emptyArray(); - for (auto const& it : mWarnings) - { - S32 val =LLSD::Integer(it.second); - if (val>0) - { - sd["warnings"][it.first] = val; - } - } - } - if (mMissingRequiredSystemFolders.size()>0) - { - sd["missing_system_folders"] = LLSD::emptyArray(); - for(auto ft: mMissingRequiredSystemFolders) - { - sd["missing_system_folders"].append(LLFolderType::lookup(ft)); - } - } - sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); - if (mDuplicateRequiredSystemFolders.size()>0) - { - sd["duplicate_system_folders"] = LLSD::emptyArray(); - for(auto ft: mDuplicateRequiredSystemFolders) - { - sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); - } - } - + sd["initialized"] = mInitialized; + sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); + sd["fatal_no_root_folder"] = mFatalNoRootFolder; + sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder; + sd["fatal_qa_debug_mode"] = mFatalQADebugMode; + + sd["warning_count"] = mWarningCount; + if (mWarningCount>0) + { + sd["warnings"] = LLSD::emptyArray(); + for (auto const& it : mWarnings) + { + S32 val =LLSD::Integer(it.second); + if (val>0) + { + sd["warnings"][it.first] = val; + } + } + } + if (mMissingRequiredSystemFolders.size()>0) + { + sd["missing_system_folders"] = LLSD::emptyArray(); + for(auto ft: mMissingRequiredSystemFolders) + { + sd["missing_system_folders"].append(LLFolderType::lookup(ft)); + } + } + sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); + if (mDuplicateRequiredSystemFolders.size()>0) + { + sd["duplicate_system_folders"] = LLSD::emptyArray(); + for(auto ft: mDuplicateRequiredSystemFolders) + { + sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); + } + } + } ///---------------------------------------------------------------------------- @@ -431,117 +431,117 @@ LLInventoryModel gInventory; // Default constructor LLInventoryModel::LLInventoryModel() : // These are now ordered, keep them that way. - mBacklinkMMap(), - mIsAgentInvUsable(false), - mRootFolderID(), - mLibraryRootFolderID(), - mLibraryOwnerID(), - mCategoryMap(), - mItemMap(), - mParentChildCategoryTree(), - mParentChildItemTree(), - mLastItem(NULL), - mIsNotifyObservers(FALSE), - mModifyMask(LLInventoryObserver::ALL), - mChangedItemIDs(), + mBacklinkMMap(), + mIsAgentInvUsable(false), + mRootFolderID(), + mLibraryRootFolderID(), + mLibraryOwnerID(), + mCategoryMap(), + mItemMap(), + mParentChildCategoryTree(), + mParentChildItemTree(), + mLastItem(NULL), + mIsNotifyObservers(FALSE), + mModifyMask(LLInventoryObserver::ALL), + mChangedItemIDs(), mBulkFecthCallbackSlot(), - mObservers(), - mHttpRequestFG(NULL), - mHttpRequestBG(NULL), - mHttpOptions(), - mHttpHeaders(), - mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mCategoryLock(), - mItemLock(), - mValidationInfo(new LLInventoryValidationInfo) + mObservers(), + mHttpRequestFG(NULL), + mHttpRequestBG(NULL), + mHttpOptions(), + mHttpHeaders(), + mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mCategoryLock(), + mItemLock(), + mValidationInfo(new LLInventoryValidationInfo) {} // Destroys the object LLInventoryModel::~LLInventoryModel() { - cleanupInventory(); + cleanupInventory(); } void LLInventoryModel::cleanupInventory() { - empty(); - // Deleting one observer might erase others from the list, so always pop off the front - while (!mObservers.empty()) - { - observer_list_t::iterator iter = mObservers.begin(); - LLInventoryObserver* observer = *iter; - mObservers.erase(iter); - delete observer; - } + empty(); + // Deleting one observer might erase others from the list, so always pop off the front + while (!mObservers.empty()) + { + observer_list_t::iterator iter = mObservers.begin(); + LLInventoryObserver* observer = *iter; + mObservers.erase(iter); + delete observer; + } if (mBulkFecthCallbackSlot.connected()) { mBulkFecthCallbackSlot.disconnect(); } - mObservers.clear(); + mObservers.clear(); - // Run down HTTP transport + // Run down HTTP transport mHttpHeaders.reset(); mHttpOptions.reset(); - delete mHttpRequestFG; - mHttpRequestFG = NULL; - delete mHttpRequestBG; - mHttpRequestBG = NULL; + delete mHttpRequestFG; + mHttpRequestFG = NULL; + delete mHttpRequestBG; + mHttpRequestBG = NULL; } // This is a convenience function to check if one object has a parent // chain up to the category specified by UUID. BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, - const LLUUID& cat_id) const + const LLUUID& cat_id) const { - if (obj_id == cat_id) return TRUE; - - const LLInventoryObject* obj = getObject(obj_id); - while(obj) - { - const LLUUID& parent_id = obj->getParentUUID(); - if( parent_id.isNull() ) - { - return FALSE; - } - if(parent_id == cat_id) - { - return TRUE; - } - // Since we're scanning up the parents, we only need to check - // in the category list. - obj = getCategory(parent_id); - } - return FALSE; + if (obj_id == cat_id) return TRUE; + + const LLInventoryObject* obj = getObject(obj_id); + while(obj) + { + const LLUUID& parent_id = obj->getParentUUID(); + if( parent_id.isNull() ) + { + return FALSE; + } + if(parent_id == cat_id) + { + return TRUE; + } + // Since we're scanning up the parents, we only need to check + // in the category list. + obj = getCategory(parent_id); + } + return FALSE; } const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const { - const LLInventoryObject* obj = getObject(obj_id); - if(!obj) - { - LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; - return NULL; - } - // Search up the parent chain until we get to root or an acceptable folder. - // This assumes there are no cycles in the tree else we'll get a hang. - LLUUID parent_id = obj->getParentUUID(); - while (!parent_id.isNull()) - { - const LLViewerInventoryCategory *cat = getCategory(parent_id); - if (!cat) break; - const LLFolderType::EType folder_type = cat->getPreferredType(); - if (folder_type != LLFolderType::FT_NONE && - folder_type != LLFolderType::FT_ROOT_INVENTORY && - !LLFolderType::lookupIsEnsembleType(folder_type)) - { - return cat; - } - parent_id = cat->getParentUUID(); - } - return NULL; + const LLInventoryObject* obj = getObject(obj_id); + if(!obj) + { + LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; + return NULL; + } + // Search up the parent chain until we get to root or an acceptable folder. + // This assumes there are no cycles in the tree else we'll get a hang. + LLUUID parent_id = obj->getParentUUID(); + while (!parent_id.isNull()) + { + const LLViewerInventoryCategory *cat = getCategory(parent_id); + if (!cat) break; + const LLFolderType::EType folder_type = cat->getPreferredType(); + if (folder_type != LLFolderType::FT_NONE && + folder_type != LLFolderType::FT_ROOT_INVENTORY && + !LLFolderType::lookupIsEnsembleType(folder_type)) + { + return cat; + } + parent_id = cat->getParentUUID(); + } + return NULL; } // @@ -549,36 +549,36 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons // const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const { - if (master_parent_id == obj_id) - { - return NULL; - } - - const LLViewerInventoryCategory* current_cat = getCategory(obj_id); - - if (current_cat == NULL) - { - current_cat = getCategory(getObject(obj_id)->getParentUUID()); - } - - while (current_cat != NULL) - { - const LLUUID& current_parent_id = current_cat->getParentUUID(); - - if (current_parent_id == master_parent_id) - { - return current_cat; - } - - current_cat = getCategory(current_parent_id); - } - - return NULL; + if (master_parent_id == obj_id) + { + return NULL; + } + + const LLViewerInventoryCategory* current_cat = getCategory(obj_id); + + if (current_cat == NULL) + { + current_cat = getCategory(getObject(obj_id)->getParentUUID()); + } + + while (current_cat != NULL) + { + const LLUUID& current_parent_id = current_cat->getParentUUID(); + + if (current_parent_id == master_parent_id) + { + return current_cat; + } + + current_cat = getCategory(current_parent_id); + } + + return NULL; } LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const { - LLInventoryObject *object = getObject(object_id); + LLInventoryObject *object = getObject(object_id); if (!object) { LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL; @@ -596,73 +596,73 @@ LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(con } object_ids.insert(parent_id); LLInventoryObject *parent_object = getObject(parent_id); - if (!parent_object) - { - LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; - return ANCESTOR_MISSING; - } - object = parent_object; - } - result = object->getUUID(); - return ANCESTOR_OK; + if (!parent_object) + { + LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; + return ANCESTOR_MISSING; + } + object = parent_object; + } + result = object->getUUID(); + return ANCESTOR_OK; } // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { - LLViewerInventoryCategory* cat = getCategory(id); - if (cat) - { - return cat; - } - LLViewerInventoryItem* item = getItem(id); - if (item) - { - return item; - } - return NULL; + LLViewerInventoryCategory* cat = getCategory(id); + if (cat) + { + return cat; + } + LLViewerInventoryItem* item = getItem(id); + if (item) + { + return item; + } + return NULL; } // Get the item by id. Returns NULL if not found. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const { - LLViewerInventoryItem* item = NULL; - if(mLastItem.notNull() && mLastItem->getUUID() == id) - { - item = mLastItem; - } - else - { - item_map_t::const_iterator iter = mItemMap.find(id); - if (iter != mItemMap.end()) - { - item = iter->second; - mLastItem = item; - } - } - return item; + LLViewerInventoryItem* item = NULL; + if(mLastItem.notNull() && mLastItem->getUUID() == id) + { + item = mLastItem; + } + else + { + item_map_t::const_iterator iter = mItemMap.find(id); + if (iter != mItemMap.end()) + { + item = iter->second; + mLastItem = item; + } + } + return item; } // Get the category by id. Returns NULL if not found LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const { - LLViewerInventoryCategory* category = NULL; - cat_map_t::const_iterator iter = mCategoryMap.find(id); - if (iter != mCategoryMap.end()) - { - category = iter->second; - } - return category; + LLViewerInventoryCategory* category = NULL; + cat_map_t::const_iterator iter = mCategoryMap.find(id); + if (iter != mCategoryMap.end()) + { + category = iter->second; + } + return category; } S32 LLInventoryModel::getItemCount() const { - return mItemMap.size(); + return mItemMap.size(); } S32 LLInventoryModel::getCategoryCount() const { - return mCategoryMap.size(); + return mCategoryMap.size(); } // Return the direct descendents of the id provided. The array @@ -671,11 +671,11 @@ S32 LLInventoryModel::getCategoryCount() const // may invalidate the internal state of the inventory. Set passed // in values to NULL if the call fails. void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, - cat_array_t*& categories, - item_array_t*& items) const + cat_array_t*& categories, + item_array_t*& items) const { - categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); - items = get_ptr_in_map(mParentChildItemTree, cat_id); + categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); + items = get_ptr_in_map(mParentChildItemTree, cat_id); } void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const @@ -684,10 +684,10 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& { for (LLViewerInventoryCategory* pFolder : *categoriesp) { - if (f(pFolder, nullptr)) - { - categories.push_back(pFolder); - } + if (f(pFolder, nullptr)) + { + categories.push_back(pFolder); + } } } @@ -695,56 +695,56 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& { for (LLViewerInventoryItem* pItem : *itemsp) { - if (f(nullptr, pItem)) - { - items.push_back(pItem); - } + if (f(nullptr, pItem)) + { + items.push_back(pItem); + } } } } LLInventoryModel::digest_t LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - getDirectDescendentsOf(cat_id,cat_array,item_array); - if (!item_array) - { - return LLUUID::null; - } - HBXXH128 item_name_hash; - for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); - iter != item_array->end(); - iter++) - { - const LLViewerInventoryItem *item = (*iter); - if (!item) - continue; - item_name_hash.update(item->getName()); - } - return item_name_hash.digest(); + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + getDirectDescendentsOf(cat_id,cat_array,item_array); + if (!item_array) + { + return LLUUID::null; + } + HBXXH128 item_name_hash; + for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); + iter != item_array->end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + if (!item) + continue; + item_name_hash.update(item->getName()); + } + return item_name_hash.digest(); } // SJB: Added version to lock the arrays to catch potential logic bugs void LLInventoryModel::lockDirectDescendentArrays(const LLUUID& cat_id, - cat_array_t*& categories, - item_array_t*& items) + cat_array_t*& categories, + item_array_t*& items) { - getDirectDescendentsOf(cat_id, categories, items); - if (categories) - { - mCategoryLock[cat_id] = true; - } - if (items) - { - mItemLock[cat_id] = true; - } + getDirectDescendentsOf(cat_id, categories, items); + if (categories) + { + mCategoryLock[cat_id] = true; + } + if (items) + { + mItemLock[cat_id] = true; + } } void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) { - mCategoryLock[cat_id] = false; - mItemLock[cat_id] = false; + mCategoryLock[cat_id] = false; + mItemLock[cat_id] = false; } void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::EType type) @@ -761,15 +761,15 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } // Iterate through those folders - for (std::vector<LLUUID>::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) - { - LLUUID folder_id = (*folder_ids_it); - + for (std::vector<LLUUID>::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) + { + LLUUID folder_id = (*folder_ids_it); + // Get the content of this folder cat_array_t* cats; item_array_t* items; getDirectDescendentsOf(folder_id, cats, items); - + // Move all items to the main folder // Note : we get the list of UUIDs and iterate on them instead of iterating directly on item_array_t // elements. This is because moving elements modify the maps and, consequently, invalidate iterators on them. @@ -809,7 +809,7 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } } remove_inventory_category(folder_id, NULL); - } + } } void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type) @@ -881,49 +881,49 @@ void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred } const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( - LLFolderType::EType preferred_type, - const LLUUID& root_id) const + LLFolderType::EType preferred_type, + const LLUUID& root_id) const { - LLUUID rv = LLUUID::null; - if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) - { - rv = root_id; - } - else if (root_id.notNull()) - { - cat_array_t* cats = NULL; - cats = get_ptr_in_map(mParentChildCategoryTree, root_id); - if(cats) - { - S32 count = cats->size(); - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* p_cat = cats->at(i); - if(p_cat && p_cat->getPreferredType() == preferred_type) - { - const LLUUID& folder_id = cats->at(i)->getUUID(); - if (rv.isNull() || folder_id < rv) - { - rv = folder_id; - } - } - } - } - } - - if(rv.isNull() + LLUUID rv = LLUUID::null; + if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) + { + rv = root_id; + } + else if (root_id.notNull()) + { + cat_array_t* cats = NULL; + cats = get_ptr_in_map(mParentChildCategoryTree, root_id); + if(cats) + { + S32 count = cats->size(); + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* p_cat = cats->at(i); + if(p_cat && p_cat->getPreferredType() == preferred_type) + { + const LLUUID& folder_id = cats->at(i)->getUUID(); + if (rv.isNull() || folder_id < rv) + { + rv = folder_id; + } + } + } + } + } + + if(rv.isNull() && root_id.notNull() && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS && preferred_type != LLFolderType::FT_OUTBOX) - { + { // if it does not exists, it should either be added // to createCommonSystemCategories or server should // have set it llassert(!isInventoryUsable()); LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type - << " but category does not exist" << LL_ENDL; - } - return rv; + << " but category does not exist" << LL_ENDL; + } + return rv; } // findCategoryUUIDForType() returns the uuid of the category that @@ -932,7 +932,7 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( // inventory category on the fly if one does not exist. const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); } const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const @@ -968,7 +968,7 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: default: break; } - + if (cat_id.isNull() || !getCategory(cat_id)) { cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID()); @@ -978,7 +978,7 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); } // Convenience function to create a new category. You could call @@ -986,56 +986,56 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp // version will take care of details like what the name should be // based on preferred type. void LLInventoryModel::createNewCategory(const LLUUID& parent_id, - LLFolderType::EType preferred_type, - const std::string& pname, - inventory_func_type callback, - const LLUUID& thumbnail_id) + LLFolderType::EType preferred_type, + const std::string& pname, + inventory_func_type callback, + const LLUUID& thumbnail_id) { - LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; - if (!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " - << preferred_type << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; + if (!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " + << preferred_type << LL_ENDL; if (callback) { callback(LLUUID::null); } - return; - } + return; + } - if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) - { - LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; + if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) + { + LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; if (callback) { callback(LLUUID::null); } - return; - } - - if (preferred_type != LLFolderType::FT_NONE) - { - // Ultimately this should only be done for non-singleton - // types. Requires back-end changes to guarantee that others - // already exist. - LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; - } - - std::string name = pname; - if (pname.empty()) - { - name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); - } - - if (AISAPI::isAvailable()) - { - LLSD new_inventory = LLSD::emptyMap(); - new_inventory["categories"] = LLSD::emptyArray(); - LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); + return; + } + + if (preferred_type != LLFolderType::FT_NONE) + { + // Ultimately this should only be done for non-singleton + // types. Requires back-end changes to guarantee that others + // already exist. + LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; + } + + std::string name = pname; + if (pname.empty()) + { + name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); + } + + if (AISAPI::isAvailable()) + { + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["categories"] = LLSD::emptyArray(); + LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); cat.setThumbnailUUID(thumbnail_id); - LLSD cat_sd = cat.asAISCreateCatLLSD(); - new_inventory["categories"].append(cat_sd); - AISAPI::CreateInventory( + LLSD cat_sd = cat.asAISCreateCatLLSD(); + new_inventory["categories"].append(cat_sd); + AISAPI::CreateInventory( parent_id, new_inventory, [this, callback, parent_id, preferred_type, name] (const LLUUID& new_category) @@ -1075,32 +1075,32 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, } }); return; - } - - LLViewerRegion* viewer_region = gAgent.getRegion(); - std::string url; - if ( viewer_region ) - url = viewer_region->getCapability("CreateInventoryCategory"); - - if (!url.empty()) - { - //Let's use the new capability. + } + + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty()) + { + //Let's use the new capability. LLUUID id; - id.generate(); - LLSD request, body; - body["folder_id"] = id; - body["parent_id"] = parent_id; - body["type"] = (LLSD::Integer) preferred_type; - body["name"] = name; - - request["message"] = "CreateInventoryCategory"; - request["payload"] = body; - - LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; + id.generate(); + LLSD request, body; + body["folder_id"] = id; + body["parent_id"] = parent_id; + body["type"] = (LLSD::Integer) preferred_type; + body["name"] = name; + + request["message"] = "CreateInventoryCategory"; + request["payload"] = body; + + LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); return; - } + } if (callback) { @@ -1115,7 +1115,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("createNewCategoryCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - + httpOpts->setWantHeaders(true); @@ -1213,36 +1213,36 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv // category has any immediate children meeting a condition, without // needing to recurse or build up any lists. bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, - LLInventoryCollectFunctor& filter) + LLInventoryCollectFunctor& filter) { - LLInventoryModel::cat_array_t *cats; - LLInventoryModel::item_array_t *items; - getDirectDescendentsOf(cat_id, cats, items); - if (cats) - { - for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); - it != cats->end(); ++it) - { - if (filter(*it,NULL)) - { - return true; - } - } - } - if (items) - { - for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); - it != items->end(); ++it) - { - if (filter(NULL,*it)) - { - return true; - } - } - } - return false; + LLInventoryModel::cat_array_t *cats; + LLInventoryModel::item_array_t *items; + getDirectDescendentsOf(cat_id, cats, items); + if (cats) + { + for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); + it != cats->end(); ++it) + { + if (filter(*it,NULL)) + { + return true; + } + } + } + if (items) + { + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); + it != items->end(); ++it) + { + if (filter(NULL,*it)) + { + return true; + } + } + } + return false; } - + // Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified by // id. There is no guaranteed order. Neither array will be erased @@ -1253,135 +1253,135 @@ bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, class LLAlwaysCollect : public LLInventoryCollectFunctor { public: - virtual ~LLAlwaysCollect() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - return TRUE; - } + virtual ~LLAlwaysCollect() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + return TRUE; + } }; void LLInventoryModel::collectDescendents(const LLUUID& id, - cat_array_t& cats, - item_array_t& items, - BOOL include_trash) + cat_array_t& cats, + item_array_t& items, + BOOL include_trash) { - LLAlwaysCollect always; - collectDescendentsIf(id, cats, items, include_trash, always); + LLAlwaysCollect always; + collectDescendentsIf(id, cats, items, include_trash, always); } void LLInventoryModel::collectDescendentsIf(const LLUUID& id, - cat_array_t& cats, - item_array_t& items, - BOOL include_trash, - LLInventoryCollectFunctor& add) + cat_array_t& cats, + item_array_t& items, + BOOL include_trash, + LLInventoryCollectFunctor& add) { - // Start with categories - if(!include_trash) - { - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(trash_id.notNull() && (trash_id == id)) - return; - } - cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); - if(cat_array) - { - S32 count = cat_array->size(); - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = cat_array->at(i); - if(add(cat,NULL)) - { - cats.push_back(cat); - } - collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); - } - } - - LLViewerInventoryItem* item = NULL; - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - - // Move onto items - if(item_array) - { - S32 count = item_array->size(); - for(S32 i = 0; i < count; ++i) - { - item = item_array->at(i); - if(add(NULL, item)) - { - items.push_back(item); - } - } - } + // Start with categories + if(!include_trash) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(trash_id.notNull() && (trash_id == id)) + return; + } + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if(cat_array) + { + S32 count = cat_array->size(); + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = cat_array->at(i); + if(add(cat,NULL)) + { + cats.push_back(cat); + } + collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); + } + } + + LLViewerInventoryItem* item = NULL; + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + // Move onto items + if(item_array) + { + S32 count = item_array->size(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->at(i); + if(add(NULL, item)) + { + items.push_back(item); + } + } + } } void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { - const LLInventoryObject *obj = getObject(object_id); - if (!obj || obj->getIsLinkType()) - return; - - LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); - for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) - { - LLViewerInventoryItem *linked_item = (*iter); - addChangedMask(mask, linked_item->getUUID()); - }; + const LLInventoryObject *obj = getObject(object_id); + if (!obj || obj->getIsLinkType()) + return; + + LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + addChangedMask(mask, linked_item->getUUID()); + }; } const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const { - const LLInventoryItem *item = gInventory.getItem(object_id); - if (!item) - { - return object_id; - } - - // Find the base item in case this a link (if it's not a link, - // this will just be inv_item_id) - return item->getLinkedUUID(); + const LLInventoryItem *item = gInventory.getItem(object_id); + if (!item) + { + return object_id; + } + + // Find the base item in case this a link (if it's not a link, + // this will just be inv_item_id) + return item->getLinkedUUID(); } LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) const { - return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; + return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; } LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id) { - // Get item list via collectDescendents (slow!) - item_array_t items; - const LLInventoryObject *obj = getObject(id); - // FIXME - should be as in next line, but this is causing a - // stack-smashing crash of cause TBD... check in the REBUILD code. - //if (obj && obj->getIsLinkType()) - if (!obj || obj->getIsLinkType()) - return items; - - std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); - for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) - { - LLViewerInventoryItem *item = getItem(it->second); - if (item) - { - items.push_back(item); - } - } - - return items; + // Get item list via collectDescendents (slow!) + item_array_t items; + const LLInventoryObject *obj = getObject(id); + // FIXME - should be as in next line, but this is causing a + // stack-smashing crash of cause TBD... check in the REBUILD code. + //if (obj && obj->getIsLinkType()) + if (!obj || obj->getIsLinkType()) + return items; + + std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) + { + LLViewerInventoryItem *item = getItem(it->second); + if (item) + { + items.push_back(item); + } + } + + return items; } bool LLInventoryModel::isInventoryUsable() const { - bool result = false; - if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) - { - result = true; - } - return result; + bool result = false; + if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) + { + result = true; + } + return result; } // Calling this method with an inventory item will either change an @@ -1389,34 +1389,34 @@ bool LLInventoryModel::isInventoryUsable() const // current inventory. U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { - if(item->getUUID().isNull()) - { - return mask; - } - - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return mask; - } - - if (item->getType() == LLAssetType::AT_MESH) - { - return mask; - } - - LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID()); - LLPointer<LLViewerInventoryItem> new_item; - if(old_item) - { - // We already have an old item, modify its values - new_item = old_item; - LLUUID old_parent_id = old_item->getParentUUID(); - LLUUID new_parent_id = item->getParentUUID(); - bool update_parent_on_server = false; - - if (new_parent_id.isNull() && !LLApp::isExiting()) - { + if(item->getUUID().isNull()) + { + return mask; + } + + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return mask; + } + + if (item->getType() == LLAssetType::AT_MESH) + { + return mask; + } + + LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID()); + LLPointer<LLViewerInventoryItem> new_item; + if(old_item) + { + // We already have an old item, modify its values + new_item = old_item; + LLUUID old_parent_id = old_item->getParentUUID(); + LLUUID new_parent_id = item->getParentUUID(); + bool update_parent_on_server = false; + + if (new_parent_id.isNull() && !LLApp::isExiting()) + { if (old_parent_id.isNull()) { // Item with null parent will end in random location and then in Lost&Found, @@ -1438,359 +1438,359 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) new_parent_id = old_parent_id; update_parent_on_server = true; } - } - - if(old_parent_id != new_parent_id) - { - // need to update the parent-child tree - item_array_t* item_array; - item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); - if(item_array) - { - vector_replace_with_last(*item_array, old_item); - } - item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); - if(item_array) - { - if (update_parent_on_server) - { - LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); - gInventory.accountForUpdate(update); - } - item_array->push_back(old_item); - } - mask |= LLInventoryObserver::STRUCTURE; - } - if(old_item->getName() != item->getName()) - { - mask |= LLInventoryObserver::LABEL; - } + } + + if(old_parent_id != new_parent_id) + { + // need to update the parent-child tree + item_array_t* item_array; + item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); + if(item_array) + { + vector_replace_with_last(*item_array, old_item); + } + item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); + if(item_array) + { + if (update_parent_on_server) + { + LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); + gInventory.accountForUpdate(update); + } + item_array->push_back(old_item); + } + mask |= LLInventoryObserver::STRUCTURE; + } + if(old_item->getName() != item->getName()) + { + mask |= LLInventoryObserver::LABEL; + } if (old_item->getPermissions() != item->getPermissions()) { mask |= LLInventoryObserver::INTERNAL; } - old_item->copyViewerItem(item); - if (update_parent_on_server) - { - // Parent id at server is null, so update server even if item already is in the same folder - old_item->setParent(new_parent_id); - new_item->updateParentOnServer(FALSE); - } - mask |= LLInventoryObserver::INTERNAL; - } - else - { - // Simply add this item - new_item = new LLViewerInventoryItem(item); - addItem(new_item); - - if(item->getParentUUID().isNull()) - { - const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType())); - new_item->setParent(category_id); - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); - if( item_array ) - { - LLInventoryModel::LLCategoryUpdate update(category_id, 1); - gInventory.accountForUpdate(update); - - // *FIX: bit of a hack to call update server from here... - new_item->updateParentOnServer(FALSE); - item_array->push_back(new_item); - } - else - { - LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; - } - } - else - { - // *NOTE: The general scheme is that if every byte of the - // uuid is 0, except for the last one or two,the use the - // last two bytes of the parent id, and match that up - // against the type. For now, we're only worried about - // lost & found. - LLUUID parent_id = item->getParentUUID(); - if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID) - { - parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - new_item->setParent(parent_id); - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - } - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); - if(item_array) - { - item_array->push_back(new_item); - } - else - { - // Whoops! No such parent, make one. - LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " - << new_item->getName() << LL_ENDL; - parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - new_item->setParent(parent_id); - item_array = get_ptr_in_map(mParentChildItemTree, parent_id); - if(item_array) - { - LLInventoryModel::LLCategoryUpdate update(parent_id, 1); - gInventory.accountForUpdate(update); - // *FIX: bit of a hack to call update server from - // here... - new_item->updateParentOnServer(FALSE); - item_array->push_back(new_item); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - } - mask |= LLInventoryObserver::ADD; - } - if(new_item->getType() == LLAssetType::AT_CALLINGCARD) - { - mask |= LLInventoryObserver::CALLING_CARD; - // Handle user created calling cards. - // Target ID is stored in the description field of the card. - LLUUID id; - std::string desc = new_item->getDescription(); - BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); - if (isId) - { - // Valid UUID; set the item UUID and rename it - new_item->setCreator(id); - LLAvatarName av_name; - - if (LLAvatarNameCache::get(id, &av_name)) - { - new_item->rename(av_name.getUserName()); - mask |= LLInventoryObserver::LABEL; - } - else - { - // Fetch the current name - LLAvatarNameCache::get(id, - boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), - _1, _2)); - } - - } - } - else if (new_item->getType() == LLAssetType::AT_GESTURE) - { - mask |= LLInventoryObserver::GESTURE; - } - addChangedMask(mask, new_item->getUUID()); - return mask; + old_item->copyViewerItem(item); + if (update_parent_on_server) + { + // Parent id at server is null, so update server even if item already is in the same folder + old_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + } + mask |= LLInventoryObserver::INTERNAL; + } + else + { + // Simply add this item + new_item = new LLViewerInventoryItem(item); + addItem(new_item); + + if(item->getParentUUID().isNull()) + { + const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType())); + new_item->setParent(category_id); + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); + if( item_array ) + { + LLInventoryModel::LLCategoryUpdate update(category_id, 1); + gInventory.accountForUpdate(update); + + // *FIX: bit of a hack to call update server from here... + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); + } + else + { + LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; + } + } + else + { + // *NOTE: The general scheme is that if every byte of the + // uuid is 0, except for the last one or two,the use the + // last two bytes of the parent id, and match that up + // against the type. For now, we're only worried about + // lost & found. + LLUUID parent_id = item->getParentUUID(); + if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID) + { + parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + new_item->setParent(parent_id); + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + } + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); + if(item_array) + { + item_array->push_back(new_item); + } + else + { + // Whoops! No such parent, make one. + LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " + << new_item->getName() << LL_ENDL; + parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + new_item->setParent(parent_id); + item_array = get_ptr_in_map(mParentChildItemTree, parent_id); + if(item_array) + { + LLInventoryModel::LLCategoryUpdate update(parent_id, 1); + gInventory.accountForUpdate(update); + // *FIX: bit of a hack to call update server from + // here... + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + } + mask |= LLInventoryObserver::ADD; + } + if(new_item->getType() == LLAssetType::AT_CALLINGCARD) + { + mask |= LLInventoryObserver::CALLING_CARD; + // Handle user created calling cards. + // Target ID is stored in the description field of the card. + LLUUID id; + std::string desc = new_item->getDescription(); + BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); + if (isId) + { + // Valid UUID; set the item UUID and rename it + new_item->setCreator(id); + LLAvatarName av_name; + + if (LLAvatarNameCache::get(id, &av_name)) + { + new_item->rename(av_name.getUserName()); + mask |= LLInventoryObserver::LABEL; + } + else + { + // Fetch the current name + LLAvatarNameCache::get(id, + boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), + _1, _2)); + } + + } + } + else if (new_item->getType() == LLAssetType::AT_GESTURE) + { + mask |= LLInventoryObserver::GESTURE; + } + addChangedMask(mask, new_item->getUUID()); + return mask; } LLInventoryModel::cat_array_t* LLInventoryModel::getUnlockedCatArray(const LLUUID& id) { - cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); - if (cat_array) - { - llassert_always(mCategoryLock[id] == false); - } - return cat_array; + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if (cat_array) + { + llassert_always(mCategoryLock[id] == false); + } + return cat_array; } LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLUUID& id) { - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - if (item_array) - { - llassert_always(mItemLock[id] == false); - } - return item_array; + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + if (item_array) + { + llassert_always(mItemLock[id] == false); + } + return item_array; } // Calling this method with an inventory category will either change // an existing item with the matching id, or it will add the category. void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask) { - if(!cat || cat->getUUID().isNull()) - { - return; - } - - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return; - } - - LLPointer<LLViewerInventoryCategory> old_cat = getCategory(cat->getUUID()); - if(old_cat) - { - // We already have an old category, modify its values - LLUUID old_parent_id = old_cat->getParentUUID(); - LLUUID new_parent_id = cat->getParentUUID(); - if(old_parent_id != new_parent_id) - { - // need to update the parent-child tree - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(old_parent_id); - if(cat_array) - { - vector_replace_with_last(*cat_array, old_cat); - } - cat_array = getUnlockedCatArray(new_parent_id); - if(cat_array) - { - cat_array->push_back(old_cat); - } - mask |= LLInventoryObserver::STRUCTURE; + if(!cat || cat->getUUID().isNull()) + { + return; + } + + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return; + } + + LLPointer<LLViewerInventoryCategory> old_cat = getCategory(cat->getUUID()); + if(old_cat) + { + // We already have an old category, modify its values + LLUUID old_parent_id = old_cat->getParentUUID(); + LLUUID new_parent_id = cat->getParentUUID(); + if(old_parent_id != new_parent_id) + { + // need to update the parent-child tree + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(old_parent_id); + if(cat_array) + { + vector_replace_with_last(*cat_array, old_cat); + } + cat_array = getUnlockedCatArray(new_parent_id); + if(cat_array) + { + cat_array->push_back(old_cat); + } + mask |= LLInventoryObserver::STRUCTURE; mask |= LLInventoryObserver::INTERNAL; - } - if(old_cat->getName() != cat->getName()) - { - mask |= LLInventoryObserver::LABEL; - } + } + if(old_cat->getName() != cat->getName()) + { + mask |= LLInventoryObserver::LABEL; + } // Under marketplace, category labels are quite complex and need extra upate const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) { - mask |= LLInventoryObserver::LABEL; + mask |= LLInventoryObserver::LABEL; } old_cat->copyViewerCategory(cat); - addChangedMask(mask, cat->getUUID()); - } - else - { - // add this category - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat->getOwnerID()); - new_cat->copyViewerCategory(cat); - addCategory(new_cat); - - // make sure this category is correctly referenced by its parent. - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) - { - cat_array->push_back(new_cat); - } - - // make space in the tree for this category's children. - llassert_always(mCategoryLock[new_cat->getUUID()] == false); - llassert_always(mItemLock[new_cat->getUUID()] == false); - cat_array_t* catsp = new cat_array_t; - item_array_t* itemsp = new item_array_t; - mParentChildCategoryTree[new_cat->getUUID()] = catsp; - mParentChildItemTree[new_cat->getUUID()] = itemsp; - mask |= LLInventoryObserver::ADD; - addChangedMask(mask, cat->getUUID()); - } + addChangedMask(mask, cat->getUUID()); + } + else + { + // add this category + LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat->getOwnerID()); + new_cat->copyViewerCategory(cat); + addCategory(new_cat); + + // make sure this category is correctly referenced by its parent. + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) + { + cat_array->push_back(new_cat); + } + + // make space in the tree for this category's children. + llassert_always(mCategoryLock[new_cat->getUUID()] == false); + llassert_always(mItemLock[new_cat->getUUID()] == false); + cat_array_t* catsp = new cat_array_t; + item_array_t* itemsp = new item_array_t; + mParentChildCategoryTree[new_cat->getUUID()] = catsp; + mParentChildItemTree[new_cat->getUUID()] = itemsp; + mask |= LLInventoryObserver::ADD; + addChangedMask(mask, cat->getUUID()); + } } void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) { - LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return; - } - - if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) - { - LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " - << cat_id << LL_ENDL; - return; - } - LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); - if(cat && (cat->getParentUUID() != cat_id)) - { - LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) vector_replace_with_last(*cat_array, cat); - cat_array = getUnlockedCatArray(cat_id); - cat->setParent(cat_id); - if(cat_array) cat_array->push_back(cat); - addChangedMask(LLInventoryObserver::STRUCTURE, object_id); - return; - } - LLPointer<LLViewerInventoryItem> item = getItem(object_id); - if(item && (item->getParentUUID() != cat_id)) - { - LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; - item_array_t* item_array; - item_array = getUnlockedItemArray(item->getParentUUID()); - if(item_array) vector_replace_with_last(*item_array, item); - item_array = getUnlockedItemArray(cat_id); - item->setParent(cat_id); - if(item_array) item_array->push_back(item); - addChangedMask(LLInventoryObserver::STRUCTURE, object_id); - return; - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return; + } + + if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) + { + LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " + << cat_id << LL_ENDL; + return; + } + LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); + if(cat && (cat->getParentUUID() != cat_id)) + { + LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) vector_replace_with_last(*cat_array, cat); + cat_array = getUnlockedCatArray(cat_id); + cat->setParent(cat_id); + if(cat_array) cat_array->push_back(cat); + addChangedMask(LLInventoryObserver::STRUCTURE, object_id); + return; + } + LLPointer<LLViewerInventoryItem> item = getItem(object_id); + if(item && (item->getParentUUID() != cat_id)) + { + LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; + item_array_t* item_array; + item_array = getUnlockedItemArray(item->getParentUUID()); + if(item_array) vector_replace_with_last(*item_array, item); + item_array = getUnlockedItemArray(cat_id); + item->setParent(cat_id); + if(item_array) item_array->push_back(item); + addChangedMask(LLInventoryObserver::STRUCTURE, object_id); + return; + } } // Migrated from llinventoryfunctions void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp) + const LLUUID& new_parent_id, + BOOL restamp) { - if (item->getParentUUID() == new_parent_id) - { - LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; - } - else - { - LL_INFOS(LOG_INV) << "Move item " << make_info(item) - << " from " << make_inventory_info(item->getParentUUID()) - << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(restamp); - updateItem(new_item); - notifyObservers(); - } + if (item->getParentUUID() == new_parent_id) + { + LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; + } + else + { + LL_INFOS(LOG_INV) << "Move item " << make_info(item) + << " from " << make_inventory_info(item->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(restamp); + updateItem(new_item); + notifyObservers(); + } } // Migrated from llinventoryfunctions void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp) + const LLUUID& new_parent_id, + BOOL restamp) { - if (!cat) - { - return; - } - - // Can't move a folder into a child of itself. - if (isObjectDescendentOf(new_parent_id, cat->getUUID())) - { - return; - } - - LL_INFOS(LOG_INV) << "Move category " << make_info(cat) - << " from " << make_inventory_info(cat->getParentUUID()) - << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - updateCategory(new_cat); - notifyObservers(); + if (!cat) + { + return; + } + + // Can't move a folder into a child of itself. + if (isObjectDescendentOf(new_parent_id, cat->getUUID())) + { + return; + } + + LL_INFOS(LOG_INV) << "Move category " << make_info(cat) + << " from " << make_inventory_info(cat->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent_id); + new_cat->updateParentOnServer(restamp); + updateCategory(new_cat); + notifyObservers(); } void LLInventoryModel::rebuildBrockenLinks() @@ -1817,262 +1817,262 @@ void LLInventoryModel::rebuildBrockenLinks() // Does not appear to be used currently. void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) { - U32 mask = LLInventoryObserver::NONE; - - LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); - LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; - if(item) - { - for (LLSD::map_const_iterator it = updates.beginMap(); - it != updates.endMap(); ++it) - { - if (it->first == "name") - { - LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; - item->rename(it->second.asString()); - mask |= LLInventoryObserver::LABEL; - } - else if (it->first == "desc") - { - LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() - << " to " << it->second.asString() << LL_ENDL; - item->setDescription(it->second.asString()); - } - else - { - LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; - } - } - mask |= LLInventoryObserver::INTERNAL; - addChangedMask(mask, item->getUUID()); - if (update_parent_version) - { - // Descendent count is unchanged, but folder version incremented. - LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); - accountForUpdate(up); - } - notifyObservers(); // do we want to be able to make this optional? - } + U32 mask = LLInventoryObserver::NONE; + + LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; + if(item) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; + item->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else if (it->first == "desc") + { + LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() + << " to " << it->second.asString() << LL_ENDL; + item->setDescription(it->second.asString()); + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, item->getUUID()); + if (update_parent_version) + { + // Descendent count is unchanged, but folder version incremented. + LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); + accountForUpdate(up); + } + notifyObservers(); // do we want to be able to make this optional? + } } // Not used? void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) { - U32 mask = LLInventoryObserver::NONE; - - LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); - LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; - if(cat) - { - for (LLSD::map_const_iterator it = updates.beginMap(); - it != updates.endMap(); ++it) - { - if (it->first == "name") - { - LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; - cat->rename(it->second.asString()); - mask |= LLInventoryObserver::LABEL; - } - else - { - LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; - } - } - mask |= LLInventoryObserver::INTERNAL; - addChangedMask(mask, cat->getUUID()); - notifyObservers(); // do we want to be able to make this optional? - } + U32 mask = LLInventoryObserver::NONE; + + LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); + LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; + if(cat) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; + cat->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, cat->getUUID()); + notifyObservers(); // do we want to be able to make this optional? + } } // Update model after descendents have been purged. void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) { - LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); - if (cat.notNull()) - { - // do the cache accounting - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); - accountForUpdate(up); - } - - // we know that descendent count is 0, however since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); - - // unceremoniously remove anything we have locally stored. - LLInventoryModel::cat_array_t categories; - LLInventoryModel::item_array_t items; - collectDescendents(object_id, - categories, - items, - LLInventoryModel::INCLUDE_TRASH); - S32 count = items.size(); - - LLUUID uu_id; - for(S32 i = 0; i < count; ++i) - { - uu_id = items.at(i)->getUUID(); - - // This check prevents the deletion of a previously deleted item. - // This is necessary because deletion is not done in a hierarchical - // order. The current item may have been already deleted as a child - // of its deleted parent. - if (getItem(uu_id)) - { - deleteObject(uu_id, fix_broken_links); - } - } - - count = categories.size(); - // Slightly kludgy way to make sure categories are removed - // only after their child categories have gone away. - - // FIXME: Would probably make more sense to have this whole - // descendent-clearing thing be a post-order recursive - // function to get the leaf-up behavior automatically. - S32 deleted_count; - S32 total_deleted_count = 0; - do - { - deleted_count = 0; - for(S32 i = 0; i < count; ++i) - { - uu_id = categories.at(i)->getUUID(); - if (getCategory(uu_id)) - { - cat_array_t* cat_list = getUnlockedCatArray(uu_id); - if (!cat_list || (cat_list->size() == 0)) - { - deleteObject(uu_id, fix_broken_links); - deleted_count++; - } - } - } - total_deleted_count += deleted_count; - } - while (deleted_count > 0); - if (total_deleted_count != count) - { - LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " - << total_deleted_count << " expected " << count << LL_ENDL; - } - //gInventory.validate(); - } + LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); + if (cat.notNull()) + { + // do the cache accounting + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); + accountForUpdate(up); + } + + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // unceremoniously remove anything we have locally stored. + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + collectDescendents(object_id, + categories, + items, + LLInventoryModel::INCLUDE_TRASH); + S32 count = items.size(); + + LLUUID uu_id; + for(S32 i = 0; i < count; ++i) + { + uu_id = items.at(i)->getUUID(); + + // This check prevents the deletion of a previously deleted item. + // This is necessary because deletion is not done in a hierarchical + // order. The current item may have been already deleted as a child + // of its deleted parent. + if (getItem(uu_id)) + { + deleteObject(uu_id, fix_broken_links); + } + } + + count = categories.size(); + // Slightly kludgy way to make sure categories are removed + // only after their child categories have gone away. + + // FIXME: Would probably make more sense to have this whole + // descendent-clearing thing be a post-order recursive + // function to get the leaf-up behavior automatically. + S32 deleted_count; + S32 total_deleted_count = 0; + do + { + deleted_count = 0; + for(S32 i = 0; i < count; ++i) + { + uu_id = categories.at(i)->getUUID(); + if (getCategory(uu_id)) + { + cat_array_t* cat_list = getUnlockedCatArray(uu_id); + if (!cat_list || (cat_list->size() == 0)) + { + deleteObject(uu_id, fix_broken_links); + deleted_count++; + } + } + } + total_deleted_count += deleted_count; + } + while (deleted_count > 0); + if (total_deleted_count != count) + { + LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " + << total_deleted_count << " expected " << count << LL_ENDL; + } + //gInventory.validate(); + } } // Update model after an item is confirmed as removed from // server. Works for categories or items. void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) { - LLPointer<LLInventoryObject> obj = getObject(object_id); - if(obj) - { - if (getCategory(object_id)) - { - // For category, need to delete/update all children first. - onDescendentsPurgedFromServer(object_id, fix_broken_links); - } - - - // From item/cat removeFromServer() - if (update_parent_version) - { - LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); - accountForUpdate(up); - } - - // From purgeObject() - LLViewerInventoryItem *item = getItem(object_id); - if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) - { - LLPreview::hide(object_id, TRUE); - } - deleteObject(object_id, fix_broken_links, do_notify_observers); - } + LLPointer<LLInventoryObject> obj = getObject(object_id); + if(obj) + { + if (getCategory(object_id)) + { + // For category, need to delete/update all children first. + onDescendentsPurgedFromServer(object_id, fix_broken_links); + } + + + // From item/cat removeFromServer() + if (update_parent_version) + { + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + } + + // From purgeObject() + LLViewerInventoryItem *item = getItem(object_id); + if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) + { + LLPreview::hide(object_id, TRUE); + } + deleteObject(object_id, fix_broken_links, do_notify_observers); + } } // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers) { - LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; - LLPointer<LLInventoryObject> obj = getObject(id); - if (!obj) - { - LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; - return; - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; + LLPointer<LLInventoryObject> obj = getObject(id); + if (!obj) + { + LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; + return; + } //collect the links before removing the item from mItemMap LLInventoryModel::item_array_t links = collectLinksTo(id); - - LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; - mLastItem = NULL; - LLUUID parent_id = obj->getParentUUID(); - mCategoryMap.erase(id); - mItemMap.erase(id); - //mInventory.erase(id); - item_array_t* item_list = getUnlockedItemArray(parent_id); - if(item_list) - { - LLPointer<LLViewerInventoryItem> item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); - vector_replace_with_last(*item_list, item); - } - cat_array_t* cat_list = getUnlockedCatArray(parent_id); - if(cat_list) - { - LLPointer<LLViewerInventoryCategory> cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); - vector_replace_with_last(*cat_list, cat); - } - + + LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; + mLastItem = NULL; + LLUUID parent_id = obj->getParentUUID(); + mCategoryMap.erase(id); + mItemMap.erase(id); + //mInventory.erase(id); + item_array_t* item_list = getUnlockedItemArray(parent_id); + if(item_list) + { + LLPointer<LLViewerInventoryItem> item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); + vector_replace_with_last(*item_list, item); + } + cat_array_t* cat_list = getUnlockedCatArray(parent_id); + if(cat_list) + { + LLPointer<LLViewerInventoryCategory> cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); + vector_replace_with_last(*cat_list, cat); + } + // Note : We need to tell the inventory observers that those things are going to be deleted *before* the tree is cleared or they won't know what to delete (in views and view models) - addChangedMask(LLInventoryObserver::REMOVE, id); - gInventory.notifyObservers(); - - item_list = getUnlockedItemArray(id); - if(item_list) - { - if (item_list->size()) - { - LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; - } - delete item_list; - mParentChildItemTree.erase(id); - } - cat_list = getUnlockedCatArray(id); - if(cat_list) - { - if (cat_list->size()) - { - LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; - } - delete cat_list; - mParentChildCategoryTree.erase(id); - } - addChangedMask(LLInventoryObserver::REMOVE, id); - - bool is_link_type = obj->getIsLinkType(); - if (is_link_type) - { - removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); - } - - // Can't have links to links, so there's no need for this update - // if the item removed is a link. Can also skip if source of the - // update is getting broken link info separately. - if (fix_broken_links && !is_link_type) - { + addChangedMask(LLInventoryObserver::REMOVE, id); + gInventory.notifyObservers(); + + item_list = getUnlockedItemArray(id); + if(item_list) + { + if (item_list->size()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; + } + delete item_list; + mParentChildItemTree.erase(id); + } + cat_list = getUnlockedCatArray(id); + if(cat_list) + { + if (cat_list->size()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; + } + delete cat_list; + mParentChildCategoryTree.erase(id); + } + addChangedMask(LLInventoryObserver::REMOVE, id); + + bool is_link_type = obj->getIsLinkType(); + if (is_link_type) + { + removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); + } + + // Can't have links to links, so there's no need for this update + // if the item removed is a link. Can also skip if source of the + // update is getting broken link info separately. + if (fix_broken_links && !is_link_type) + { rebuildLinkItems(links); - } - obj = nullptr; // delete obj - if (do_notify_observers) - { - notifyObservers(); - } + } + obj = nullptr; // delete obj + if (do_notify_observers) + { + notifyObservers(); + } } void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items) @@ -2100,23 +2100,23 @@ void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items) // remove it. void LLInventoryModel::addObserver(LLInventoryObserver* observer) { - mObservers.insert(observer); + mObservers.insert(observer); } - + void LLInventoryModel::removeObserver(LLInventoryObserver* observer) { - mObservers.erase(observer); + mObservers.erase(observer); } BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const { - return mObservers.find(observer) != mObservers.end(); + return mObservers.find(observer) != mObservers.end(); } void LLInventoryModel::idleNotifyObservers() { - // *FIX: Think I want this conditional or moved elsewhere... - handleResponses(true); + // *FIX: Think I want this conditional or moved elsewhere... + handleResponses(true); if (mLinksRebuildList.size() > 0) { @@ -2131,78 +2131,78 @@ void LLInventoryModel::idleNotifyObservers() mLinksRebuildList.clear(); notifyObservers(); } - - if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) - { - return; - } - notifyObservers(); + + if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) + { + return; + } + notifyObservers(); } // Call this method when it's time to update everyone on a new state. void LLInventoryModel::notifyObservers() { - if (mIsNotifyObservers) - { - // Within notifyObservers, something called notifyObservers - // again. This type of recursion is unsafe because it causes items to be - // processed twice, and this can easily lead to infinite loops. - LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; - return; - } - - mIsNotifyObservers = TRUE; - for (observer_list_t::iterator iter = mObservers.begin(); - iter != mObservers.end(); ) - { - LLInventoryObserver* observer = *iter; - observer->changed(mModifyMask); - - // safe way to increment since changed may delete entries! (@!##%@!@&*!) - iter = mObservers.upper_bound(observer); - } - - // If there were any changes that arrived during notifyObservers, - // shedule them for next loop - mModifyMask = mModifyMaskBacklog; - mChangedItemIDs.clear(); - mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); - mAddedItemIDs.clear(); - mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); - - mModifyMaskBacklog = LLInventoryObserver::NONE; - mChangedItemIDsBacklog.clear(); - mAddedItemIDsBacklog.clear(); - - mIsNotifyObservers = FALSE; + if (mIsNotifyObservers) + { + // Within notifyObservers, something called notifyObservers + // again. This type of recursion is unsafe because it causes items to be + // processed twice, and this can easily lead to infinite loops. + LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; + return; + } + + mIsNotifyObservers = TRUE; + for (observer_list_t::iterator iter = mObservers.begin(); + iter != mObservers.end(); ) + { + LLInventoryObserver* observer = *iter; + observer->changed(mModifyMask); + + // safe way to increment since changed may delete entries! (@!##%@!@&*!) + iter = mObservers.upper_bound(observer); + } + + // If there were any changes that arrived during notifyObservers, + // shedule them for next loop + mModifyMask = mModifyMaskBacklog; + mChangedItemIDs.clear(); + mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); + mAddedItemIDs.clear(); + mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); + + mModifyMaskBacklog = LLInventoryObserver::NONE; + mChangedItemIDsBacklog.clear(); + mAddedItemIDsBacklog.clear(); + + mIsNotifyObservers = FALSE; } // store flag for change // and id of object change applies to -void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) -{ - if (mIsNotifyObservers) - { - // Something marked an item for change within a call to notifyObservers - // (which is in the process of processing the list of items marked for change). - // This means the change will have to be processed later. - // It's preferable for this not to happen, but it's not an issue unless code - // specifically wants to notifyObservers immediately (changes won't happen untill later) - LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; - LLViewerInventoryItem *item = getItem(referent); - if (item) - { - LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; - } - else - { - LLViewerInventoryCategory *cat = getCategory(referent); - if (cat) - { - LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; - } - } - } +void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) +{ + if (mIsNotifyObservers) + { + // Something marked an item for change within a call to notifyObservers + // (which is in the process of processing the list of items marked for change). + // This means the change will have to be processed later. + // It's preferable for this not to happen, but it's not an issue unless code + // specifically wants to notifyObservers immediately (changes won't happen untill later) + LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; + LLViewerInventoryItem *item = getItem(referent); + if (item) + { + LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; + } + else + { + LLViewerInventoryCategory *cat = getCategory(referent); + if (cat) + { + LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; + } + } + } if (mIsNotifyObservers) { @@ -2227,7 +2227,7 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } if (needs_update) - { + { if (mIsNotifyObservers) { mChangedItemIDsBacklog.insert(referent); @@ -2256,42 +2256,42 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) mAddedItemIDs.insert(referent); } } - - // Update all linked items. Starting with just LABEL because I'm - // not sure what else might need to be accounted for this. - if (mask & LLInventoryObserver::LABEL) - { - addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); - } - } + + // Update all linked items. Starting with just LABEL because I'm + // not sure what else might need to be accounted for this. + if (mask & LLInventoryObserver::LABEL) + { + addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); + } + } } bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const { - if(folder_id.isNull()) - { - LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; - return false; - } - LLViewerInventoryCategory* cat = getCategory(folder_id); - if(!cat) - { - LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " - << folder_id << LL_ENDL; - return false; - } - //S32 known_descendents = 0; - ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); - //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); - //if(categories) - //{ - // known_descendents += categories->size(); - //} - //if(items) - //{ - // known_descendents += items->size(); - //} - return cat->fetch(); + if(folder_id.isNull()) + { + LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; + return false; + } + LLViewerInventoryCategory* cat = getCategory(folder_id); + if(!cat) + { + LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " + << folder_id << LL_ENDL; + return false; + } + //S32 known_descendents = 0; + ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); + //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); + //if(categories) + //{ + // known_descendents += categories->size(); + //} + //if(items) + //{ + // known_descendents += items->size(); + //} + return cat->fetch(); } //static @@ -2318,138 +2318,138 @@ std::string LLInventoryModel::getInvCacheAddres(const LLUUID& owner_id) } void LLInventoryModel::cache( - const LLUUID& parent_folder_id, - const LLUUID& agent_id) + const LLUUID& parent_folder_id, + const LLUUID& agent_id) { - LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id - << LL_ENDL; - LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); - if(!root_cat) return; - cat_array_t categories; - categories.push_back(root_cat); - item_array_t items; - - LLCanCache can_cache(this); - can_cache(root_cat, NULL); - collectDescendentsIf( - parent_folder_id, - categories, - items, - INCLUDE_TRASH, - can_cache); + LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id + << LL_ENDL; + LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); + if(!root_cat) return; + cat_array_t categories; + categories.push_back(root_cat); + item_array_t items; + + LLCanCache can_cache(this); + can_cache(root_cat, NULL); + collectDescendentsIf( + parent_folder_id, + categories, + items, + INCLUDE_TRASH, + can_cache); // Use temporary file to avoid potential conflicts with other // instances (even a 'read only' instance unzips into a file) std::string temp_file = gDirUtilp->getTempFilename(); - saveToFile(temp_file, categories, items); + saveToFile(temp_file, categories, items); std::string gzip_filename = getInvCacheAddres(agent_id); - gzip_filename.append(".gz"); - if(gzip_file(temp_file, gzip_filename)) - { - LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; - LLFile::remove(temp_file); - } - else - { - LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; - } + gzip_filename.append(".gz"); + if(gzip_file(temp_file, gzip_filename)) + { + LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; + LLFile::remove(temp_file); + } + else + { + LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; + } } void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) { - //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; - if(category) - { - // We aren't displaying the Meshes folder - if (category->mPreferredType == LLFolderType::FT_MESH) - { - return; - } - - // try to localize default names first. See EXT-8319, EXT-7051. - category->localizeName(); - - // Insert category uniquely into the map - mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one - //mInventory[category->getUUID()] = category; - } + //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; + if(category) + { + // We aren't displaying the Meshes folder + if (category->mPreferredType == LLFolderType::FT_MESH) + { + return; + } + + // try to localize default names first. See EXT-8319, EXT-7051. + category->localizeName(); + + // Insert category uniquely into the map + mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one + //mInventory[category->getUUID()] = category; + } } bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const { - std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; - range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - if (it->second == link_id) - { - return true; - } - } - return false; + std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + if (it->second == link_id) + { + return true; + } + } + return false; } void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - if (!hasBacklinkInfo(link_id, target_id)) - { - mBacklinkMMap.insert(std::make_pair(target_id, link_id)); - } + if (!hasBacklinkInfo(link_id, target_id)) + { + mBacklinkMMap.insert(std::make_pair(target_id, link_id)); + } } void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; - range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::iterator it = range.first; it != range.second; ) - { - if (it->second == link_id) - { - backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. - ++it; - mBacklinkMMap.erase(delete_it); - } - else - { - ++it; - } - } + std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ) + { + if (it->second == link_id) + { + backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. + ++it; + mBacklinkMMap.erase(delete_it); + } + else + { + ++it; + } + } } void LLInventoryModel::addItem(LLViewerInventoryItem* item) { - llassert(item); - if(item) - { - if (item->getType() <= LLAssetType::AT_NONE) - { - LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; - return; - } - - if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) - { - if (item->getType() >= LLAssetType::AT_COUNT) - { - // Not yet supported. - LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; - } - else - { - LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; - } - } - - // This condition means that we tried to add a link without the baseobj being in memory. - // The item will show up as a broken link. - if (item->getIsBrokenLink()) - { + llassert(item); + if(item) + { + if (item->getType() <= LLAssetType::AT_NONE) + { + LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; + return; + } + + if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) + { + if (item->getType() >= LLAssetType::AT_COUNT) + { + // Not yet supported. + LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + } + + // This condition means that we tried to add a link without the baseobj being in memory. + // The item will show up as a broken link. + if (item->getIsBrokenLink()) + { if (item->getAssetUUID().notNull() && LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive()) { @@ -2485,7 +2485,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; } - } + } if (!mPossiblyBrockenLinks.empty()) { // check if we are waiting for this item @@ -2496,705 +2496,705 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) mPossiblyBrockenLinks.erase(iter); } } - if (item->getIsLinkType()) - { - // Add back-link from linked-to UUID. - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - addBacklinkInfo(link_id, target_id); - } - mItemMap[item->getUUID()] = item; - } + if (item->getIsLinkType()) + { + // Add back-link from linked-to UUID. + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + addBacklinkInfo(link_id, target_id); + } + mItemMap[item->getUUID()] = item; + } } // Empty the entire contents void LLInventoryModel::empty() { -// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; - std::for_each( - mParentChildCategoryTree.begin(), - mParentChildCategoryTree.end(), - DeletePairedPointer()); - mParentChildCategoryTree.clear(); - std::for_each( - mParentChildItemTree.begin(), - mParentChildItemTree.end(), - DeletePairedPointer()); - mParentChildItemTree.clear(); - mBacklinkMMap.clear(); // forget all backlink information. - mCategoryMap.clear(); // remove all references (should delete entries) - mItemMap.clear(); // remove all references (should delete entries) - mLastItem = NULL; - //mInventory.clear(); +// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; + std::for_each( + mParentChildCategoryTree.begin(), + mParentChildCategoryTree.end(), + DeletePairedPointer()); + mParentChildCategoryTree.clear(); + std::for_each( + mParentChildItemTree.begin(), + mParentChildItemTree.end(), + DeletePairedPointer()); + mParentChildItemTree.clear(); + mBacklinkMMap.clear(); // forget all backlink information. + mCategoryMap.clear(); // remove all references (should delete entries) + mItemMap.clear(); // remove all references (should delete entries) + mLastItem = NULL; + //mInventory.clear(); } void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const { - LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); - if(cat) - { - S32 version = cat->getVersion(); - if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = cat->getDescendentCount(); - S32 descendents_actual = cat->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - descendents_actual += update.mDescendentDelta; - cat->setDescendentCount(descendents_actual); - cat->setVersion(++version); - LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " - << version << " with " << descendents_actual - << " descendents." << LL_ENDL; - } - else - { - // Error condition, this means that the category did not register that - // it got new descendents (perhaps because it is still being loaded) - // which means its descendent count will be wrong. - LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" - << version << " due to mismatched descendent count: server == " - << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; - } - } - else - { - LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" - << version << ")" << LL_ENDL; - } - } - else - { - LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; - } + LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); + if(cat) + { + S32 version = cat->getVersion(); + if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + descendents_actual += update.mDescendentDelta; + cat->setDescendentCount(descendents_actual); + cat->setVersion(++version); + LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " + << version << " with " << descendents_actual + << " descendents." << LL_ENDL; + } + else + { + // Error condition, this means that the category did not register that + // it got new descendents (perhaps because it is still being loaded) + // which means its descendent count will be wrong. + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" + << version << " due to mismatched descendent count: server == " + << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; + } + } + else + { + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" + << version << ")" << LL_ENDL; + } + } + else + { + LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; + } } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_list_t& update) + const LLInventoryModel::update_list_t& update) { - update_list_t::const_iterator it = update.begin(); - update_list_t::const_iterator end = update.end(); - for(; it != end; ++it) - { - accountForUpdate(*it); - } + update_list_t::const_iterator it = update.begin(); + update_list_t::const_iterator end = update.end(); + for(; it != end; ++it) + { + accountForUpdate(*it); + } } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_map_t& update) + const LLInventoryModel::update_map_t& update) { - LLCategoryUpdate up; - update_map_t::const_iterator it = update.begin(); - update_map_t::const_iterator end = update.end(); - for(; it != end; ++it) - { - up.mCategoryID = (*it).first; - up.mDescendentDelta = (*it).second.mValue; - accountForUpdate(up); - } + LLCategoryUpdate up; + update_map_t::const_iterator it = update.begin(); + update_map_t::const_iterator end = update.end(); + for(; it != end; ++it) + { + up.mCategoryID = (*it).first; + up.mDescendentDelta = (*it).second.mValue; + accountForUpdate(up); + } } LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( - const LLUUID& cat_id) const + const LLUUID& cat_id) const { - LLViewerInventoryCategory* cat = getCategory(cat_id); - if(!cat) return CHILDREN_NO; - if(cat->getDescendentCount() > 0) - { - return CHILDREN_YES; - } - if(cat->getDescendentCount() == 0) - { - return CHILDREN_NO; - } - if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) - || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) - { - return CHILDREN_MAYBE; - } - - // Shouldn't have to run this, but who knows. - parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) - { - return CHILDREN_YES; - } - parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); - if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) - { - return CHILDREN_YES; - } - - return CHILDREN_NO; + LLViewerInventoryCategory* cat = getCategory(cat_id); + if(!cat) return CHILDREN_NO; + if(cat->getDescendentCount() > 0) + { + return CHILDREN_YES; + } + if(cat->getDescendentCount() == 0) + { + return CHILDREN_NO; + } + if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + return CHILDREN_MAYBE; + } + + // Shouldn't have to run this, but who knows. + parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); + if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) + { + return CHILDREN_YES; + } + parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); + if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) + { + return CHILDREN_YES; + } + + return CHILDREN_NO; } bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const { - LLViewerInventoryCategory* cat = getCategory(cat_id); - if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) - { - S32 descendents_server = cat->getDescendentCount(); - S32 descendents_actual = cat->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - return true; - } - } - return false; -} - + LLViewerInventoryCategory* cat = getCategory(cat_id); + if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + return true; + } + } + return false; +} + bool LLInventoryModel::loadSkeleton( - const LLSD& options, - const LLUUID& owner_id) + const LLSD& options, + const LLUUID& owner_id) { LL_PROFILE_ZONE_SCOPED; - LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; - - typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t; - cat_set_t temp_cats; - bool rv = true; - - for(LLSD::array_const_iterator it = options.beginArray(), - end = options.endArray(); it != end; ++it) - { - LLSD name = (*it)["name"]; - LLSD folder_id = (*it)["folder_id"]; - LLSD parent_id = (*it)["parent_id"]; - LLSD version = (*it)["version"]; - if(name.isDefined() - && folder_id.isDefined() - && parent_id.isDefined() - && version.isDefined() - && folder_id.asUUID().notNull() // if an id is null, it locks the viewer. - ) - { - LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id); - cat->rename(name.asString()); - cat->setUUID(folder_id.asUUID()); - cat->setParent(parent_id.asUUID()); - - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLSD type_default = (*it)["type_default"]; - if(type_default.isDefined()) + LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; + + typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t; + cat_set_t temp_cats; + bool rv = true; + + for(LLSD::array_const_iterator it = options.beginArray(), + end = options.endArray(); it != end; ++it) + { + LLSD name = (*it)["name"]; + LLSD folder_id = (*it)["folder_id"]; + LLSD parent_id = (*it)["parent_id"]; + LLSD version = (*it)["version"]; + if(name.isDefined() + && folder_id.isDefined() + && parent_id.isDefined() + && version.isDefined() + && folder_id.asUUID().notNull() // if an id is null, it locks the viewer. + ) + { + LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id); + cat->rename(name.asString()); + cat->setUUID(folder_id.asUUID()); + cat->setParent(parent_id.asUUID()); + + LLFolderType::EType preferred_type = LLFolderType::FT_NONE; + LLSD type_default = (*it)["type_default"]; + if(type_default.isDefined()) { - preferred_type = (LLFolderType::EType)type_default.asInteger(); + preferred_type = (LLFolderType::EType)type_default.asInteger(); } cat->setPreferredType(preferred_type); - cat->setVersion(version.asInteger()); + cat->setVersion(version.asInteger()); temp_cats.insert(cat); - } - else - { - LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; rv = false; - } - } - - S32 cached_category_count = 0; - S32 cached_item_count = 0; - if(!temp_cats.empty()) - { - update_map_t child_counts; - cat_array_t categories; - item_array_t items; - changed_items_t categories_to_update; - item_array_t possible_broken_links; - cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. - std::string inventory_filename = getInvCacheAddres(owner_id); - const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; - std::string gzip_filename(inventory_filename); - gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); - bool remove_inventory_file = false; - if(fp) - { - fclose(fp); - fp = NULL; - if(gunzip_file(gzip_filename, inventory_filename)) - { - // we only want to remove the inventory file if it was - // gzipped before we loaded, and we successfully - // gunziped it. - remove_inventory_file = true; - } - else - { - LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; - } - } - bool is_cache_obsolete = false; - if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) - { - // We were able to find a cache of files. So, use what we - // found to generate a set of categories we should add. We - // will go through each category loaded and if the version - // does not match, invalidate the version. - S32 count = categories.size(); - cat_set_t::iterator not_cached = temp_cats.end(); - std::set<LLUUID> cached_ids; - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = categories[i]; - cat_set_t::iterator cit = temp_cats.find(cat); - if (cit == temp_cats.end()) - { - continue; // cache corruption?? not sure why this happens -SJB - } - LLViewerInventoryCategory* tcat = *cit; - - if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) - { - tcat->setVersion(NO_VERSION); - LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; - } - - // we can safely ignore anything loaded from file, but - // not sent down in the skeleton. Must have been removed from inventory. - if (cit == not_cached) - { - continue; - } - else if (cat->getVersion() != tcat->getVersion()) - { - // if the cached version does not match the server version, - // throw away the version we have so we can fetch the - // correct contents the next time the viewer opens the folder. - tcat->setVersion(NO_VERSION); - } - else - { - cached_ids.insert(tcat->getUUID()); + } + } + + S32 cached_category_count = 0; + S32 cached_item_count = 0; + if(!temp_cats.empty()) + { + update_map_t child_counts; + cat_array_t categories; + item_array_t items; + changed_items_t categories_to_update; + item_array_t possible_broken_links; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. + std::string inventory_filename = getInvCacheAddres(owner_id); + const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; + std::string gzip_filename(inventory_filename); + gzip_filename.append(".gz"); + LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); + bool remove_inventory_file = false; + if(fp) + { + fclose(fp); + fp = NULL; + if(gunzip_file(gzip_filename, inventory_filename)) + { + // we only want to remove the inventory file if it was + // gzipped before we loaded, and we successfully + // gunziped it. + remove_inventory_file = true; + } + else + { + LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; + } + } + bool is_cache_obsolete = false; + if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) + { + // We were able to find a cache of files. So, use what we + // found to generate a set of categories we should add. We + // will go through each category loaded and if the version + // does not match, invalidate the version. + S32 count = categories.size(); + cat_set_t::iterator not_cached = temp_cats.end(); + std::set<LLUUID> cached_ids; + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories[i]; + cat_set_t::iterator cit = temp_cats.find(cat); + if (cit == temp_cats.end()) + { + continue; // cache corruption?? not sure why this happens -SJB + } + LLViewerInventoryCategory* tcat = *cit; + + if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) + { + tcat->setVersion(NO_VERSION); + LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; + } + + // we can safely ignore anything loaded from file, but + // not sent down in the skeleton. Must have been removed from inventory. + if (cit == not_cached) + { + continue; + } + else if (cat->getVersion() != tcat->getVersion()) + { + // if the cached version does not match the server version, + // throw away the version we have so we can fetch the + // correct contents the next time the viewer opens the folder. + tcat->setVersion(NO_VERSION); + } + else + { + cached_ids.insert(tcat->getUUID()); // At the moment download does not provide a thumbnail // uuid, use the one from cache tcat->setThumbnailUUID(cat->getThumbnailUUID()); - } - } - - // go ahead and add the cats returned during the download - std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end(); - cached_category_count = cached_ids.size(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - if(cached_ids.find((*it)->getUUID()) == not_cached_id) - { - // this check is performed so that we do not - // mark new folders in the skeleton (and not in cache) - // as being cached. - LLViewerInventoryCategory *llvic = (*it); - llvic->setVersion(NO_VERSION); - } - addCategory(*it); - ++child_counts[(*it)->getParentUUID()]; - } - - // Add all the items loaded which are parented to a - // category with a correctly cached parent - S32 bad_link_count = 0; - S32 good_link_count = 0; - S32 recovered_link_count = 0; - cat_map_t::iterator unparented = mCategoryMap.end(); - for(item_array_t::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) - { - LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - - if(cit != unparented) - { - const LLViewerInventoryCategory* cat = cit->second.get(); - if(cat->getVersion() != NO_VERSION) - { - // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. - if (item->getIsBrokenLink()) - { - //bad_link_count++; - LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " - << item->getName() << " itemID: " << item->getUUID() - << " assetID: " << item->getAssetUUID() - << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; - possible_broken_links.push_back(item); - continue; - } - else if (item->getIsLinkType()) - { - good_link_count++; - } - addItem(item); - cached_item_count += 1; - ++child_counts[cat->getUUID()]; - } - } - } - if (possible_broken_links.size() > 0) - { - for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); - item_iter != possible_broken_links.end(); - ++item_iter) - { - LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - const LLViewerInventoryCategory* cat = cit->second.get(); - if (item->getIsBrokenLink()) - { - bad_link_count++; - invalid_categories.insert(cit->second); - //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; - } - else - { - // was marked as broken because of loading order, its actually fine to load - addItem(item); - cached_item_count += 1; - ++child_counts[cat->getUUID()]; - recovered_link_count++; - } - } - - LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << good_link_count << " link items were successfully added. " - << recovered_link_count << " links added in recovery. " - << "The corresponding categories were invalidated." << LL_ENDL; - } - - } - else - { - // go ahead and add everything after stripping the version - // information. - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - LLViewerInventoryCategory *llvic = (*it); - llvic->setVersion(NO_VERSION); - addCategory(*it); - } - } - - // Invalidate all categories that failed fetching descendents for whatever - // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) - { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); - cat->setVersion(NO_VERSION); - LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; - } - if (invalid_categories.size() > 0) - { - LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; - } - - // At this point, we need to set the known descendents for each - // category which successfully cached so that we do not - // needlessly fetch descendents for categories which we have. - update_map_t::const_iterator no_child_counts = child_counts.end(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - LLViewerInventoryCategory* cat = (*it).get(); - if(cat->getVersion() != NO_VERSION) - { - update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); - if(the_count != no_child_counts) - { - const S32 num_descendents = (*the_count).second.mValue; - cat->setDescendentCount(num_descendents); - } - else - { - cat->setDescendentCount(0); - } - } - } - - if(remove_inventory_file) - { - // clean up the gunzipped file. - LLFile::remove(inventory_filename); - } - if(is_cache_obsolete) - { - // If out of date, remove the gzipped file too. - LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; - LLFile::remove(gzip_filename); - } - categories.clear(); // will unref and delete entries - } - - LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count - << " categories and " << cached_item_count << " items from cache." - << LL_ENDL; - - return rv; + } + } + + // go ahead and add the cats returned during the download + std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end(); + cached_category_count = cached_ids.size(); + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + if(cached_ids.find((*it)->getUUID()) == not_cached_id) + { + // this check is performed so that we do not + // mark new folders in the skeleton (and not in cache) + // as being cached. + LLViewerInventoryCategory *llvic = (*it); + llvic->setVersion(NO_VERSION); + } + addCategory(*it); + ++child_counts[(*it)->getParentUUID()]; + } + + // Add all the items loaded which are parented to a + // category with a correctly cached parent + S32 bad_link_count = 0; + S32 good_link_count = 0; + S32 recovered_link_count = 0; + cat_map_t::iterator unparented = mCategoryMap.end(); + for(item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + + if(cit != unparented) + { + const LLViewerInventoryCategory* cat = cit->second.get(); + if(cat->getVersion() != NO_VERSION) + { + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. + if (item->getIsBrokenLink()) + { + //bad_link_count++; + LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " + << item->getName() << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; + possible_broken_links.push_back(item); + continue; + } + else if (item->getIsLinkType()) + { + good_link_count++; + } + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + } + } + } + if (possible_broken_links.size() > 0) + { + for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); + item_iter != possible_broken_links.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const LLViewerInventoryCategory* cat = cit->second.get(); + if (item->getIsBrokenLink()) + { + bad_link_count++; + invalid_categories.insert(cit->second); + //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; + } + else + { + // was marked as broken because of loading order, its actually fine to load + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + recovered_link_count++; + } + } + + LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << LL_ENDL; + } + + } + else + { + // go ahead and add everything after stripping the version + // information. + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + LLViewerInventoryCategory *llvic = (*it); + llvic->setVersion(NO_VERSION); + addCategory(*it); + } + } + + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; + } + if (invalid_categories.size() > 0) + { + LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + } + + // At this point, we need to set the known descendents for each + // category which successfully cached so that we do not + // needlessly fetch descendents for categories which we have. + update_map_t::const_iterator no_child_counts = child_counts.end(); + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + LLViewerInventoryCategory* cat = (*it).get(); + if(cat->getVersion() != NO_VERSION) + { + update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); + if(the_count != no_child_counts) + { + const S32 num_descendents = (*the_count).second.mValue; + cat->setDescendentCount(num_descendents); + } + else + { + cat->setDescendentCount(0); + } + } + } + + if(remove_inventory_file) + { + // clean up the gunzipped file. + LLFile::remove(inventory_filename); + } + if(is_cache_obsolete) + { + // If out of date, remove the gzipped file too. + LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; + LLFile::remove(gzip_filename); + } + categories.clear(); // will unref and delete entries + } + + LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count + << " categories and " << cached_item_count << " items from cache." + << LL_ENDL; + + return rv; } // This is a brute force method to rebuild the entire parent-child // relations. The overall operation has O(NlogN) performance, which -// should be sufficient for our needs. +// should be sufficient for our needs. void LLInventoryModel::buildParentChildMap() { - LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; - - // *NOTE: I am skipping the logic around folder version - // synchronization here because it seems if a folder is lost, we - // might actually want to invalidate it at that point - not - // attempt to cache. More time & thought is necessary. - - // First the categories. We'll copy all of the categories into a - // temporary container to iterate over (oh for real iterators.) - // While we're at it, we'll allocate the arrays in the trees. - cat_array_t cats; - cat_array_t* catsp; - item_array_t* itemsp; - - for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - LLViewerInventoryCategory* cat = cit->second; - cats.push_back(cat); - if (mParentChildCategoryTree.count(cat->getUUID()) == 0) - { - llassert_always(mCategoryLock[cat->getUUID()] == false); - catsp = new cat_array_t; - mParentChildCategoryTree[cat->getUUID()] = catsp; - } - if (mParentChildItemTree.count(cat->getUUID()) == 0) - { - llassert_always(mItemLock[cat->getUUID()] == false); - itemsp = new item_array_t; - mParentChildItemTree[cat->getUUID()] = itemsp; - } - } - - // Insert a special parent for the root - so that lookups on - // LLUUID::null as the parent work correctly. This is kind of a - // blatent wastes of space since we allocate a block of memory for - // the array, but whatever - it's not that much space. - if (mParentChildCategoryTree.count(LLUUID::null) == 0) - { - catsp = new cat_array_t; - mParentChildCategoryTree[LLUUID::null] = catsp; - } - - // Now we have a structure with all of the categories that we can - // iterate over and insert into the correct place in the child - // category tree. - S32 count = cats.size(); - S32 i; - S32 lost = 0; - cat_array_t lost_cats; - for(i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = cats.at(i); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp && - // Only the two root folders should be children of null. - // Others should go to lost & found. - (cat->getParentUUID().notNull() || - cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) - { - catsp->push_back(cat); - } - else - { - // *NOTE: This process could be a lot more efficient if we - // used the new MoveInventoryFolder message, but we would - // have to continue to do the update & build here. So, to - // implement it, we would need a set or map of uuid pairs - // which would be (folder_id, new_parent_id) to be sent up - // to the server. - LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " - << cat->getName() << LL_ENDL; - ++lost; - lost_cats.push_back(cat); - } - } - if(lost) - { - LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; - } - - // Do moves in a separate pass to make sure we've properly filed - // the FT_LOST_AND_FOUND category before we try to find its UUID. - for(i = 0; i<lost_cats.size(); ++i) - { - LLViewerInventoryCategory *cat = lost_cats.at(i); - - // plop it into the lost & found. - LLFolderType::EType pref = cat->getPreferredType(); - if(LLFolderType::FT_NONE == pref) - { - cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - } - else if(LLFolderType::FT_ROOT_INVENTORY == pref) - { - // it's the root - cat->setParent(LLUUID::null); - } - else - { - // it's a protected folder. - cat->setParent(gInventory.getRootFolderID()); - } - // FIXME note that updateServer() fails with protected - // types, so this will not work as intended in that case. - // UpdateServer uses AIS, AIS cat move is not implemented yet - // cat->updateServer(TRUE); - - // MoveInventoryFolder message, intentionally per item - cat->updateParentOnServer(FALSE); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp) - { - catsp->push_back(cat); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - - const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); - sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); - - - // Now the items. We allocated in the last step, so now all we - // have to do is iterate over the items and put them in the right - // place. - item_array_t items; - if(!mItemMap.empty()) - { - LLPointer<LLViewerInventoryItem> item; - for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - item = (*iit).second; - items.push_back(item); - } - } - count = items.size(); - lost = 0; - uuid_vec_t lost_item_ids; - for(i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryItem> item; - item = items.at(i); - itemsp = getUnlockedItemArray(item->getParentUUID()); - if(itemsp) - { - itemsp->push_back(item); - } - else - { - LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " - << item->getName() << LL_ENDL; - ++lost; - // plop it into the lost & found. - // - item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - // move it later using a special message to move items. If - // we update server here, the client might crash. - //item->updateServer(); - lost_item_ids.push_back(item->getUUID()); - itemsp = getUnlockedItemArray(item->getParentUUID()); - if(itemsp) - { - itemsp->push_back(item); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - } - if(lost) - { - LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - for(uuid_vec_t::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it) - { - if(start_new_message) - { - start_new_message = FALSE; - msg->newMessageFast(_PREHASH_MoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOLFast(_PREHASH_Stamp, FALSE); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, (*it)); - msg->addUUIDFast(_PREHASH_FolderID, lnf); - msg->addString("NewName", NULL); - if(msg->isSendFull(NULL)) - { - start_new_message = TRUE; - gAgent.sendReliableMessage(); - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - } - } - - const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); - if (agent_inv_root_id.notNull()) - { - cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); - if(catsp) - { - // *HACK - fix root inventory folder - // some accounts has pbroken inventory root folders - - std::string name = "My Inventory"; - for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), - it_end = mParentChildCategoryTree.end(); it != it_end; ++it) - { - cat_array_t* cat_array = it->second; - for (cat_array_t::const_iterator cat_it = cat_array->begin(), - cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) - { - LLPointer<LLViewerInventoryCategory> category = *cat_it; - - if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) - continue; - if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) - { - if(category->getUUID()!=mRootFolderID) - { - LLUUID& new_inv_root_folder_id = const_cast<LLUUID&>(mRootFolderID); - new_inv_root_folder_id = category->getUUID(); - } - } - } - } - - LLPointer<LLInventoryValidationInfo> validation_info = validate(); - if (validation_info->mFatalErrorCount > 0) - { - // Fatal inventory error. Will not be able to engage in many inventory operations. - // This should be followed by an error dialog leading to logout. - LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " - << "Will not be able to do normal inventory operations in this session." - << LL_ENDL; - mIsAgentInvUsable = false; - } - else - { - mIsAgentInvUsable = true; - } - validation_info->mInitialized = true; - mValidationInfo = validation_info; - - // notifyObservers() has been moved to - // llstartup/idle_startup() after this func completes. - // Allows some system categories to be created before - // observers start firing. - } - } + LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; + + // *NOTE: I am skipping the logic around folder version + // synchronization here because it seems if a folder is lost, we + // might actually want to invalidate it at that point - not + // attempt to cache. More time & thought is necessary. + + // First the categories. We'll copy all of the categories into a + // temporary container to iterate over (oh for real iterators.) + // While we're at it, we'll allocate the arrays in the trees. + cat_array_t cats; + cat_array_t* catsp; + item_array_t* itemsp; + + for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + LLViewerInventoryCategory* cat = cit->second; + cats.push_back(cat); + if (mParentChildCategoryTree.count(cat->getUUID()) == 0) + { + llassert_always(mCategoryLock[cat->getUUID()] == false); + catsp = new cat_array_t; + mParentChildCategoryTree[cat->getUUID()] = catsp; + } + if (mParentChildItemTree.count(cat->getUUID()) == 0) + { + llassert_always(mItemLock[cat->getUUID()] == false); + itemsp = new item_array_t; + mParentChildItemTree[cat->getUUID()] = itemsp; + } + } + + // Insert a special parent for the root - so that lookups on + // LLUUID::null as the parent work correctly. This is kind of a + // blatent wastes of space since we allocate a block of memory for + // the array, but whatever - it's not that much space. + if (mParentChildCategoryTree.count(LLUUID::null) == 0) + { + catsp = new cat_array_t; + mParentChildCategoryTree[LLUUID::null] = catsp; + } + + // Now we have a structure with all of the categories that we can + // iterate over and insert into the correct place in the child + // category tree. + S32 count = cats.size(); + S32 i; + S32 lost = 0; + cat_array_t lost_cats; + for(i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = cats.at(i); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp && + // Only the two root folders should be children of null. + // Others should go to lost & found. + (cat->getParentUUID().notNull() || + cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) + { + catsp->push_back(cat); + } + else + { + // *NOTE: This process could be a lot more efficient if we + // used the new MoveInventoryFolder message, but we would + // have to continue to do the update & build here. So, to + // implement it, we would need a set or map of uuid pairs + // which would be (folder_id, new_parent_id) to be sent up + // to the server. + LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " + << cat->getName() << LL_ENDL; + ++lost; + lost_cats.push_back(cat); + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; + } + + // Do moves in a separate pass to make sure we've properly filed + // the FT_LOST_AND_FOUND category before we try to find its UUID. + for(i = 0; i<lost_cats.size(); ++i) + { + LLViewerInventoryCategory *cat = lost_cats.at(i); + + // plop it into the lost & found. + LLFolderType::EType pref = cat->getPreferredType(); + if(LLFolderType::FT_NONE == pref) + { + cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + } + else if(LLFolderType::FT_ROOT_INVENTORY == pref) + { + // it's the root + cat->setParent(LLUUID::null); + } + else + { + // it's a protected folder. + cat->setParent(gInventory.getRootFolderID()); + } + // FIXME note that updateServer() fails with protected + // types, so this will not work as intended in that case. + // UpdateServer uses AIS, AIS cat move is not implemented yet + // cat->updateServer(TRUE); + + // MoveInventoryFolder message, intentionally per item + cat->updateParentOnServer(FALSE); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp) + { + catsp->push_back(cat); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + + const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); + sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); + + + // Now the items. We allocated in the last step, so now all we + // have to do is iterate over the items and put them in the right + // place. + item_array_t items; + if(!mItemMap.empty()) + { + LLPointer<LLViewerInventoryItem> item; + for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + item = (*iit).second; + items.push_back(item); + } + } + count = items.size(); + lost = 0; + uuid_vec_t lost_item_ids; + for(i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryItem> item; + item = items.at(i); + itemsp = getUnlockedItemArray(item->getParentUUID()); + if(itemsp) + { + itemsp->push_back(item); + } + else + { + LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " + << item->getName() << LL_ENDL; + ++lost; + // plop it into the lost & found. + // + item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + // move it later using a special message to move items. If + // we update server here, the client might crash. + //item->updateServer(); + lost_item_ids.push_back(item->getUUID()); + itemsp = getUnlockedItemArray(item->getParentUUID()); + if(itemsp) + { + itemsp->push_back(item); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + for(uuid_vec_t::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it) + { + if(start_new_message) + { + start_new_message = FALSE; + msg->newMessageFast(_PREHASH_MoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addBOOLFast(_PREHASH_Stamp, FALSE); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, (*it)); + msg->addUUIDFast(_PREHASH_FolderID, lnf); + msg->addString("NewName", NULL); + if(msg->isSendFull(NULL)) + { + start_new_message = TRUE; + gAgent.sendReliableMessage(); + } + } + if(!start_new_message) + { + gAgent.sendReliableMessage(); + } + } + + const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); + if (agent_inv_root_id.notNull()) + { + cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); + if(catsp) + { + // *HACK - fix root inventory folder + // some accounts has pbroken inventory root folders + + std::string name = "My Inventory"; + for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), + it_end = mParentChildCategoryTree.end(); it != it_end; ++it) + { + cat_array_t* cat_array = it->second; + for (cat_array_t::const_iterator cat_it = cat_array->begin(), + cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) + { + LLPointer<LLViewerInventoryCategory> category = *cat_it; + + if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) + continue; + if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) + { + if(category->getUUID()!=mRootFolderID) + { + LLUUID& new_inv_root_folder_id = const_cast<LLUUID&>(mRootFolderID); + new_inv_root_folder_id = category->getUUID(); + } + } + } + } + + LLPointer<LLInventoryValidationInfo> validation_info = validate(); + if (validation_info->mFatalErrorCount > 0) + { + // Fatal inventory error. Will not be able to engage in many inventory operations. + // This should be followed by an error dialog leading to logout. + LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " + << "Will not be able to do normal inventory operations in this session." + << LL_ENDL; + mIsAgentInvUsable = false; + } + else + { + mIsAgentInvUsable = true; + } + validation_info->mInitialized = true; + mValidationInfo = validation_info; + + // notifyObservers() has been moved to + // llstartup/idle_startup() after this func completes. + // Allows some system categories to be created before + // observers start firing. + } + } } // Would normally do this at construction but that's too early @@ -3202,22 +3202,22 @@ void LLInventoryModel::buildParentChildMap() // call set things up. void LLInventoryModel::initHttpRequest() { - if (! mHttpRequestFG) - { - // Haven't initialized, get to it - LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); - - mHttpRequestFG = new LLCore::HttpRequest; - mHttpRequestBG = new LLCore::HttpRequest; - mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); - mHttpOptions->setTransferTimeout(300); - mHttpOptions->setUseRetryAfter(true); - // mHttpOptions->setTrace(2); // Do tracing of requests + if (! mHttpRequestFG) + { + // Haven't initialized, get to it + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + + mHttpRequestFG = new LLCore::HttpRequest; + mHttpRequestBG = new LLCore::HttpRequest; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + mHttpOptions->setTransferTimeout(300); + mHttpOptions->setUseRetryAfter(true); + // mHttpOptions->setTrace(2); // Do tracing of requests mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); - mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); - mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); - mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); - } + mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); + mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); + } if (!gGenericDispatcher.isHandlerPresent("BulkUpdateInventory")) { @@ -3227,49 +3227,49 @@ void LLInventoryModel::initHttpRequest() void LLInventoryModel::handleResponses(bool foreground) { - if (foreground && mHttpRequestFG) - { - mHttpRequestFG->update(0); - } - else if (! foreground && mHttpRequestBG) - { - mHttpRequestBG->update(50000L); - } + if (foreground && mHttpRequestFG) + { + mHttpRequestFG->update(0); + } + else if (! foreground && mHttpRequestBG) + { + mHttpRequestBG->update(50000L); + } } LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground, - const std::string & url, - const LLSD & body, - const LLCore::HttpHandler::ptr_t &handler, - const char * const message) + const std::string & url, + const LLSD & body, + const LLCore::HttpHandler::ptr_t &handler, + const char * const message) { - if (! mHttpRequestFG) - { - // We do the initialization late and lazily as this class is - // statically-constructed and not all the bits are ready at - // that time. - initHttpRequest(); - } - - LLCore::HttpRequest * request(foreground ? mHttpRequestFG : mHttpRequestBG); - LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - - handle = LLCoreHttpUtil::requestPostWithLLSD(request, - mHttpPolicyClass, - url, - body, - mHttpOptions, - mHttpHeaders, - handler); - if (LLCORE_HTTP_HANDLE_INVALID == handle) - { - LLCore::HttpStatus status(request->getStatus()); - LL_WARNS(LOG_INV) << "HTTP POST request failed for " << message - << ", Status: " << status.toTerseString() - << " Reason: '" << status.toString() << "'" - << LL_ENDL; - } - return handle; + if (! mHttpRequestFG) + { + // We do the initialization late and lazily as this class is + // statically-constructed and not all the bits are ready at + // that time. + initHttpRequest(); + } + + LLCore::HttpRequest * request(foreground ? mHttpRequestFG : mHttpRequestBG); + LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + + handle = LLCoreHttpUtil::requestPostWithLLSD(request, + mHttpPolicyClass, + url, + body, + mHttpOptions, + mHttpHeaders, + handler); + if (LLCORE_HTTP_HANDLE_INVALID == handle) + { + LLCore::HttpStatus status(request->getStatus()); + LL_WARNS(LOG_INV) << "HTTP POST request failed for " << message + << ", Status: " << status.toTerseString() + << " Reason: '" << status.toString() << "'" + << LL_ENDL; + } + return handle; } void LLInventoryModel::createCommonSystemCategories() @@ -3277,12 +3277,12 @@ void LLInventoryModel::createCommonSystemCategories() //amount of System Folder we should wait for sPendingSystemFolders = 9; - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS); gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MATERIAL); // probably should be server created gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX); @@ -3290,154 +3290,154 @@ void LLInventoryModel::createCommonSystemCategories() struct LLUUIDAndName { - LLUUIDAndName() {} - LLUUIDAndName(const LLUUID& id, const std::string& name); - bool operator==(const LLUUIDAndName& rhs) const; - bool operator<(const LLUUIDAndName& rhs) const; - bool operator>(const LLUUIDAndName& rhs) const; - - LLUUID mID; - std::string mName; + LLUUIDAndName() {} + LLUUIDAndName(const LLUUID& id, const std::string& name); + bool operator==(const LLUUIDAndName& rhs) const; + bool operator<(const LLUUIDAndName& rhs) const; + bool operator>(const LLUUIDAndName& rhs) const; + + LLUUID mID; + std::string mName; }; LLUUIDAndName::LLUUIDAndName(const LLUUID& id, const std::string& name) : - mID(id), mName(name) + mID(id), mName(name) { } bool LLUUIDAndName::operator==(const LLUUIDAndName& rhs) const { - return ((mID == rhs.mID) && (mName == rhs.mName)); + return ((mID == rhs.mID) && (mName == rhs.mName)); } bool LLUUIDAndName::operator<(const LLUUIDAndName& rhs) const { - return (mID < rhs.mID); + return (mID < rhs.mID); } bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const { - return (mID > rhs.mID); + return (mID > rhs.mID); } // static bool LLInventoryModel::loadFromFile(const std::string& filename, - LLInventoryModel::cat_array_t& categories, - LLInventoryModel::item_array_t& items, - LLInventoryModel::changed_items_t& cats_to_update, - bool &is_cache_obsolete) + LLInventoryModel::cat_array_t& categories, + LLInventoryModel::item_array_t& items, + LLInventoryModel::changed_items_t& cats_to_update, + bool &is_cache_obsolete) { LL_PROFILE_ZONE_NAMED("inventory load from file"); - if(filename.empty()) - { - LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; - return false; - } - LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; - - llifstream file(filename.c_str()); - - if (!file.is_open()) - { - LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; - return false; - } - - is_cache_obsolete = true; // Obsolete until proven current - - //U64 lines_count = 0U; - std::string line; - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - while (std::getline(file, line)) - { - LLSD s_item; - std::istringstream iss(line); - if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; - break; - } - - if (s_item.has("inv_cache_version")) - { - S32 version = s_item["inv_cache_version"].asInteger(); - if (version == sCurrentInvCacheVersion) - { - // Cache is up to date - is_cache_obsolete = false; - continue; - } - else - { - LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; - break; - } - } - else if (s_item.has("cat_id")) - { - if (is_cache_obsolete) - break; - - LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importLLSD(s_item)) - { - categories.push_back(inv_cat); - } - } - else if (s_item.has("item_id")) - { - if (is_cache_obsolete) - break; - - LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; - if( inv_item->fromLLSD(s_item) ) - { - if(inv_item->getUUID().isNull()) - { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - } - else - { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) - { - cats_to_update.insert(inv_item->getParentUUID()); - } - else - { - items.push_back(inv_item); - } - } - } - } + if(filename.empty()) + { + LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; + return false; + } + LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; + + llifstream file(filename.c_str()); + + if (!file.is_open()) + { + LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; + return false; + } + + is_cache_obsolete = true; // Obsolete until proven current + + //U64 lines_count = 0U; + std::string line; + LLPointer<LLSDParser> parser = new LLSDNotationParser(); + while (std::getline(file, line)) + { + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; + break; + } + + if (s_item.has("inv_cache_version")) + { + S32 version = s_item["inv_cache_version"].asInteger(); + if (version == sCurrentInvCacheVersion) + { + // Cache is up to date + is_cache_obsolete = false; + continue; + } + else + { + LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; + break; + } + } + else if (s_item.has("cat_id")) + { + if (is_cache_obsolete) + break; + + LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if(inv_cat->importLLSD(s_item)) + { + categories.push_back(inv_cat); + } + } + else if (s_item.has("item_id")) + { + if (is_cache_obsolete) + break; + + LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; + if( inv_item->fromLLSD(s_item) ) + { + if(inv_item->getUUID().isNull()) + { + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; + } + else + { + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } + } + } + } // TODO(brad) - figure out how to reenable this without breaking everything else -// static constexpr U64 BATCH_SIZE = 512U; -// if ((++lines_count % BATCH_SIZE) == 0) -// { -// // SL-19968 - make sure message system code gets a chance to run every so often -// pump_idle_startup_network(); -// } - } +// static constexpr U64 BATCH_SIZE = 512U; +// if ((++lines_count % BATCH_SIZE) == 0) +// { +// // SL-19968 - make sure message system code gets a chance to run every so often +// pump_idle_startup_network(); +// } + } - file.close(); + file.close(); - return !is_cache_obsolete; + return !is_cache_obsolete; } // static bool LLInventoryModel::saveToFile(const std::string& filename, - const cat_array_t& categories, - const item_array_t& items) + const cat_array_t& categories, + const item_array_t& items) { - if (filename.empty()) - { - LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; - return false; - } + if (filename.empty()) + { + LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; + return false; + } - LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; + LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; try { @@ -3509,46 +3509,46 @@ bool LLInventoryModel::saveToFile(const std::string& filename, // static void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) { - //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate, - // processInventoryUpdate, - // NULL); - //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory, - // processUseCachedInventory, - // NULL); - msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem, - processUpdateCreateInventoryItem, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, - processRemoveInventoryItem, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, - processRemoveInventoryFolder, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, - processRemoveInventoryObjects, - NULL); - msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory, - processSaveAssetIntoInventory, - NULL); - msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, - processBulkUpdateInventory, - NULL); - msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem); + //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate, + // processInventoryUpdate, + // NULL); + //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory, + // processUseCachedInventory, + // NULL); + msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem, + processUpdateCreateInventoryItem, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, + processRemoveInventoryItem, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, + processRemoveInventoryFolder, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, + processRemoveInventoryObjects, + NULL); + msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory, + processSaveAssetIntoInventory, + NULL); + msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, + processBulkUpdateInventory, + NULL); + msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem); } -// static +// static void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**) { - // do accounting and highlight new items if they arrive - if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) - { - U32 callback_id; - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); - msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id); + // do accounting and highlight new items if they arrive + if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) + { + U32 callback_id; + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); + msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id); - gInventoryCallbacks.fire(callback_id, item_id); + gInventoryCallbacks.fire(callback_id, item_id); // Message system at the moment doesn't support Thumbnails and potential // newer features so just rerequest whole item @@ -3556,251 +3556,251 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo // todo: instead of unpacking message fully, // grab only an item_id, then fetch LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true); - } + } } bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask) { - //make sure our added inventory observer is active - start_new_inventory_observer(); - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id - << LL_ENDL; - return false; - } - item_array_t items; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - // Does this loop ever execute more than once? - for(S32 i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " - << titem->getUUID() << LL_ENDL; - items.push_back(titem); - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) - { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; - } - } - if(account) - { - gInventory.accountForUpdate(update); - } - - if (account) - { - mask |= LLInventoryObserver::CREATE; - } - //as above, this loop never seems to loop more than once per call - for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - gInventory.updateItem(*it, mask); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); - - return true; -} - -// static -void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) -{ - LLUUID item_id; - S32 count = msg->getNumberOfBlocksFast(msg_label); - LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; - uuid_vec_t item_ids; - update_map_t update; - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); - LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if(itemp) - { - LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; - // we only bother with the delete and account if we found - // the item - this is usually a back-up for permissions, - // so frequently the item will already be gone. - --update[itemp->getParentUUID()]; - item_ids.push_back(item_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; - gInventory.deleteObject(*it); - } -} - -// static -void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) -{ - LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; - LLUUID agent_id, item_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); - gInventory.notifyObservers(); -} + //make sure our added inventory observer is active + start_new_inventory_observer(); -// static -void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, - LLMessageSystem* msg) + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return false; + } + item_array_t items; + update_map_t update; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + // Does this loop ever execute more than once? + for(S32 i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + titem->unpackMessage(msg, _PREHASH_InventoryData, i); + LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + // examine update for changes. + LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); + if(itemp) + { + if(titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + } + if(account) + { + gInventory.accountForUpdate(update); + } + + if (account) + { + mask |= LLInventoryObserver::CREATE; + } + //as above, this loop never seems to loop more than once per call + for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + gInventory.updateItem(*it, mask); + } + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); + + return true; +} + +// static +void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) +{ + LLUUID item_id; + S32 count = msg->getNumberOfBlocksFast(msg_label); + LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; + uuid_vec_t item_ids; + update_map_t update; + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); + LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if(itemp) + { + LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; + // we only bother with the delete and account if we found + // the item - this is usually a back-up for permissions, + // so frequently the item will already be gone. + --update[itemp->getParentUUID()]; + item_ids.push_back(item_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) + { + LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; + gInventory.deleteObject(*it); + } +} + +// static +void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) { - LLUUID folder_id; - uuid_vec_t folder_ids; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i); - LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id); - if(folderp) - { - --update[folderp->getParentUUID()]; - folder_ids.push_back(folder_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) - { - gInventory.deleteObject(*it); - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; + LLUUID agent_id, item_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); + gInventory.notifyObservers(); } -// static +// static +void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, + LLMessageSystem* msg) +{ + LLUUID folder_id; + uuid_vec_t folder_ids; + update_map_t update; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i); + LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id); + if(folderp) + { + --update[folderp->getParentUUID()]; + folder_ids.push_back(folder_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) + { + gInventory.deleteObject(*it); + } +} + +// static void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, - void**) + void**) { - LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; - LLUUID agent_id, session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryFolder( agent_id, msg ); - gInventory.notifyObservers(); + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + gInventory.notifyObservers(); } -// static +// static void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, - void**) + void**) { - LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; - LLUUID agent_id, session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryFolder( agent_id, msg ); - LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); - gInventory.notifyObservers(); + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); + gInventory.notifyObservers(); } -// static +// static void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, - void**) + void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." - << LL_ENDL; - return; - } - - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); - - // The viewer ignores the asset id because this message is only - // used for attachments/objects, so the asset id is not used in - // the viewer anyway. - LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" - << item_id << LL_ENDL; - LLViewerInventoryItem* item = gInventory.getItem( item_id ); - if( item ) - { - LLCategoryUpdate up(item->getParentUUID(), 0); - gInventory.accountForUpdate(up); - gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id); - gInventory.notifyObservers(); - } - else - { - LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" - " not found: " << item_id << LL_ENDL; - } - if(gViewerWindow) - { - gViewerWindow->getWindow()->decBusyCount(); - } + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." + << LL_ENDL; + return; + } + + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); + + // The viewer ignores the asset id because this message is only + // used for attachments/objects, so the asset id is not used in + // the viewer anyway. + LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" + << item_id << LL_ENDL; + LLViewerInventoryItem* item = gInventory.getItem( item_id ); + if( item ) + { + LLCategoryUpdate up(item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id); + gInventory.notifyObservers(); + } + else + { + LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" + " not found: " << item_id << LL_ENDL; + } + if(gViewerWindow) + { + gViewerWindow->getWindow()->decBusyCount(); + } } // static void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; - return; - } - LLUUID tid; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; + return; + } + LLUUID tid; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); #ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; + LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; #endif - update_map_t update; - cat_array_t folders; - S32 count; - S32 i; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID()); - tfolder->unpackMessage(msg, _PREHASH_FolderData, i); - LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" - << tfolder->getUUID() << ") in " << tfolder->getParentUUID() - << LL_ENDL; - + update_map_t update; + cat_array_t folders; + S32 count; + S32 i; + count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + for(i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID()); + tfolder->unpackMessage(msg, _PREHASH_FolderData, i); + LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" + << tfolder->getUUID() << ") in " << tfolder->getParentUUID() + << LL_ENDL; + // If the folder is a listing or a version folder, all we need to do is update the SLM data int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID()); if ((depth_folder == 1) || (depth_folder == 2)) @@ -3811,12 +3811,12 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLMarketplaceData::instance().getListing(listing_id); // In that case, there is no item to update so no callback -> we skip the rest of the update } - else if(tfolder->getUUID().notNull()) - { - folders.push_back(tfolder); - LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); - if(folderp) - { + else if(tfolder->getUUID().notNull()) + { + folders.push_back(tfolder); + LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { if (tfolder->getParentUUID() == folderp->getParentUUID()) @@ -3833,15 +3833,15 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - else - { - // we could not find the folder, so it is probably - // new. However, we only want to attempt accounting - // for the parent if we can find the parent. - folderp = gInventory.getCategory(tfolder->getParentUUID()); - if(folderp) - { + } + else + { + // we could not find the folder, so it is probably + // new. However, we only want to attempt accounting + // for the parent if we can find the parent. + folderp = gInventory.getCategory(tfolder->getParentUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { ++update[tfolder->getParentUUID()]; @@ -3850,51 +3850,51 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - } - } - } - - - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - uuid_vec_t wearable_ids; - item_array_t items; - std::list<InventoryCallbackInfo> cblist; - for(i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - titem->unpackMessage(msg, _PREHASH_ItemData, i); - LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " - << titem->getParentUUID() << LL_ENDL; - U32 callback_id; - msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); - if(titem->getUUID().notNull() ) // && callback_id.notNull() ) - { - items.push_back(titem); - cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); - if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) - { - wearable_ids.push_back(titem->getUUID()); - } - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) - { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); - if(folderp) - { + } + } + } + } + + + count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); + uuid_vec_t wearable_ids; + item_array_t items; + std::list<InventoryCallbackInfo> cblist; + for(i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + titem->unpackMessage(msg, _PREHASH_ItemData, i); + LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " + << titem->getParentUUID() << LL_ENDL; + U32 callback_id; + msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); + if(titem->getUUID().notNull() ) // && callback_id.notNull() ) + { + items.push_back(titem); + cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); + if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) + { + wearable_ids.push_back(titem->getUUID()); + } + // examine update for changes. + LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); + if(itemp) + { + if(titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { ++update[titem->getParentUUID()]; @@ -3903,18 +3903,18 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - } - } - else - { - cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); - } - } - gInventory.accountForUpdate(update); - - for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) - { + } + } + } + else + { + cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); + } + } + gInventory.accountForUpdate(update); + + for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) + { gInventory.updateCategory(*cit); if ((*cit)->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { @@ -3924,100 +3924,100 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); } // else already called fetch() above - } - for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) - { - gInventory.updateItem(*iit); + } + for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) + { + gInventory.updateItem(*iit); // Temporary workaround: just fetch the item using AIS to get missing fields. // If this works fine we might want to extract 'ids only' from the message // then use AIS as a primary fetcher LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true); - } - gInventory.notifyObservers(); - - // The incoming inventory could span more than one BulkInventoryUpdate packet, - // so record the transaction ID for this purchase, then wear all clothing - // that comes in as part of that transaction ID. JC - if (LLInventoryState::sWearNewClothing) - { - LLInventoryState::sWearNewClothingTransactionID = tid; - LLInventoryState::sWearNewClothing = FALSE; - } - - if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) - { - count = wearable_ids.size(); - for (i = 0; i < count; ++i) - { - LLViewerInventoryItem* wearable_item; - wearable_item = gInventory.getItem(wearable_ids[i]); - LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); - } - } - - std::list<InventoryCallbackInfo>::iterator inv_it; - for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) - { - InventoryCallbackInfo cbinfo = (*inv_it); - gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); - } + } + gInventory.notifyObservers(); + + // The incoming inventory could span more than one BulkInventoryUpdate packet, + // so record the transaction ID for this purchase, then wear all clothing + // that comes in as part of that transaction ID. JC + if (LLInventoryState::sWearNewClothing) + { + LLInventoryState::sWearNewClothingTransactionID = tid; + LLInventoryState::sWearNewClothing = FALSE; + } + + if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) + { + count = wearable_ids.size(); + for (i = 0; i < count; ++i) + { + LLViewerInventoryItem* wearable_item; + wearable_item = gInventory.getItem(wearable_ids[i]); + LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); + } + } + + std::list<InventoryCallbackInfo>::iterator inv_it; + for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) + { + InventoryCallbackInfo cbinfo = (*inv_it); + gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); + } } // static void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) { - LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." - << LL_ENDL; - return; - } - - LLUUID item_id; - LLUUID folder_id; - std::string new_name; - bool anything_changed = false; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if(item) - { - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); - msg->getString("InventoryData", "NewName", new_name, i); - - LL_DEBUGS() << "moving item " << item_id << " to folder " - << folder_id << LL_ENDL; - update_list_t update; - LLCategoryUpdate old_folder(item->getParentUUID(), -1); - update.push_back(old_folder); - LLCategoryUpdate new_folder(folder_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - new_item->setParent(folder_id); - if (new_name.length() > 0) - { - new_item->rename(new_name); - } - gInventory.updateItem(new_item); - anything_changed = true; - } - else - { - LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; - } - } - if(anything_changed) - { - gInventory.notifyObservers(); - } + LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." + << LL_ENDL; + return; + } + + LLUUID item_id; + LLUUID folder_id; + std::string new_name; + bool anything_changed = false; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if(item) + { + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); + msg->getString("InventoryData", "NewName", new_name, i); + + LL_DEBUGS() << "moving item " << item_id << " to folder " + << folder_id << LL_ENDL; + update_list_t update; + LLCategoryUpdate old_folder(item->getParentUUID(), -1); + update.push_back(old_folder); + LLCategoryUpdate new_folder(folder_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + new_item->setParent(folder_id); + if (new_name.length() > 0) + { + new_item->rename(new_name); + } + gInventory.updateItem(new_item); + anything_changed = true; + } + else + { + LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; + } + } + if(anything_changed) + { + gInventory.notifyObservers(); + } } //---------------------------------------------------------------------------- @@ -4026,274 +4026,274 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purge_descendents_of(folder_id, NULL); + } + return false; } void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderType::EType preferred_type) { - if (!notification.empty()) - { - LLSD args; - if(LLFolderType::FT_TRASH == preferred_type) - { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - const LLUUID trash_id = findCategoryUUIDForType(preferred_type); - gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants - S32 item_count = items.size() + cats.size(); - args["COUNT"] = item_count; - } - LLNotificationsUtil::add(notification, args, LLSD(), - boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); - } - else - { - const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); - } + if (!notification.empty()) + { + LLSD args; + if(LLFolderType::FT_TRASH == preferred_type) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + const LLUUID trash_id = findCategoryUUIDForType(preferred_type); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants + S32 item_count = items.size() + cats.size(); + args["COUNT"] = item_count; + } + LLNotificationsUtil::add(notification, args, LLSD(), + boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); + } + else + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purge_descendents_of(folder_id, NULL); + } } //---------------------------------------------------------------------------- void LLInventoryModel::removeItem(const LLUUID& item_id) { - LLViewerInventoryItem* item = getItem(item_id); - if (! item) - { - LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; - } - else - { - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (new_parent.notNull()) - { - LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; - changeItemParent(item, new_parent, TRUE); - } - } + LLViewerInventoryItem* item = getItem(item_id); + if (! item) + { + LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (new_parent.notNull()) + { + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); + } + } } void LLInventoryModel::removeCategory(const LLUUID& category_id) { - if (! get_is_category_removable(this, category_id)) - { - return; - } - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - collectDescendents(category_id, descendent_categories, descendent_items, FALSE); - - for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); - iter != descendent_items.end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - const LLUUID& item_id = item->getUUID(); - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item_id)) - { - LLGestureMgr::instance().deactivateGesture(item_id); - } - } - - LLViewerInventoryCategory* cat = getCategory(category_id); - if (cat) - { - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (trash_id.notNull()) - { - changeCategoryParent(cat, trash_id, TRUE); - } - } - - checkTrashOverflow(); + if (! get_is_category_removable(this, category_id)) + { + return; + } + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + collectDescendents(category_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + const LLUUID& item_id = item->getUUID(); + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item_id)) + { + LLGestureMgr::instance().deactivateGesture(item_id); + } + } + + LLViewerInventoryCategory* cat = getCategory(category_id); + if (cat) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull()) + { + changeCategoryParent(cat, trash_id, TRUE); + } + } + + checkTrashOverflow(); } void LLInventoryModel::removeObject(const LLUUID& object_id) { - if(object_id.isNull()) - { - return; - } - - LLInventoryObject* obj = getObject(object_id); - if (dynamic_cast<LLViewerInventoryItem*>(obj)) - { - removeItem(object_id); - } - else if (dynamic_cast<LLViewerInventoryCategory*>(obj)) - { - removeCategory(object_id); - } - else if (obj) - { - LL_WARNS("Inventory") << "object ID " << object_id - << " is an object of unrecognized class " - << typeid(*obj).name() << LL_ENDL; - } - else - { - LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; - } + if(object_id.isNull()) + { + return; + } + + LLInventoryObject* obj = getObject(object_id); + if (dynamic_cast<LLViewerInventoryItem*>(obj)) + { + removeItem(object_id); + } + else if (dynamic_cast<LLViewerInventoryCategory*>(obj)) + { + removeCategory(object_id); + } + else if (obj) + { + LL_WARNS("Inventory") << "object ID " << object_id + << " is an object of unrecognized class " + << typeid(*obj).name() << LL_ENDL; + } + else + { + LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; + } } bool callback_preview_trash_folder(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - LLFloaterPreviewTrash::show(); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + LLFloaterPreviewTrash::show(); + } + return false; } void LLInventoryModel::checkTrashOverflow() { - static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); - - // Collect all descendants including those in subfolders. - // - // Note: Do we really need content of subfolders? - // This was made to prevent download of trash folder timeouting - // viewer and sub-folders are supposed to download independently. - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); - S32 item_count = items.size() + cats.size(); - - if (item_count >= trash_max_capacity) - { - if (LLFloaterPreviewTrash::isVisible()) - { - // bring to front - LLFloaterPreviewTrash::show(); - } - else - { - LLNotificationsUtil::add("TrashIsFull", LLSD(), LLSD(), - boost::bind(callback_preview_trash_folder, _1, _2)); - } - } + static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); + + // Collect all descendants including those in subfolders. + // + // Note: Do we really need content of subfolders? + // This was made to prevent download of trash folder timeouting + // viewer and sub-folders are supposed to download independently. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + S32 item_count = items.size() + cats.size(); + + if (item_count >= trash_max_capacity) + { + if (LLFloaterPreviewTrash::isVisible()) + { + // bring to front + LLFloaterPreviewTrash::show(); + } + else + { + LLNotificationsUtil::add("TrashIsFull", LLSD(), LLSD(), + boost::bind(callback_preview_trash_folder, _1, _2)); + } + } } const LLUUID &LLInventoryModel::getRootFolderID() const { - return mRootFolderID; + return mRootFolderID; } void LLInventoryModel::setRootFolderID(const LLUUID& val) { - mRootFolderID = val; + mRootFolderID = val; } const LLUUID &LLInventoryModel::getLibraryRootFolderID() const { - return mLibraryRootFolderID; + return mLibraryRootFolderID; } void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val) { - mLibraryRootFolderID = val; + mLibraryRootFolderID = val; } const LLUUID &LLInventoryModel::getLibraryOwnerID() const { - return mLibraryOwnerID; + return mLibraryOwnerID; } void LLInventoryModel::setLibraryOwnerID(const LLUUID& val) { - mLibraryOwnerID = val; + mLibraryOwnerID = val; } // static BOOL LLInventoryModel::getIsFirstTimeInViewer2() { - // Do not call this before parentchild map is built. - if (!gInventory.mIsAgentInvUsable) - { - LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; - return TRUE; - } - - return sFirstTimeInViewer2; + // Do not call this before parentchild map is built. + if (!gInventory.mIsAgentInvUsable) + { + LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; + return TRUE; + } + + return sFirstTimeInViewer2; } LLInventoryModel::item_array_t::iterator LLInventoryModel::findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) { - LLInventoryModel::item_array_t::iterator curr_item = items.begin(); - - while (curr_item != items.end()) - { - if ((*curr_item)->getUUID() == id) - { - break; - } - ++curr_item; - } - - return curr_item; + LLInventoryModel::item_array_t::iterator curr_item = items.begin(); + + while (curr_item != items.end()) + { + if ((*curr_item)->getUUID() == id) + { + break; + } + ++curr_item; + } + + return curr_item; } // static // * @param[in, out] items - vector with items to be updated. It should be sorted in a right way // * before calling this method. // * @param src_item_id - LLUUID of inventory item to be moved in new position -// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should +// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should // * be placed. -// * @param insert_before - bool indicating if src_item_id should be placed before or after +// * @param insert_before - bool indicating if src_item_id should be placed before or after // * dest_item_id. Default is true. void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id, bool insert_before) { - LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); - LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); - - // If one of the passed UUID is not in the item list, bail out - if ((it_src == items.end()) || (it_dest == items.end())) - return; - - // Erase the source element from the list, keep a copy before erasing. - LLViewerInventoryItem* src_item = *it_src; - items.erase(it_src); - - // Note: Target iterator is not valid anymore because the container was changed, so update it. - it_dest = findItemIterByUUID(items, dest_item_id); - - // Go to the next element if one wishes to insert after the dest element - if (!insert_before) - { - ++it_dest; - } - - // Reinsert the source item in the right place - if (it_dest != items.end()) - { - items.insert(it_dest, src_item); - } - else - { - // Append to the list if it_dest reached the end - items.push_back(src_item); - } + LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); + LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); + + // If one of the passed UUID is not in the item list, bail out + if ((it_src == items.end()) || (it_dest == items.end())) + return; + + // Erase the source element from the list, keep a copy before erasing. + LLViewerInventoryItem* src_item = *it_src; + items.erase(it_src); + + // Note: Target iterator is not valid anymore because the container was changed, so update it. + it_dest = findItemIterByUUID(items, dest_item_id); + + // Go to the next element if one wishes to insert after the dest element + if (!insert_before) + { + ++it_dest; + } + + // Reinsert the source item in the right place + if (it_dest != items.end()) + { + items.insert(it_dest, src_item); + } + else + { + // Append to the list if it_dest reached the end + items.push_back(src_item); + } } // See also LLInventorySort where landmarks in the Favorites folder are sorted. class LLViewerInventoryItemSort { public: - bool operator()(const LLPointer<LLViewerInventoryItem>& a, const LLPointer<LLViewerInventoryItem>& b) - { - return a->getSortField() < b->getSortField(); - } + bool operator()(const LLPointer<LLViewerInventoryItem>& a, const LLPointer<LLViewerInventoryItem>& b) + { + return a->getSortField() < b->getSortField(); + } }; //---------------------------------------------------------------------------- @@ -4301,95 +4301,95 @@ public: // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() const { - LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; - LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - const LLViewerInventoryCategory* cat = cit->second; - if(cat) - { - LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " - << cat->getVersion() << " " << cat->getDescendentCount() - << LL_ENDL; - } - else - { - LL_INFOS() << " NULL!" << LL_ENDL; - } - } - LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - const LLViewerInventoryItem* item = iit->second; - if(item) - { - LL_INFOS() << " " << item->getUUID() << " " - << item->getName() << LL_ENDL; - } - else - { - LL_INFOS() << " NULL!" << LL_ENDL; - } - } - LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; + LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; + LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLViewerInventoryCategory* cat = cit->second; + if(cat) + { + LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " + << cat->getVersion() << " " << cat->getDescendentCount() + << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLViewerInventoryItem* item = iit->second; + if(item) + { + LL_INFOS() << " " << item->getUUID() << " " + << item->getName() << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; } // Do various integrity checks on model, logging issues found and -// returning an overall good/bad flag. +// returning an overall good/bad flag. LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { - LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; - S32 fatal_errs = 0; - S32 warning_count= 0; + LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; + S32 fatal_errs = 0; + S32 warning_count= 0; S32 loop_count = 0; S32 orphaned_count = 0; - if (getRootFolderID().isNull()) - { - LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; - validation_info->mFatalNoRootFolder = true; + if (getRootFolderID().isNull()) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; + validation_info->mFatalNoRootFolder = true; fatal_errs++; - } - if (getLibraryRootFolderID().isNull()) - { - // Probably shouldn't be a fatality, inventory can function without a library - LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; - validation_info->mFatalNoLibraryRootFolder = true; + } + if (getLibraryRootFolderID().isNull()) + { + // Probably shouldn't be a fatality, inventory can function without a library + LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; + validation_info->mFatalNoLibraryRootFolder = true; fatal_errs++; - } - - if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) - { - // ParentChild should be one larger because of the special entry for null uuid. - LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() - << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; - - validation_info->mWarnings["category_map_size"]++; - warning_count++; - } - S32 cat_lock = 0; - S32 item_lock = 0; - S32 desc_unknown_count = 0; - S32 version_unknown_count = 0; - - typedef std::map<LLFolderType::EType, S32> ft_count_map; - ft_count_map ft_counts_under_root; - ft_count_map ft_counts_elsewhere; - - // Loop over all categories and check. - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - const LLUUID& cat_id = cit->first; - const LLViewerInventoryCategory *cat = cit->second; - if (!cat) - { - LL_WARNS("Inventory") << "null cat" << LL_ENDL; - validation_info->mWarnings["null_cat"]++; - warning_count++; - continue; - } - LLUUID topmost_ancestor_id; - // Will leave as null uuid on failure + } + + if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) + { + // ParentChild should be one larger because of the special entry for null uuid. + LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + + validation_info->mWarnings["category_map_size"]++; + warning_count++; + } + S32 cat_lock = 0; + S32 item_lock = 0; + S32 desc_unknown_count = 0; + S32 version_unknown_count = 0; + + typedef std::map<LLFolderType::EType, S32> ft_count_map; + ft_count_map ft_counts_under_root; + ft_count_map ft_counts_elsewhere; + + // Loop over all categories and check. + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLUUID& cat_id = cit->first; + const LLViewerInventoryCategory *cat = cit->second; + if (!cat) + { + LL_WARNS("Inventory") << "null cat" << LL_ENDL; + validation_info->mWarnings["null_cat"]++; + warning_count++; + continue; + } + LLUUID topmost_ancestor_id; + // Will leave as null uuid on failure EAncestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id); switch (res) { @@ -4403,361 +4403,361 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const break; default: LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL; - validation_info->mWarnings["unknown_ancestor_status"]++; + validation_info->mWarnings["unknown_ancestor_status"]++; warning_count++; break; } - if (cat_id != cat->getUUID()) - { - LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; - validation_info->mWarnings["cat_id_index_mismatch"]++; - warning_count++; - } - - if (cat->getParentUUID().isNull()) - { - if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" - << getRootFolderID() << ") or library root (" - << getLibraryRootFolderID() << ")" << LL_ENDL; - validation_info->mWarnings["null_parent"]++; - warning_count++; - } - } - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(cat_id,cats,items); - if (!cats || !items) - { - LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; - validation_info->mWarnings["direct_descendents"]++; - warning_count++; - continue; - } - if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) - { - desc_unknown_count++; - } - else if (cats->size() + items->size() != cat->getDescendentCount()) - { - // In the case of library this is not unexpected, since - // different user accounts may be getting the library - // contents from different inventory hosts. - if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() +items->size() << LL_ENDL; - validation_info->mWarnings["invalid_descendent_count"]++; - warning_count++; - } - } - if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) - { - version_unknown_count++; - } - auto cat_lock_it = mCategoryLock.find(cat_id); - if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) - { - cat_lock++; - } - auto item_lock_it = mItemLock.find(cat_id); - if (item_lock_it != mItemLock.end() && item_lock_it->second) - { - item_lock++; - } - for (S32 i = 0; i<items->size(); i++) - { - LLViewerInventoryItem *item = items->at(i); - - if (!item) - { - LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; - validation_info->mWarnings["null_item_at_index"]++; - warning_count++; - continue; - } - - const LLUUID& item_id = item->getUUID(); - - if (item->getParentUUID() != cat_id) - { - LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " - << item->getParentUUID() << " expected " << cat_id - << LL_ENDL; - validation_info->mWarnings["wrong_parent_for_item"]++; - warning_count++; - } - - - // Entries in items and mItemMap should correspond. - item_map_t::const_iterator it = mItemMap.find(item_id); - if (it == mItemMap.end()) - { - LL_WARNS("Inventory") << "item " << item_id << " found as child of " - << cat_id << " but not in top level mItemMap" << LL_ENDL; - validation_info->mWarnings["item_not_in_top_map"]++; - warning_count++; - } - else - { - LLViewerInventoryItem *top_item = it->second; - if (top_item != item) - { - LL_WARNS("Inventory") << "item mismatch, item_id " << item_id - << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; - } - } - - // Topmost ancestor should be root or library. - LLUUID topmost_ancestor_id; + if (cat_id != cat->getUUID()) + { + LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + validation_info->mWarnings["cat_id_index_mismatch"]++; + warning_count++; + } + + if (cat->getParentUUID().isNull()) + { + if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + validation_info->mWarnings["null_parent"]++; + warning_count++; + } + } + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(cat_id,cats,items); + if (!cats || !items) + { + LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; + validation_info->mWarnings["direct_descendents"]++; + warning_count++; + continue; + } + if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + { + desc_unknown_count++; + } + else if (cats->size() + items->size() != cat->getDescendentCount()) + { + // In the case of library this is not unexpected, since + // different user accounts may be getting the library + // contents from different inventory hosts. + if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + validation_info->mWarnings["invalid_descendent_count"]++; + warning_count++; + } + } + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + version_unknown_count++; + } + auto cat_lock_it = mCategoryLock.find(cat_id); + if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) + { + cat_lock++; + } + auto item_lock_it = mItemLock.find(cat_id); + if (item_lock_it != mItemLock.end() && item_lock_it->second) + { + item_lock++; + } + for (S32 i = 0; i<items->size(); i++) + { + LLViewerInventoryItem *item = items->at(i); + + if (!item) + { + LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + validation_info->mWarnings["null_item_at_index"]++; + warning_count++; + continue; + } + + const LLUUID& item_id = item->getUUID(); + + if (item->getParentUUID() != cat_id) + { + LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + validation_info->mWarnings["wrong_parent_for_item"]++; + warning_count++; + } + + + // Entries in items and mItemMap should correspond. + item_map_t::const_iterator it = mItemMap.find(item_id); + if (it == mItemMap.end()) + { + LL_WARNS("Inventory") << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + validation_info->mWarnings["item_not_in_top_map"]++; + warning_count++; + } + else + { + LLViewerInventoryItem *top_item = it->second; + if (top_item != item) + { + LL_WARNS("Inventory") << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + } + } + + // Topmost ancestor should be root or library. + LLUUID topmost_ancestor_id; EAncestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); - if (found != ANCESTOR_OK) - { - LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; - validation_info->mWarnings["topmost_ancestor_not_found"]++; - warning_count++; - } - else - { - if (topmost_ancestor_id != getRootFolderID() && - topmost_ancestor_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id - << " got " << topmost_ancestor_id - << " expected " << getRootFolderID() - << " or " << getLibraryRootFolderID() << LL_ENDL; - validation_info->mWarnings["topmost_ancestor_not_recognized"]++; - warning_count++; - } - } - } - - // Does this category appear as a child of its supposed parent? - const LLUUID& parent_id = cat->getParentUUID(); - if (!parent_id.isNull()) - { - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(parent_id,cats,items); - if (!cats) - { - LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + if (found != ANCESTOR_OK) + { + LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; + validation_info->mWarnings["topmost_ancestor_not_found"]++; + warning_count++; + } + else + { + if (topmost_ancestor_id != getRootFolderID() && + topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + validation_info->mWarnings["topmost_ancestor_not_recognized"]++; + warning_count++; + } + } + } + + // Does this category appear as a child of its supposed parent? + const LLUUID& parent_id = cat->getParentUUID(); + if (!parent_id.isNull()) + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!cats) + { + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - else - { - bool found = false; - for (S32 i = 0; i<cats->size(); i++) - { - LLViewerInventoryCategory *kid_cat = cats->at(i); - if (kid_cat == cat) - { - found = true; - break; - } - } - if (!found) - { - LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i = 0; i<cats->size(); i++) + { + LLViewerInventoryCategory *kid_cat = cats->at(i); + if (kid_cat == cat) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - } - } - - // Update count of preferred types - LLFolderType::EType folder_type = cat->getPreferredType(); - bool cat_is_in_library = false; - LLUUID topmost_id; - if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID()) - { - cat_is_in_library = true; - } - if (!cat_is_in_library) - { - if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) - { - ft_counts_under_root[folder_type]++; - if (folder_type != LLFolderType::FT_NONE) - { - LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; - } - } - else - { - ft_counts_elsewhere[folder_type]++; - if (folder_type != LLFolderType::FT_NONE) - { - LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; - } - } - } - } - - // Loop over all items and check - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - const LLUUID& item_id = iit->first; - LLViewerInventoryItem *item = iit->second; - if (item->getUUID() != item_id) - { - LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; - validation_info->mWarnings["item_id_mismatch"]++; - warning_count++; - } - - const LLUUID& parent_id = item->getParentUUID(); - if (parent_id.isNull()) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + } + } + } + + // Update count of preferred types + LLFolderType::EType folder_type = cat->getPreferredType(); + bool cat_is_in_library = false; + LLUUID topmost_id; + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID()) + { + cat_is_in_library = true; + } + if (!cat_is_in_library) + { + if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) + { + ft_counts_under_root[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + else + { + ft_counts_elsewhere[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + } + } + + // Loop over all items and check + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLUUID& item_id = iit->first; + LLViewerInventoryItem *item = iit->second; + if (item->getUUID() != item_id) + { + LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + validation_info->mWarnings["item_id_mismatch"]++; + warning_count++; + } + + const LLUUID& parent_id = item->getParentUUID(); + if (parent_id.isNull()) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; orphaned_count++; - } - else - { - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(parent_id,cats,items); - if (!items) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() - << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + } + else + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!items) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; orphaned_count++; - } - else - { - bool found = false; - for (S32 i=0; i<items->size(); ++i) - { - if (items->at(i) == item) - { - found = true; - break; - } - } - if (!found) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() - << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i=0; i<items->size(); ++i) + { + if (items->at(i) == item) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - } - - } - // Link checking - if (item->getIsLinkType()) - { - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - LLViewerInventoryItem *target_item = getItem(target_id); - LLViewerInventoryCategory *target_cat = getCategory(target_id); - // Linked-to UUID should have back reference to this link. - if (!hasBacklinkInfo(link_id, target_id)) - { - LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() - << " missing backlink info at target_id " << target_id - << LL_ENDL; + } + } + + } + // Link checking + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; orphaned_count++; - } - // Links should have referents. - if (item->getActualType() == LLAssetType::AT_LINK && !target_item) - { - LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; orphaned_count++; - } - else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) - { - LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; orphaned_count++; - } - if (target_item && target_item->getIsLinkType()) - { - LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " - << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; - } - - // Links should not have backlinks. - std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); - if (range.first != range.second) - { - LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; - } - } - else - { - // Check the backlinks of a non-link item. - const LLUUID& target_id = item->getUUID(); - std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - const LLUUID& link_id = it->second; - LLViewerInventoryItem *link_item = getItem(link_id); - if (!link_item || !link_item->getIsLinkType()) - { - LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; - } - } - } - } - - // Check system folders - for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) - { - LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; - } - for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) - { - LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; - } - - static LLCachedControl<bool> fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); - static std::default_random_engine e{}; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } + } + else + { + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } + } + } + + // Check system folders + for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; + } + for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; + } + + static LLCachedControl<bool> fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); + static std::default_random_engine e{}; static std::uniform_int_distribution<> distrib(0, 1); - for (S32 ft=LLFolderType::FT_TEXTURE; ft<LLFolderType::FT_COUNT; ft++) - { - LLFolderType::EType folder_type = static_cast<LLFolderType::EType>(ft); - if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) - { - continue; - } - bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); - bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); - S32 count_under_root = ft_counts_under_root[folder_type]; - S32 count_elsewhere = ft_counts_elsewhere[folder_type]; - if (fake_system_folder_issues) - { - // Force all counts to be either 0 or 2, thus flagged as an error. - count_under_root = 2*distrib(e); - count_elsewhere = 2*distrib(e); - validation_info->mFatalQADebugMode = true; - } - if (is_singleton) - { - if (count_under_root==0) - { - LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; - // Need to create, if allowed. - if (is_automatic) - { - LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; - validation_info->mMissingRequiredSystemFolders.insert(folder_type); + for (S32 ft=LLFolderType::FT_TEXTURE; ft<LLFolderType::FT_COUNT; ft++) + { + LLFolderType::EType folder_type = static_cast<LLFolderType::EType>(ft); + if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) + { + continue; + } + bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); + bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); + S32 count_under_root = ft_counts_under_root[folder_type]; + S32 count_elsewhere = ft_counts_elsewhere[folder_type]; + if (fake_system_folder_issues) + { + // Force all counts to be either 0 or 2, thus flagged as an error. + count_under_root = 2*distrib(e); + count_elsewhere = 2*distrib(e); + validation_info->mFatalQADebugMode = true; + } + if (is_singleton) + { + if (count_under_root==0) + { + LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; + // Need to create, if allowed. + if (is_automatic) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; + validation_info->mMissingRequiredSystemFolders.insert(folder_type); fatal_errs++; - } - else - { - // Can create, and will when needed. - // (Not sure this is really a warning, but worth logging) - validation_info->mWarnings["missing_system_folder_can_create"]++; - warning_count++; - } - } - else if (count_under_root > 1) - { - validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); + } + else + { + // Can create, and will when needed. + // (Not sure this is really a warning, but worth logging) + validation_info->mWarnings["missing_system_folder_can_create"]++; + warning_count++; + } + } + else if (count_under_root > 1) + { + validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS // FT_MATERIAL might need to be automatic like the rest of upload folders @@ -4766,7 +4766,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { // It is a fatal problem or can lead to fatal problems for COF, // outfits, trash and other non-automatic folders. - validation_info->mFatalSystemDuplicate++; + validation_info->mFatalSystemDuplicate++; fatal_errs++; LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; } @@ -4775,74 +4775,74 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const // For automatic folders it's not a fatal issue and shouldn't // break inventory or other functionality further // Exception: FT_SETTINGS is not automatic, but only deserves a warning. - validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++; + validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++; warning_count++; LL_WARNS("Inventory") << "System folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; } - } - if (count_elsewhere > 0) - { - LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; - validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++; - warning_count++; - } - } - } - - - if (cat_lock > 0 || item_lock > 0) - { - LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " - << cat_lock << ", item arrays " << item_lock << LL_ENDL; - } - if (desc_unknown_count != 0) - { - LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; - } - if (version_unknown_count != 0) - { - LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; - } - - // FIXME need to fail login and tell user to retry, contact support if problem persists. - bool valid = (fatal_errs == 0); - LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL; - - validation_info->mFatalErrorCount = fatal_errs; - validation_info->mWarningCount = warning_count; + } + if (count_elsewhere > 0) + { + LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; + validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++; + warning_count++; + } + } + } + + + if (cat_lock > 0 || item_lock > 0) + { + LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " + << cat_lock << ", item arrays " << item_lock << LL_ENDL; + } + if (desc_unknown_count != 0) + { + LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + } + if (version_unknown_count != 0) + { + LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + } + + // FIXME need to fail login and tell user to retry, contact support if problem persists. + bool valid = (fatal_errs == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL; + + validation_info->mFatalErrorCount = fatal_errs; + validation_info->mWarningCount = warning_count; validation_info->mLoopCount = loop_count; validation_info->mOrphanedCount = orphaned_count; - return validation_info; + return validation_info; } // Provides a unix-style path from root, like "/My Inventory/Clothing/.../myshirt" std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const { - std::vector<std::string> path_elts; - std::map<LLUUID,bool> visited; - while (obj != NULL && !visited[obj->getUUID()]) - { - path_elts.push_back(obj->getName()); - // avoid infinite loop in the unlikely event of a cycle - visited[obj->getUUID()] = true; - obj = getObject(obj->getParentUUID()); - } - std::stringstream s; - std::string delim("/"); - std::reverse(path_elts.begin(), path_elts.end()); - std::string result = "/" + boost::algorithm::join(path_elts, delim); - return result; + std::vector<std::string> path_elts; + std::map<LLUUID,bool> visited; + while (obj != NULL && !visited[obj->getUUID()]) + { + path_elts.push_back(obj->getName()); + // avoid infinite loop in the unlikely event of a cycle + visited[obj->getUUID()] = true; + obj = getObject(obj->getParentUUID()); + } + std::stringstream s; + std::string delim("/"); + std::reverse(path_elts.begin(), path_elts.end()); + std::string result = "/" + boost::algorithm::join(path_elts, delim); + return result; } /* const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& path) { - vector<std::string> path_elts; - boost::algorithm::split(path_elts, path, boost::is_any_of("/")); - for(path_elts, auto e) - { - } + vector<std::string> path_elts; + boost::algorithm::split(path_elts, path, boost::is_any_of("/")); + for(path_elts, auto e) + { + } } */ @@ -4854,41 +4854,41 @@ const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& pat #if 0 BOOL decompress_file(const char* src_filename, const char* dst_filename) { - BOOL rv = FALSE; - gzFile src = NULL; - U8* buffer = NULL; - LLFILE* dst = NULL; - S32 bytes = 0; - const S32 DECOMPRESS_BUFFER_SIZE = 32000; - - // open the files - src = gzopen(src_filename, "rb"); - if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, "wb"); - if(!dst) goto err_decompress; - - // decompress. - buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; - - do - { - bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE); - if (bytes < 0) - { - goto err_decompress; - } - - fwrite(buffer, bytes, 1, dst); - } while(gzeof(src) == 0); - - // success - rv = TRUE; + BOOL rv = FALSE; + gzFile src = NULL; + U8* buffer = NULL; + LLFILE* dst = NULL; + S32 bytes = 0; + const S32 DECOMPRESS_BUFFER_SIZE = 32000; + + // open the files + src = gzopen(src_filename, "rb"); + if(!src) goto err_decompress; + dst = LLFile::fopen(dst_filename, "wb"); + if(!dst) goto err_decompress; + + // decompress. + buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; + + do + { + bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE); + if (bytes < 0) + { + goto err_decompress; + } + + fwrite(buffer, bytes, 1, dst); + } while(gzeof(src) == 0); + + // success + rv = TRUE; err_decompress: - if(src != NULL) gzclose(src); - if(buffer != NULL) delete[] buffer; - if(dst != NULL) fclose(dst); - return rv; + if(src != NULL) gzclose(src); + if(buffer != NULL) delete[] buffer; + if(dst != NULL) fclose(dst); + return rv; } #endif @@ -4898,163 +4898,163 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) ///---------------------------------------------------------------------------- LLInventoryModel::FetchItemHttpHandler::FetchItemHttpHandler(const LLSD & request_sd) - : LLCore::HttpHandler(), - mRequestSD(request_sd) + : LLCore::HttpHandler(), + mRequestSD(request_sd) {} LLInventoryModel::FetchItemHttpHandler::~FetchItemHttpHandler() {} void LLInventoryModel::FetchItemHttpHandler::onCompleted(LLCore::HttpHandle handle, - LLCore::HttpResponse * response) + LLCore::HttpResponse * response) { - do // Single-pass do-while used for common exit handling - { - LLCore::HttpStatus status(response->getStatus()); - // status = LLCore::HttpStatus(404); // Dev tool to force error handling - if (! status) - { - processFailure(status, response); - break; // Goto common exit - } - - LLCore::BufferArray * body(response->getBody()); - // body = NULL; // Dev tool to force error handling - if (! body || ! body->size()) - { - LL_WARNS(LOG_INV) << "Missing data in inventory item query." << LL_ENDL; - processFailure("HTTP response for inventory item query missing body", response); - break; // Goto common exit - } - - // body->write(0, "Garbage Response", 16); // Dev tool to force error handling - LLSD body_llsd; - if (! LLCoreHttpUtil::responseToLLSD(response, true, body_llsd)) - { - // INFOS-level logging will occur on the parsed failure - processFailure("HTTP response for inventory item query has malformed LLSD", response); - break; // Goto common exit - } - - // Expect top-level structure to be a map - // body_llsd = LLSD::emptyArray(); // Dev tool to force error handling - if (! body_llsd.isMap()) - { - processFailure("LLSD response for inventory item not a map", response); - break; // Goto common exit - } - - // Check for 200-with-error failures - // - // Original Responder-based serivce model didn't check for these errors. - // It may be more robust to ignore this condition. With aggregated requests, - // an error in one inventory item might take down the entire request. - // So if this instead broke up the aggregated items into single requests, - // maybe that would make progress. Or perhaps there's structured information - // that can tell us what went wrong. Need to dig into this and firm up - // the API. - // - // body_llsd["error"] = LLSD::emptyMap(); // Dev tool to force error handling - // body_llsd["error"]["identifier"] = "Development"; - // body_llsd["error"]["message"] = "You left development code in the viewer"; - if (body_llsd.has("error")) - { - processFailure("Inventory application error (200-with-error)", response); - break; // Goto common exit - } - - // Okay, process data if possible - processData(body_llsd, response); - } - while (false); + do // Single-pass do-while used for common exit handling + { + LLCore::HttpStatus status(response->getStatus()); + // status = LLCore::HttpStatus(404); // Dev tool to force error handling + if (! status) + { + processFailure(status, response); + break; // Goto common exit + } + + LLCore::BufferArray * body(response->getBody()); + // body = NULL; // Dev tool to force error handling + if (! body || ! body->size()) + { + LL_WARNS(LOG_INV) << "Missing data in inventory item query." << LL_ENDL; + processFailure("HTTP response for inventory item query missing body", response); + break; // Goto common exit + } + + // body->write(0, "Garbage Response", 16); // Dev tool to force error handling + LLSD body_llsd; + if (! LLCoreHttpUtil::responseToLLSD(response, true, body_llsd)) + { + // INFOS-level logging will occur on the parsed failure + processFailure("HTTP response for inventory item query has malformed LLSD", response); + break; // Goto common exit + } + + // Expect top-level structure to be a map + // body_llsd = LLSD::emptyArray(); // Dev tool to force error handling + if (! body_llsd.isMap()) + { + processFailure("LLSD response for inventory item not a map", response); + break; // Goto common exit + } + + // Check for 200-with-error failures + // + // Original Responder-based serivce model didn't check for these errors. + // It may be more robust to ignore this condition. With aggregated requests, + // an error in one inventory item might take down the entire request. + // So if this instead broke up the aggregated items into single requests, + // maybe that would make progress. Or perhaps there's structured information + // that can tell us what went wrong. Need to dig into this and firm up + // the API. + // + // body_llsd["error"] = LLSD::emptyMap(); // Dev tool to force error handling + // body_llsd["error"]["identifier"] = "Development"; + // body_llsd["error"]["message"] = "You left development code in the viewer"; + if (body_llsd.has("error")) + { + processFailure("Inventory application error (200-with-error)", response); + break; // Goto common exit + } + + // Okay, process data if possible + processData(body_llsd, response); + } + while (false); } void LLInventoryModel::FetchItemHttpHandler::processData(LLSD & content, LLCore::HttpResponse * response) { - start_new_inventory_observer(); + start_new_inventory_observer(); #if 0 - LLUUID agent_id; - agent_id = content["agent_id"].asUUID(); - if (agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id - << LL_ENDL; - return; - } + LLUUID agent_id; + agent_id = content["agent_id"].asUUID(); + if (agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return; + } #endif - - LLInventoryModel::item_array_t items; - LLInventoryModel::update_map_t update; - LLUUID folder_id; - LLSD content_items(content["items"]); - const S32 count(content_items.size()); - - // Does this loop ever execute more than once? - for (S32 i(0); i < count; ++i) - { - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - titem->unpackMessage(content_items[i]); - - LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " - << titem->getUUID() << LL_ENDL; - items.push_back(titem); - - // examine update for changes. - LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); - - if (itemp) - { - if (titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; - } - - if (folder_id.isNull()) - { - folder_id = titem->getParentUUID(); - } - } - - // as above, this loop never seems to loop more than once per call - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - gInventory.updateItem(*it); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); + + LLInventoryModel::item_array_t items; + LLInventoryModel::update_map_t update; + LLUUID folder_id; + LLSD content_items(content["items"]); + const S32 count(content_items.size()); + + // Does this loop ever execute more than once? + for (S32 i(0); i < count; ++i) + { + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + titem->unpackMessage(content_items[i]); + + LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + + // examine update for changes. + LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); + + if (itemp) + { + if (titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + + if (folder_id.isNull()) + { + folder_id = titem->getParentUUID(); + } + } + + // as above, this loop never seems to loop more than once per call + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + gInventory.updateItem(*it); + } + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); } void LLInventoryModel::FetchItemHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::HttpResponse * response) { - const std::string & ct(response->getContentType()); - LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" - << "[Status: " << status.toTerseString() << "]\n" - << "[Reason: " << status.toString() << "]\n" - << "[Content-type: " << ct << "]\n" - << "[Content (abridged): " - << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; - gInventory.notifyObservers(); + const std::string & ct(response->getContentType()); + LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" + << "[Status: " << status.toTerseString() << "]\n" + << "[Reason: " << status.toString() << "]\n" + << "[Content-type: " << ct << "]\n" + << "[Content (abridged): " + << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; + gInventory.notifyObservers(); } void LLInventoryModel::FetchItemHttpHandler::processFailure(const char * const reason, LLCore::HttpResponse * response) { - LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" - << "[Status: internal error]\n" - << "[Reason: " << reason << "]\n" - << "[Content (abridged): " - << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; - gInventory.notifyObservers(); + LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" + << "[Status: internal error]\n" + << "[Reason: " << reason << "]\n" + << "[Content (abridged): " + << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; + gInventory.notifyObservers(); } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a8ba75ab5f..426b71ba67 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstartup.cpp * @brief startup routines. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,9 +31,9 @@ #include "llcallstack.h" #if LL_WINDOWS -# include <process.h> // _spawnl() +# include <process.h> // _spawnl() #else -# include <sys/stat.h> // mkdir() +# include <sys/stat.h> // mkdir() #endif #include <memory> // std::unique_ptr @@ -84,7 +84,7 @@ #include "llversioninfo.h" #include "llviewercontrol.h" #include "llviewerhelp.h" -#include "llxorcipher.h" // saved password, MAC address +#include "llxorcipher.h" // saved password, MAC address #include "llwindow.h" #include "message.h" #include "v3math.h" @@ -121,7 +121,7 @@ #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" -#include "llloginhandler.h" // gLoginHandler, SLURL support +#include "llloginhandler.h" // gLoginHandler, SLURL support #include "lllogininstance.h" // Host the login module. #include "llpanellogin.h" #include "llmutelist.h" @@ -138,7 +138,7 @@ #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" -#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance +#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance #include "llsurface.h" #include "lltexturecache.h" #include "lltexturefetch.h" @@ -237,7 +237,7 @@ extern S32 gStartImageHeight; // static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; -static std::string sInitialOutfitGender; // "male" or "female" +static std::string sInitialOutfitGender; // "male" or "female" static bool gUseCircuitCallbackCalled = false; @@ -291,12 +291,12 @@ void transition_back_to_login_panel(const std::string& emsg); void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) { - LLNameBox::refreshAll(id, full_name, is_group); - LLNameEditor::refreshAll(id, full_name, is_group); - - // TODO: Actually be intelligent about the refresh. - // For now, just brute force refresh the dialogs. - dialog_refresh_all(); + LLNameBox::refreshAll(id, full_name, is_group); + LLNameEditor::refreshAll(id, full_name, is_group); + + // TODO: Actually be intelligent about the refresh. + // For now, just brute force refresh the dialogs. + dialog_refresh_all(); } // @@ -321,10 +321,10 @@ void pump_idle_startup_network(void) // void update_texture_fetch() { - LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread - LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - gTextureList.updateImages(0.10f); + LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + gTextureList.updateImages(0.10f); if (LLImageGLThread::sEnabledTextures) { @@ -335,8 +335,8 @@ void update_texture_fetch() void set_flags_and_update_appearance() { - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); LLInventoryModelBackgroundFetch::instance().start(); } @@ -345,310 +345,310 @@ void set_flags_and_update_appearance() // true when all initialization done. bool idle_startup() { - if (gViewerWindow == NULL) - { - // We expect window to be initialized - LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; - return false; // No world yet - } - - const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); - static LLTimer timeout; - - static LLTimer login_time; - - // until this is encapsulated, this little hack for the - // auth/transform loop will do. - static F32 progress = 0.10f; - - static std::string auth_desc; - static std::string auth_message; - - static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server - - // last location by default - static S32 agent_location_id = START_LOCATION_ID_LAST; - - static bool show_connect_box = true; - - //static bool stipend_since_login = false; - - // HACK: These are things from the main loop that usually aren't done - // until initialization is complete, but need to be done here for things - // to work. - gIdleCallbacks.callFunctions(); - gViewerWindow->updateUI(); - - LLMortician::updateClass(); - - const std::string delims (" "); - std::string system; - int begIdx, endIdx; - std::string osString = LLOSInfo::instance().getOSStringSimple(); - - begIdx = osString.find_first_not_of (delims); - endIdx = osString.find_first_of (delims, begIdx); - system = osString.substr (begIdx, endIdx - begIdx); - system += "Locale"; - - LLStringUtil::setLocale (LLTrans::getString(system)); - - //note: Removing this line will cause incorrect button size in the login screen. -- bao. - gTextureList.updateImages(0.01f) ; - - if ( STATE_FIRST == LLStartUp::getStartupState() ) - { - static bool first_call = true; - if (first_call) - { - // Other phases get handled when startup state changes, - // need to capture the initial state as well. - LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); - first_call = false; - } - - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - - ///////////////////////////////////////////////// - // - // Initialize stuff that doesn't need data from simulators - // - std::string lastGPU = gSavedSettings.getString("LastGPUString"); - std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); - - if (LLFeatureManager::getInstance()->isSafe()) - { - LLNotificationsUtil::add("DisplaySetToSafe"); - } - else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && - (gSavedSettings.getS32("LastFeatureVersion") != 0)) - { - LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); - } - else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) - { - LLSD subs; - subs["LAST_GPU"] = lastGPU; - subs["THIS_GPU"] = thisGPU; - LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); - } - else if (!gViewerWindow->getInitAlert().empty()) - { - LLNotificationsUtil::add(gViewerWindow->getInitAlert()); - } - - //------------------------------------------------- - // Init the SOCKS 5 proxy if the user has configured - // one. We need to do this early in case the user - // is using SOCKS for HTTP so we get the login - // screen and HTTP tables via SOCKS. - //------------------------------------------------- - LLStartUp::startLLProxy(); - - gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); - gSavedSettings.setString("LastGPUString", thisGPU); - - - std::string xml_file = LLUI::locateSkin("xui_version.xml"); - LLXMLNodePtr root; - bool xml_ok = false; - if (LLXMLNode::parseFile(xml_file, root, NULL)) - { - if( (root->hasName("xui_version") ) ) - { - std::string value = root->getValue(); - F32 version = 0.0f; - LLStringUtil::convertToF32(value, version); - if (version >= 1.0f) - { - xml_ok = true; - } - } - } - if (!xml_ok) - { - // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. - // If that's so, then we'll get a fatal error on attempting to load it, - // which will display a nontranslatable error message that says so. - // Otherwise, we'll display a reasonable error message that IS translatable. - LLAppViewer::instance()->earlyExit("BadInstallation"); - } - // - // Statistics stuff - // - - // Load autopilot and stats stuff - gAgentPilot.load(); - - //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); - - // Load the throttle settings - gViewerThrottle.load(); - - // - // Initialize messaging system - // - LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; - - std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); - - LLFILE* found_template = NULL; - found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ - - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message_template.msg - // file will be located in: - // build-vc**/newview/<config>/app_settings - if (!found_template) - { - message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } - #elif LL_DARWIN - // On Mac dev builds, message_template.msg lives in: - // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings - if (!found_template) - { - message_template_path = - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, - "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } - #endif - - if (found_template) - { - fclose(found_template); - - U32 port = gSavedSettings.getU32("UserConnectionPort"); - - if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) - (gSavedSettings.getBOOL("ConnectionPortEnabled"))) - { - port = gSavedSettings.getU32("ConnectionPort"); - } - - // TODO parameterize - const F32 circuit_heartbeat_interval = 5; - const F32 circuit_timeout = 100; - - const LLUseCircuitCodeResponder* responder = NULL; - bool failure_is_fatal = true; - - if(!start_messaging_system( - message_template_path, - port, - LLVersionInfo::instance().getMajor(), - LLVersionInfo::instance().getMinor(), - LLVersionInfo::instance().getPatch(), - FALSE, - std::string(), - responder, - failure_is_fatal, - circuit_heartbeat_interval, - circuit_timeout)) - { - std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); - LL_WARNS("AppInit") << diagnostic << LL_ENDL; - LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); - } - - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message.xml file will - // be located in indra/build-vc**/newview/<config>/app_settings. - std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); - - if (!LLFile::isfile(message_path.c_str())) - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); - } - else - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - } - #else - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - #endif - - } - else - { - LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); - } - - if(gMessageSystem && gMessageSystem->isOK()) - { - // Initialize all of the callbacks in case of bad message - // system data - LLMessageSystem* msg = gMessageSystem; - msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, - invalid_message_callback, - NULL); - msg->setExceptionFunc(MX_PACKET_TOO_SHORT, - invalid_message_callback, - NULL); - - // running off end of a packet is now valid in the case - // when a reader has a newer message template than - // the sender - /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, - invalid_message_callback, - NULL);*/ - msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, - invalid_message_callback, - NULL); - - if (gSavedSettings.getBOOL("LogMessages")) - { - LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; - msg->startLogging(); - } - - // start the xfer system. by default, choke the downloads - // a lot... - const S32 VIEWER_MAX_XFER = 3; - start_xfer_manager(); - gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); - F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); - if (xfer_throttle_bps > 1.f) - { - gXferManager->setUseAckThrottling(TRUE); - gXferManager->setAckThrottleBPS(xfer_throttle_bps); - } - gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); - - - F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); - msg->mPacketRing.setDropPercentage(dropPercent); - - F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); - F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); - if (inBandwidth != 0.f) - { - LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; - msg->mPacketRing.setUseInThrottle(TRUE); - msg->mPacketRing.setInBandwidth(inBandwidth); - } - if (outBandwidth != 0.f) - { - LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; - msg->mPacketRing.setUseOutThrottle(TRUE); - msg->mPacketRing.setOutBandwidth(outBandwidth); - } - } - - LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; - - //------------------------------------------------- - // Init audio, which may be needed for prefs dialog - // or audio cues in connection UI. - //------------------------------------------------- - - if (FALSE == gSavedSettings.getBOOL("NoAudio")) - { - delete gAudiop; - gAudiop = NULL; + if (gViewerWindow == NULL) + { + // We expect window to be initialized + LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; + return false; // No world yet + } + + const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); + static LLTimer timeout; + + static LLTimer login_time; + + // until this is encapsulated, this little hack for the + // auth/transform loop will do. + static F32 progress = 0.10f; + + static std::string auth_desc; + static std::string auth_message; + + static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server + + // last location by default + static S32 agent_location_id = START_LOCATION_ID_LAST; + + static bool show_connect_box = true; + + //static bool stipend_since_login = false; + + // HACK: These are things from the main loop that usually aren't done + // until initialization is complete, but need to be done here for things + // to work. + gIdleCallbacks.callFunctions(); + gViewerWindow->updateUI(); + + LLMortician::updateClass(); + + const std::string delims (" "); + std::string system; + int begIdx, endIdx; + std::string osString = LLOSInfo::instance().getOSStringSimple(); + + begIdx = osString.find_first_not_of (delims); + endIdx = osString.find_first_of (delims, begIdx); + system = osString.substr (begIdx, endIdx - begIdx); + system += "Locale"; + + LLStringUtil::setLocale (LLTrans::getString(system)); + + //note: Removing this line will cause incorrect button size in the login screen. -- bao. + gTextureList.updateImages(0.01f) ; + + if ( STATE_FIRST == LLStartUp::getStartupState() ) + { + static bool first_call = true; + if (first_call) + { + // Other phases get handled when startup state changes, + // need to capture the initial state as well. + LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); + first_call = false; + } + + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + ///////////////////////////////////////////////// + // + // Initialize stuff that doesn't need data from simulators + // + std::string lastGPU = gSavedSettings.getString("LastGPUString"); + std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); + + if (LLFeatureManager::getInstance()->isSafe()) + { + LLNotificationsUtil::add("DisplaySetToSafe"); + } + else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && + (gSavedSettings.getS32("LastFeatureVersion") != 0)) + { + LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); + } + else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) + { + LLSD subs; + subs["LAST_GPU"] = lastGPU; + subs["THIS_GPU"] = thisGPU; + LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); + } + else if (!gViewerWindow->getInitAlert().empty()) + { + LLNotificationsUtil::add(gViewerWindow->getInitAlert()); + } + + //------------------------------------------------- + // Init the SOCKS 5 proxy if the user has configured + // one. We need to do this early in case the user + // is using SOCKS for HTTP so we get the login + // screen and HTTP tables via SOCKS. + //------------------------------------------------- + LLStartUp::startLLProxy(); + + gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); + gSavedSettings.setString("LastGPUString", thisGPU); + + + std::string xml_file = LLUI::locateSkin("xui_version.xml"); + LLXMLNodePtr root; + bool xml_ok = false; + if (LLXMLNode::parseFile(xml_file, root, NULL)) + { + if( (root->hasName("xui_version") ) ) + { + std::string value = root->getValue(); + F32 version = 0.0f; + LLStringUtil::convertToF32(value, version); + if (version >= 1.0f) + { + xml_ok = true; + } + } + } + if (!xml_ok) + { + // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. + // If that's so, then we'll get a fatal error on attempting to load it, + // which will display a nontranslatable error message that says so. + // Otherwise, we'll display a reasonable error message that IS translatable. + LLAppViewer::instance()->earlyExit("BadInstallation"); + } + // + // Statistics stuff + // + + // Load autopilot and stats stuff + gAgentPilot.load(); + + //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); + + // Load the throttle settings + gViewerThrottle.load(); + + // + // Initialize messaging system + // + LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; + + std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); + + LLFILE* found_template = NULL; + found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message_template.msg + // file will be located in: + // build-vc**/newview/<config>/app_settings + if (!found_template) + { + message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #elif LL_DARWIN + // On Mac dev builds, message_template.msg lives in: + // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings + if (!found_template) + { + message_template_path = + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, + "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #endif + + if (found_template) + { + fclose(found_template); + + U32 port = gSavedSettings.getU32("UserConnectionPort"); + + if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) + (gSavedSettings.getBOOL("ConnectionPortEnabled"))) + { + port = gSavedSettings.getU32("ConnectionPort"); + } + + // TODO parameterize + const F32 circuit_heartbeat_interval = 5; + const F32 circuit_timeout = 100; + + const LLUseCircuitCodeResponder* responder = NULL; + bool failure_is_fatal = true; + + if(!start_messaging_system( + message_template_path, + port, + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + FALSE, + std::string(), + responder, + failure_is_fatal, + circuit_heartbeat_interval, + circuit_timeout)) + { + std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); + } + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message.xml file will + // be located in indra/build-vc**/newview/<config>/app_settings. + std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); + + if (!LLFile::isfile(message_path.c_str())) + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); + } + else + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + } + #else + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + #endif + + } + else + { + LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); + } + + if(gMessageSystem && gMessageSystem->isOK()) + { + // Initialize all of the callbacks in case of bad message + // system data + LLMessageSystem* msg = gMessageSystem; + msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, + invalid_message_callback, + NULL); + msg->setExceptionFunc(MX_PACKET_TOO_SHORT, + invalid_message_callback, + NULL); + + // running off end of a packet is now valid in the case + // when a reader has a newer message template than + // the sender + /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, + invalid_message_callback, + NULL);*/ + msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, + invalid_message_callback, + NULL); + + if (gSavedSettings.getBOOL("LogMessages")) + { + LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; + msg->startLogging(); + } + + // start the xfer system. by default, choke the downloads + // a lot... + const S32 VIEWER_MAX_XFER = 3; + start_xfer_manager(); + gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); + F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); + if (xfer_throttle_bps > 1.f) + { + gXferManager->setUseAckThrottling(TRUE); + gXferManager->setAckThrottleBPS(xfer_throttle_bps); + } + gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); + + + F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); + msg->mPacketRing.setDropPercentage(dropPercent); + + F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); + F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); + if (inBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; + msg->mPacketRing.setUseInThrottle(TRUE); + msg->mPacketRing.setInBandwidth(inBandwidth); + } + if (outBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; + msg->mPacketRing.setUseOutThrottle(TRUE); + msg->mPacketRing.setOutBandwidth(outBandwidth); + } + } + + LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; + + //------------------------------------------------- + // Init audio, which may be needed for prefs dialog + // or audio cues in connection UI. + //------------------------------------------------- + + if (FALSE == gSavedSettings.getBOOL("NoAudio")) + { + delete gAudiop; + gAudiop = NULL; #ifdef LL_FMODSTUDIO #if !LL_WINDOWS @@ -661,262 +661,262 @@ bool idle_startup() #ifdef LL_OPENAL #if !LL_WINDOWS - if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) + if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) #endif // !LL_WINDOWS - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); - } + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); + } #endif - - if (gAudiop) - { + + if (gAudiop) + { #if LL_WINDOWS - // FMOD Ex on Windows needs the window handle to stop playing audio - // when window is minimized. JC - void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); + // FMOD Ex on Windows needs the window handle to stop playing audio + // when window is minimized. JC + void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); #else - void* window_handle = NULL; + void* window_handle = NULL; #endif - if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) - { - if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) - { - LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); - } - - // if the audio engine hasn't set up its own preferred handler for streaming audio - // then set up the generic streaming audio implementation which uses media plugins - if (NULL == gAudiop->getStreamingAudioImpl()) - { - LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); - } - - gAudiop->setMuted(TRUE); - } - else - { - LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; - delete gAudiop; - gAudiop = NULL; - } - } - } - - LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; - - if (LLTimer::knownBadTimer()) - { - LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; - } - - // - // Log on to system - // - if (gUserCredential.isNull()) - { - gUserCredential = gLoginHandler.initializeLoginInfo(); - } - // Previous initializeLoginInfo may have generated user credentials. Re-check them. - if (gUserCredential.isNull()) - { - show_connect_box = TRUE; - } - else if (gSavedSettings.getBOOL("AutoLogin")) - { - // Log into last account - gRememberPassword = true; - gRememberUser = true; - gSavedSettings.setBOOL("RememberPassword", TRUE); - gSavedSettings.setBOOL("RememberUser", TRUE); - show_connect_box = false; - } - else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) - { - // Console provided login&password - gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); - gRememberUser = gSavedSettings.getBOOL("RememberUser"); - show_connect_box = false; - } - else - { - gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); - gRememberUser = gSavedSettings.getBOOL("RememberUser"); - show_connect_box = TRUE; - } - - //setup map of datetime strings to codes and slt & local time offset from utc - // *TODO: Does this need to be here? - LLStringOps::setupDatetimeInfo(false); - - // Go to the next startup state - LLStartUp::setStartupState( STATE_BROWSER_INIT ); - return FALSE; - } - - - if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingBrowser"); - set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); - // LLViewerMedia::initBrowser(); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - return FALSE; - } - - - if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " - << show_connect_box << LL_ENDL; - - // if we've gone backwards in the login state machine, to this state where we show the UI - // AND the debug setting to exit in this case is true, then go ahead and bail quickly - if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) - { - LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; - // no requirement for notification here - just exit - LLAppViewer::instance()->earlyExitNoNotify(); - } - - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - - // Login screen needs menus for preferences, but we can enter - // this startup phase more than once. - if (gLoginMenuBarView == NULL) - { - LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; - initialize_spellcheck_menu(); - init_menus(); - } - show_release_notes_if_required(); - - if (show_connect_box) - { - LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; - // Load all the name information out of the login view - // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't - // show the login view until login_show() is called below. - if (gUserCredential.isNull()) - { - LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; - gUserCredential = gLoginHandler.initializeLoginInfo(); - } - // Make sure the process dialog doesn't hide things - gViewerWindow->setShowProgress(FALSE); - // Show the login dialog - login_show(); - // connect dialog is already shown, so fill in the names - LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); - LLPanelLogin::giveFocus(); - - // MAINT-3231 Show first run dialog only for Desura viewer - if (gSavedSettings.getString("sourceid") == "1208_desura") - { - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) - { - LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; - show_first_run_dialog(); - } - else - { - LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; - } - } - display_startup(); - LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input - } - else - { - LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; - // skip directly to message template verification - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - } - - gViewerWindow->setNormalControlsVisible( FALSE ); - gLoginMenuBarView->setVisible( TRUE ); - gLoginMenuBarView->setEnabled( TRUE ); - show_debug_menus(); - - // Hide the splash screen - LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; - LLSplashScreen::hide(); - // Push our window frontmost - gViewerWindow->getWindow()->show(); - - // DEV-16927. The following code removes errant keystrokes that happen while the window is being - // first made visible. + if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) + { + if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) + { + LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); + } + + // if the audio engine hasn't set up its own preferred handler for streaming audio + // then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + + gAudiop->setMuted(TRUE); + } + else + { + LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; + delete gAudiop; + gAudiop = NULL; + } + } + } + + LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; + + if (LLTimer::knownBadTimer()) + { + LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; + } + + // + // Log on to system + // + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + // Previous initializeLoginInfo may have generated user credentials. Re-check them. + if (gUserCredential.isNull()) + { + show_connect_box = TRUE; + } + else if (gSavedSettings.getBOOL("AutoLogin")) + { + // Log into last account + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); + show_connect_box = false; + } + else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) + { + // Console provided login&password + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); + show_connect_box = false; + } + else + { + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); + show_connect_box = TRUE; + } + + //setup map of datetime strings to codes and slt & local time offset from utc + // *TODO: Does this need to be here? + LLStringOps::setupDatetimeInfo(false); + + // Go to the next startup state + LLStartUp::setStartupState( STATE_BROWSER_INIT ); + return FALSE; + } + + + if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingBrowser"); + set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + // LLViewerMedia::initBrowser(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + return FALSE; + } + + + if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " + << show_connect_box << LL_ENDL; + + // if we've gone backwards in the login state machine, to this state where we show the UI + // AND the debug setting to exit in this case is true, then go ahead and bail quickly + if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) + { + LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; + // no requirement for notification here - just exit + LLAppViewer::instance()->earlyExitNoNotify(); + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + + // Login screen needs menus for preferences, but we can enter + // this startup phase more than once. + if (gLoginMenuBarView == NULL) + { + LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; + initialize_spellcheck_menu(); + init_menus(); + } + show_release_notes_if_required(); + + if (show_connect_box) + { + LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; + // Load all the name information out of the login view + // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't + // show the login view until login_show() is called below. + if (gUserCredential.isNull()) + { + LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + // Make sure the process dialog doesn't hide things + gViewerWindow->setShowProgress(FALSE); + // Show the login dialog + login_show(); + // connect dialog is already shown, so fill in the names + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); + LLPanelLogin::giveFocus(); + + // MAINT-3231 Show first run dialog only for Desura viewer + if (gSavedSettings.getString("sourceid") == "1208_desura") + { + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; + show_first_run_dialog(); + } + else + { + LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; + } + } + display_startup(); + LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input + } + else + { + LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; + // skip directly to message template verification + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + } + + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + show_debug_menus(); + + // Hide the splash screen + LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; + LLSplashScreen::hide(); + // Push our window frontmost + gViewerWindow->getWindow()->show(); + + // DEV-16927. The following code removes errant keystrokes that happen while the window is being + // first made visible. #ifdef _WIN32 LL_DEBUGS("AppInit") << "Processing PeekMessage" << LL_ENDL; - MSG msg; - while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) + MSG msg; + while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) { } LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL; #endif display_startup(); timeout.reset(); - return FALSE; - } - - if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) - { - // when we get to this state, we've already been past the login UI - // (possiblely automatically) - flag this so we can test in the - // STATE_LOGIN_SHOW state if we've gone backwards - mLoginStatePastUI = true; - - // Don't do anything. Wait for the login view to call the login_callback, - // which will push us to the next state. - - // display() function will be the one to run display_startup() - // Sleep so we don't spin the CPU - ms_sleep(1); - return FALSE; - } - - if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) - { - // Post login screen, we should see if any settings have changed that may - // require us to either start/stop or change the socks proxy. As various communications - // past this point may require the proxy to be up. - if (!LLStartUp::startLLProxy()) - { - // Proxy start up failed, we should now bail the state machine - // startLLProxy() will have reported an error to the user - // already, so we just go back to the login screen. The user - // could then change the preferences to fix the issue. - - LLStartUp::setStartupState(STATE_LOGIN_SHOW); - return FALSE; - } - - // reset the values that could have come in from a slurl - // DEV-42215: Make sure they're not empty -- gUserCredential - // might already have been set from gSavedSettings, and it's too bad - // to overwrite valid values with empty strings. - - if (show_connect_box) - { - // TODO if not use viewer auth - // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); - // end TODO - - // HACK: Try to make not jump on login - gKeyboard->resetKeys(); - } - - // when we get to this state, we've already been past the login UI - // (possiblely automatically) - flag this so we can test in the - // STATE_LOGIN_SHOW state if we've gone backwards - mLoginStatePastUI = true; - - // save the credentials - std::string userid = "unknown"; + return FALSE; + } + + if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) + { + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // Don't do anything. Wait for the login view to call the login_callback, + // which will push us to the next state. + + // display() function will be the one to run display_startup() + // Sleep so we don't spin the CPU + ms_sleep(1); + return FALSE; + } + + if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) + { + // Post login screen, we should see if any settings have changed that may + // require us to either start/stop or change the socks proxy. As various communications + // past this point may require the proxy to be up. + if (!LLStartUp::startLLProxy()) + { + // Proxy start up failed, we should now bail the state machine + // startLLProxy() will have reported an error to the user + // already, so we just go back to the login screen. The user + // could then change the preferences to fix the issue. + + LLStartUp::setStartupState(STATE_LOGIN_SHOW); + return FALSE; + } + + // reset the values that could have come in from a slurl + // DEV-42215: Make sure they're not empty -- gUserCredential + // might already have been set from gSavedSettings, and it's too bad + // to overwrite valid values with empty strings. + + if (show_connect_box) + { + // TODO if not use viewer auth + // Load all the name information out of the login view + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); + // end TODO + + // HACK: Try to make not jump on login + gKeyboard->resetKeys(); + } + + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // save the credentials + std::string userid = "unknown"; if (gUserCredential.notNull()) { userid = gUserCredential->userID(); @@ -928,24 +928,24 @@ bool idle_startup() gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); } } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); - gSavedSettings.setBOOL("RememberUser", gRememberUser); - LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; - gDebugInfo["LoginName"] = userid; - - // create necessary directories - // *FIX: these mkdir's should error check - gDirUtilp->setLindenUserDir(userid); - LLFile::mkdir(gDirUtilp->getLindenUserDir()); - - // As soon as directories are ready initialize notification storages - if (!LLPersistentNotificationStorage::instanceExists()) - { - // check existance since this part of code can be reached - // twice due to login failures - LLPersistentNotificationStorage::initParamSingleton(); - LLDoNotDisturbNotificationStorage::initParamSingleton(); - } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); + LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; + gDebugInfo["LoginName"] = userid; + + // create necessary directories + // *FIX: these mkdir's should error check + gDirUtilp->setLindenUserDir(userid); + LLFile::mkdir(gDirUtilp->getLindenUserDir()); + + // As soon as directories are ready initialize notification storages + if (!LLPersistentNotificationStorage::instanceExists()) + { + // check existance since this part of code can be reached + // twice due to login failures + LLPersistentNotificationStorage::initParamSingleton(); + LLDoNotDisturbNotificationStorage::initParamSingleton(); + } else { // reinitialize paths in case user switched grids or accounts @@ -953,152 +953,152 @@ bool idle_startup() LLDoNotDisturbNotificationStorage::getInstance()->reset(); } - // Set PerAccountSettingsFile to the default value. - std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); - gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); - gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; - - // Note: can't store warnings files per account because some come up before login - - // Overwrite default user settings with user settings - LLAppViewer::instance()->loadSettingsFromDirectory("Account"); - - // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). - LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); - if (logInstantMessagesControl.notNull()) - { - gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); - } - - // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation - // and startup time is close enough if we don't have a real value. - if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) - { - gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); - } - - //Default the path if one isn't set. - // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was - // provided in pre 2.0 viewer. See EXT-6661 - if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) - { - gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); - gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); - } - else - { - gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - } - gDirUtilp->setPerAccountChatLogsDir(userid); - - LLFile::mkdir(gDirUtilp->getChatLogsDir()); - LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); - - if (show_connect_box) - { - LLSLURL slurl; - //LLPanelLogin::closePanel(); - } - - - // Load URL History File - LLURLHistory::loadFile("url_history.xml"); - // Load location history - LLLocationHistory::getInstance()->load(); - - // Load Avatars icons cache - LLAvatarIconIDCache::getInstance()->load(); - - LLRenderMuteList::getInstance()->loadFromFile(); - - //------------------------------------------------- - // Handle startup progress screen - //------------------------------------------------- - - // on startup the user can request to go to their home, - // their last location, or some URL "-url //sim/x/y[/z]" - // All accounts have both a home and a last location, and we don't support - // more locations than that. Choose the appropriate one. JC - switch (LLStartUp::getStartSLURL().getType()) - { - case LLSLURL::LOCATION: - agent_location_id = START_LOCATION_ID_URL; - break; - case LLSLURL::LAST_LOCATION: - agent_location_id = START_LOCATION_ID_LAST; - break; - default: - agent_location_id = START_LOCATION_ID_HOME; - break; - } - - gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - - // Display the startup progress bar. - gViewerWindow->initTextures(agent_location_id); - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); - - gViewerWindow->revealIntroPanel(); - - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); - - return FALSE; - } - - if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) - { - gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); - - // Update progress status and the display loop. - auth_desc = LLTrans::getString("LoginInProgress"); - set_startup_status(progress, auth_desc, auth_message); - progress += 0.02f; - display_startup(); - - // Setting initial values... - LLLoginInstance* login = LLLoginInstance::getInstance(); - login->setNotificationsInterface(LLNotifications::getInstance()); - - login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); - login->setLastExecEvent(gLastExecEvent); - login->setLastExecDuration(gLastExecDuration); - - // This call to LLLoginInstance::connect() starts the - // authentication process. - login->connect(gUserCredential); - - LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); - return FALSE; - } - - if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) - { - // If we get here we have gotten past the potential stall - // in curl, so take "may appear frozen" out of progress bar. JC - auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); - set_startup_status(progress, auth_desc, auth_message); - - LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); - return FALSE; - } - - if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) - { - // Generic failure message - std::ostringstream emsg; - emsg << LLTrans::getString("LoginFailedHeader") << "\n"; - if(LLLoginInstance::getInstance()->authFailure()) - { - LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " - << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; - LLSD response = LLLoginInstance::getInstance()->getResponse(); - // Still have error conditions that may need some - // sort of handling - dig up specific message - std::string reason_response = response["reason"]; - std::string message_response = response["message"]; - std::string message_id = response["message_id"]; - std::string message; // actual string to show the user + // Set PerAccountSettingsFile to the default value. + std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); + gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); + gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; + + // Note: can't store warnings files per account because some come up before login + + // Overwrite default user settings with user settings + LLAppViewer::instance()->loadSettingsFromDirectory("Account"); + + // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). + LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); + if (logInstantMessagesControl.notNull()) + { + gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); + } + + // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation + // and startup time is close enough if we don't have a real value. + if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) + { + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + } + + //Default the path if one isn't set. + // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was + // provided in pre 2.0 viewer. See EXT-6661 + if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) + { + gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); + gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); + } + else + { + gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + } + gDirUtilp->setPerAccountChatLogsDir(userid); + + LLFile::mkdir(gDirUtilp->getChatLogsDir()); + LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); + + if (show_connect_box) + { + LLSLURL slurl; + //LLPanelLogin::closePanel(); + } + + + // Load URL History File + LLURLHistory::loadFile("url_history.xml"); + // Load location history + LLLocationHistory::getInstance()->load(); + + // Load Avatars icons cache + LLAvatarIconIDCache::getInstance()->load(); + + LLRenderMuteList::getInstance()->loadFromFile(); + + //------------------------------------------------- + // Handle startup progress screen + //------------------------------------------------- + + // on startup the user can request to go to their home, + // their last location, or some URL "-url //sim/x/y[/z]" + // All accounts have both a home and a last location, and we don't support + // more locations than that. Choose the appropriate one. JC + switch (LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + agent_location_id = START_LOCATION_ID_URL; + break; + case LLSLURL::LAST_LOCATION: + agent_location_id = START_LOCATION_ID_LAST; + break; + default: + agent_location_id = START_LOCATION_ID_HOME; + break; + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + // Display the startup progress bar. + gViewerWindow->initTextures(agent_location_id); + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); + + gViewerWindow->revealIntroPanel(); + + LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); + + return FALSE; + } + + if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) + { + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); + + // Update progress status and the display loop. + auth_desc = LLTrans::getString("LoginInProgress"); + set_startup_status(progress, auth_desc, auth_message); + progress += 0.02f; + display_startup(); + + // Setting initial values... + LLLoginInstance* login = LLLoginInstance::getInstance(); + login->setNotificationsInterface(LLNotifications::getInstance()); + + login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); + login->setLastExecEvent(gLastExecEvent); + login->setLastExecDuration(gLastExecDuration); + + // This call to LLLoginInstance::connect() starts the + // authentication process. + login->connect(gUserCredential); + + LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); + return FALSE; + } + + if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) + { + // If we get here we have gotten past the potential stall + // in curl, so take "may appear frozen" out of progress bar. JC + auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); + set_startup_status(progress, auth_desc, auth_message); + + LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); + return FALSE; + } + + if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) + { + // Generic failure message + std::ostringstream emsg; + emsg << LLTrans::getString("LoginFailedHeader") << "\n"; + if(LLLoginInstance::getInstance()->authFailure()) + { + LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " + << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; + LLSD response = LLLoginInstance::getInstance()->getResponse(); + // Still have error conditions that may need some + // sort of handling - dig up specific message + std::string reason_response = response["reason"]; + std::string message_response = response["message"]; + std::string message_id = response["message_id"]; + std::string message; // actual string to show the user bool localized_by_id = false; if(!message_id.empty()) @@ -1131,63 +1131,63 @@ bool idle_startup() } if(!localized_by_id && !message_response.empty()) - { - // *HACK: "no_inventory_host" sent as the message itself. - // Remove this clause when server is sending message_id as well. - message = LLAgent::sTeleportErrorMessages[ message_response ]; - } - - if (message.empty()) - { - // Fallback to server-supplied string; necessary since server - // may add strings that this viewer is not yet aware of - message = message_response; - } - - emsg << message; - - - if(reason_response == "key") - { - // Couldn't login because user/password is wrong - // Clear the credential - gUserCredential->clearAuthenticator(); - } - - if(reason_response == "update" - || reason_response == "optional") - { - // In the case of a needed update, quit. - // Its either downloading or declined. - // If optional was skipped this case shouldn't - // be reached. - - LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; - LLLoginInstance::getInstance()->disconnect(); - LLAppViewer::instance()->forceQuit(); - } - else - { - if (reason_response != "tos" && reason_response != "mfa_challenge") - { - // Don't pop up a notification in the TOS or MFA cases because - // the specialized floater has already scolded the user. - std::string error_code; - if(response.has("errorcode")) - { - error_code = response["errorcode"].asString(); - } - if ((reason_response == "CURLError") && - (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && - response.has("certificate")) - { - // This was a certificate error, so grab the certificate - // and throw up the appropriate dialog. - LLPointer<LLCertificate> certificate; - try - { - certificate = gSecAPIHandler->getCertificate(response["certificate"]); - } + { + // *HACK: "no_inventory_host" sent as the message itself. + // Remove this clause when server is sending message_id as well. + message = LLAgent::sTeleportErrorMessages[ message_response ]; + } + + if (message.empty()) + { + // Fallback to server-supplied string; necessary since server + // may add strings that this viewer is not yet aware of + message = message_response; + } + + emsg << message; + + + if(reason_response == "key") + { + // Couldn't login because user/password is wrong + // Clear the credential + gUserCredential->clearAuthenticator(); + } + + if(reason_response == "update" + || reason_response == "optional") + { + // In the case of a needed update, quit. + // Its either downloading or declined. + // If optional was skipped this case shouldn't + // be reached. + + LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; + LLLoginInstance::getInstance()->disconnect(); + LLAppViewer::instance()->forceQuit(); + } + else + { + if (reason_response != "tos" && reason_response != "mfa_challenge") + { + // Don't pop up a notification in the TOS or MFA cases because + // the specialized floater has already scolded the user. + std::string error_code; + if(response.has("errorcode")) + { + error_code = response["errorcode"].asString(); + } + if ((reason_response == "CURLError") && + (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && + response.has("certificate")) + { + // This was a certificate error, so grab the certificate + // and throw up the appropriate dialog. + LLPointer<LLCertificate> certificate; + try + { + certificate = gSecAPIHandler->getCertificate(response["certificate"]); + } catch (LLCertException &cert_exception) { LL_WARNS("LLStartup", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL; @@ -1201,1231 +1201,1231 @@ bool idle_startup() gSavedSettings.setBOOL("AutoLogin", FALSE); show_connect_box = true; } - if(certificate) - { - LLSD args = transform_cert_args(certificate); - - if(error_code == "SSL_CACERT") - { - // if we are handling an untrusted CA, throw up the dialog - // with the 'trust this CA' button. - LLNotificationsUtil::add("TrustCertificateError", args, response, - trust_cert_done); - - show_connect_box = true; - } - else - { - // the certificate exception returns a unique string for each type of exception. - // we grab this string via the LLUserAuth object, and use that to grab the localized - // string. - args["REASON"] = LLTrans::getString(message_response); - - LLNotificationsUtil::add("GeneralCertificateError", args, response, - general_cert_done); - - reset_login(); - gSavedSettings.setBOOL("AutoLogin", FALSE); - show_connect_box = true; - - } - - } - } + if(certificate) + { + LLSD args = transform_cert_args(certificate); + + if(error_code == "SSL_CACERT") + { + // if we are handling an untrusted CA, throw up the dialog + // with the 'trust this CA' button. + LLNotificationsUtil::add("TrustCertificateError", args, response, + trust_cert_done); + + show_connect_box = true; + } + else + { + // the certificate exception returns a unique string for each type of exception. + // we grab this string via the LLUserAuth object, and use that to grab the localized + // string. + args["REASON"] = LLTrans::getString(message_response); + + LLNotificationsUtil::add("GeneralCertificateError", args, response, + general_cert_done); + + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + show_connect_box = true; + + } + + } + } else if (reason_response == "BadType") { LLNotificationsUtil::add("LoginFailedToParse", LLSD(), LLSD(), login_alert_done); } - else if (!message.empty()) - { - // This wasn't a certificate error, so throw up the normal - // notificatioin message. - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); - } - } - transition_back_to_login_panel(emsg.str()); - show_connect_box = true; - } - } - else if(LLLoginInstance::getInstance()->authSuccess()) - { - if(process_login_success_response()) - { - // Pass the user information to the voice chat server interface. - LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); - // create the default proximal channel - LLVoiceChannel::initClass(); - LLStartUp::setStartupState( STATE_WORLD_INIT); - LLTrace::get_frame_recording().reset(); - } - else - { - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); - transition_back_to_login_panel(emsg.str()); - show_connect_box = true; - return FALSE; - } - } - return FALSE; - } - - //--------------------------------------------------------------------- - // World Init - //--------------------------------------------------------------------- - if (STATE_WORLD_INIT == LLStartUp::getStartupState()) - { - set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); - display_startup(); - // We should have an agent id by this point. - llassert(!(gAgentID == LLUUID::null)); - - // Finish agent initialization. (Requires gSavedSettings, builds camera) - gAgent.init(); - display_startup(); - gAgentCamera.init(); - display_startup(); - display_startup(); - - // Since we connected, save off the settings so the user doesn't have to - // type the name/password again if we crash. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - LLUIColorTable::instance().saveUserSettings(); - - display_startup(); - - // - // Initialize classes w/graphics stuff. - // - LLViewerStatsRecorder::instance(); // Since textures work in threads - LLSurface::initClasses(); - display_startup(); - - display_startup(); - - LLDrawable::initClass(); - display_startup(); - - // init the shader managers - LLPostProcess::initClass(); - display_startup(); + else if (!message.empty()) + { + // This wasn't a certificate error, so throw up the normal + // notificatioin message. + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + } + } + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + } + } + else if(LLLoginInstance::getInstance()->authSuccess()) + { + if(process_login_success_response()) + { + // Pass the user information to the voice chat server interface. + LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); + // create the default proximal channel + LLVoiceChannel::initClass(); + LLStartUp::setStartupState( STATE_WORLD_INIT); + LLTrace::get_frame_recording().reset(); + } + else + { + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + return FALSE; + } + } + return FALSE; + } + + //--------------------------------------------------------------------- + // World Init + //--------------------------------------------------------------------- + if (STATE_WORLD_INIT == LLStartUp::getStartupState()) + { + set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + display_startup(); + // We should have an agent id by this point. + llassert(!(gAgentID == LLUUID::null)); + + // Finish agent initialization. (Requires gSavedSettings, builds camera) + gAgent.init(); + display_startup(); + gAgentCamera.init(); + display_startup(); + display_startup(); + + // Since we connected, save off the settings so the user doesn't have to + // type the name/password again if we crash. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + LLUIColorTable::instance().saveUserSettings(); + + display_startup(); + + // + // Initialize classes w/graphics stuff. + // + LLViewerStatsRecorder::instance(); // Since textures work in threads + LLSurface::initClasses(); + display_startup(); + + display_startup(); + + LLDrawable::initClass(); + display_startup(); + + // init the shader managers + LLPostProcess::initClass(); + display_startup(); + + LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); + display_startup(); + + LLViewerObject::initVOClasses(); + display_startup(); + + // Initialize all our tools. Must be done after saved settings loaded. + // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. + LLToolMgr::getInstance()->initTools(); + display_startup(); + + // Pre-load floaters, like the world map, that are slow to spawn + // due to XML complexity. + gViewerWindow->initWorldUI(); + + display_startup(); + + // This is where we used to initialize gWorldp. Original comment said: + // World initialization must be done after above window init + + // User might have overridden far clip + LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); + display_startup(); + // Before we create the first region, we need to set the agent's mOriginGlobal + // This is necessary because creating objects before this is set will result in a + // bad mPositionAgent cache. + + gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); + display_startup(); + + LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); + display_startup(); + + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " + << gFirstSimSeedCap << LL_ENDL; + regionp->setSeedCapability(gFirstSimSeedCap); + LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; + display_startup(); + // Set agent's initial region to be the one we just created. + gAgent.setRegion(regionp); + display_startup(); + // Set agent's initial position, which will be read by LLVOAvatar when the avatar + // object is created. I think this must be done after setting the region. JC + gAgent.setPositionAgent(agent_start_position_region); + + display_startup(); + LLStartUp::initExperiences(); + + display_startup(); + + // If logging should be enebled, turns it on and loads history from disk + // Note: does not happen on init of singleton because preferences can use + // this instance without logging in + LLConversationLog::getInstance()->initLoggingState(); + + LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); + + return FALSE; + } + + + //--------------------------------------------------------------------- + // Load QuickTime/GStreamer and other multimedia engines, can be slow. + // Do it while we're waiting on the network for our seed capability. JC + //--------------------------------------------------------------------- + if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) + { + LLStartUp::multimediaInit(); + LLStartUp::setStartupState( STATE_FONT_INIT ); + display_startup(); + return FALSE; + } + + // Loading fonts takes several seconds + if (STATE_FONT_INIT == LLStartUp::getStartupState()) + { + LLStartUp::fontInit(); + LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); + display_startup(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Wait for Seed Cap Grant + //--------------------------------------------------------------------- + if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + if (regionp->capabilitiesReceived()) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + else if (regionp->capabilitiesError()) + { + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else + { + U32 num_retries = regionp->getNumSeedCapRetries(); + if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) + { + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else if (num_retries > 0) + { + LLStringUtil::format_map_t args; + args["[NUMBER]"] = llformat("%d", num_retries + 1); + set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); + } + else + { + set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); + } + } + display_startup(); + return FALSE; + } + + + //--------------------------------------------------------------------- + // Seed Capability Granted + // no newMessage calls should happen before this point + //--------------------------------------------------------------------- + if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) + { + display_startup(); + + // These textures are not warrantied to be cached, so needs + // to hapen with caps granted + gTextureList.doPrefetchImages(); + + // will init images, should be done with caps, but before gSky.init() + LLEnvironment::getInstance()->initSingleton(); + + display_startup(); + update_texture_fetch(); + display_startup(); + + if ( gViewerWindow != NULL) + { // This isn't the first logon attempt, so show the UI + gViewerWindow->setNormalControlsVisible( TRUE ); + } + gLoginMenuBarView->setVisible( FALSE ); + gLoginMenuBarView->setEnabled( FALSE ); + display_startup(); + + // direct logging to the debug console's line buffer + LLError::logToFixedBuffer(gDebugView->mDebugConsolep); + display_startup(); + + // set initial visibility of debug console + gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); + display_startup(); + + // + // Set message handlers + // + LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; + + // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted + register_viewer_callbacks(gMessageSystem); + display_startup(); + + // Debugging info parameters + gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms + display_startup(); + + #ifndef LL_RELEASE_FOR_DOWNLOAD + gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg + gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode + #endif + display_startup(); + + gXferManager->registerCallbacks(gMessageSystem); + display_startup(); + + LLStartUp::initNameCache(); + display_startup(); + + // update the voice settings *after* gCacheName initialization + // so that we can construct voice UI that relies on the name cache + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->updateSettings(); + } + display_startup(); + + // create a container's instance for start a controlling conversation windows + // by the voice's events + LLFloaterIMContainer::getInstance(); + if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) + { + LLViewerParcelAskPlay::getInstance()->loadSettings(); + } + + gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); + + // *Note: this is where gWorldMap used to be initialized. + + // register null callbacks for audio until the audio system is initialized + gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); + gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); + display_startup(); + + //reset statistics + LLViewerStats::instance().resetStats(); + + display_startup(); + // + // Set up region and surface defaults + // + + + // Sets up the parameters for the first simulator + + LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; + gFrameTime = totalTime(); + F32Seconds last_time = gFrameTimeSeconds; + gFrameTimeSeconds = (gFrameTime - gStartTime); + + gFrameIntervalSeconds = gFrameTimeSeconds - last_time; + if (gFrameIntervalSeconds < 0.f) + { + gFrameIntervalSeconds = 0.f; + } + + // Make sure agent knows correct aspect ratio + // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below + LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); + LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); + // Initialize FOV + LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); + display_startup(); + + // Move agent to starting location. The position handed to us by + // the space server is in global coordinates, but the agent frame + // is in region local coordinates. Therefore, we need to adjust + // the coordinates handed to us to fit in the local region. + + gAgent.setPositionAgent(agent_start_position_region); + gAgent.resetAxes(gAgentStartLookAt); + gAgentCamera.stopCameraAnimation(); + gAgentCamera.resetCamera(); + display_startup(); + + // Initialize global class data needed for surfaces (i.e. textures) + LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; + // Initialize all of the viewer object classes for the first time (doing things like texture fetches. + LLGLState::checkStates(); + + gSky.init(); + + LLGLState::checkStates(); + + display_startup(); + + LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; + // For all images pre-loaded into viewer cache, init + // priorities and fetching using decodeAllImages. + // Most of the fetching and decoding likely to be done + // by update_texture_fetch() later, while viewer waits. + // + // Need to do this AFTER we init the sky + const S32 DECODE_TIME_SEC = 2; + for (int i = 0; i < DECODE_TIME_SEC; i++) + { + F32 frac = (F32)i / (F32)DECODE_TIME_SEC; + set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); + display_startup(); + gTextureList.decodeAllImages(1.f); + } + LLStartUp::setStartupState( STATE_WORLD_WAIT ); + + display_startup(); + + // JC - Do this as late as possible to increase likelihood Purify + // will run. + LLMessageSystem* msg = gMessageSystem; + if (!msg->mOurCircuitCode) + { + LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; + } + + gUseCircuitCallbackCalled = false; + + msg->enableCircuit(gFirstSim, TRUE); + // now, use the circuit info to tell simulator about us! + LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; + msg->newMessageFast(_PREHASH_UseCircuitCode); + msg->nextBlockFast(_PREHASH_CircuitCode); + msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); + msg->sendReliable( + gFirstSim, + gSavedSettings.getS32("UseCircuitCodeMaxRetries"), + FALSE, + (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), + use_circuit_callback, + NULL); + + timeout.reset(); + display_startup(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // World Wait + //--------------------------------------------------------------------- + if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; + set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); + if(gGotUseCircuitCodeAck) + { + LLStartUp::setStartupState( STATE_AGENT_SEND ); + } + pump_idle_startup_network(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Send + //--------------------------------------------------------------------- + if (STATE_AGENT_SEND == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; + set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); + display_startup(); + // register with the message system so it knows we're + // expecting this message + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast( + _PREHASH_AgentMovementComplete, + process_agent_movement_complete); + LLViewerRegion* regionp = gAgent.getRegion(); + if(regionp) + { + send_complete_agent_movement(regionp->getHost()); + gAssetStorage->setUpstream(regionp->getHost()); + gCacheName->setUpstream(regionp->getHost()); + } + display_startup(); + + // Create login effect + // But not on first login, because you can't see your avatar then + if (!gAgent.isFirstLogin()) + { + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + } + + LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT + + timeout.reset(); + display_startup(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Wait + //--------------------------------------------------------------------- + if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) + { + { + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) + { + if (gAgentMovementCompleted) + { + // Sometimes we have more than one message in the + // queue. break out of this loop and continue + // processing. If we don't, then this could skip one + // or more login steps. + break; + } + else + { + LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " + << gMessageSystem->getMessageName() << LL_ENDL; + } + display_startup(); + } + lmc.processAcks(); + } + + display_startup(); + + if (gAgentMovementCompleted) + { + LLStartUp::setStartupState( STATE_INVENTORY_SEND ); + } + display_startup(); + + if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) + { + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + return FALSE; + } + + //--------------------------------------------------------------------- + // Inventory Send + //--------------------------------------------------------------------- + if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory send") + display_startup(); + + // request mute list + LL_INFOS() << "Requesting Mute List" << LL_ENDL; + LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + + // Get L$ and ownership credit information + LL_INFOS() << "Requesting Money Balance" << LL_ENDL; + LLStatusBar::sendMoneyBalanceRequest(); + + display_startup(); + + // Inform simulator of our language preference + LLAgentLanguage::update(); + + display_startup(); + // unpack thin inventory + LLSD response = LLLoginInstance::getInstance()->getResponse(); + //bool dump_buffer = false; + + LLSD inv_lib_root = response["inventory-lib-root"]; + if(inv_lib_root.isDefined()) + { + // should only be one + LLSD id = inv_lib_root[0]["folder_id"]; + if(id.isDefined()) + { + gInventory.setLibraryRootFolderID(id.asUUID()); + } + } + display_startup(); + + LLSD inv_lib_owner = response["inventory-lib-owner"]; + if(inv_lib_owner.isDefined()) + { + // should only be one + LLSD id = inv_lib_owner[0]["agent_id"]; + if(id.isDefined()) + { + gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); + } + } + display_startup(); + LLStartUp::setStartupState(STATE_INVENTORY_SKEL); + display_startup(); + return FALSE; + } + + if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory load skeleton") + + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + LLSD inv_skel_lib = response["inventory-skel-lib"]; + if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + { + LL_PROFILE_ZONE_NAMED("load library inv") + if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + } + } + display_startup(); + + LLSD inv_skeleton = response["inventory-skeleton"]; + if (inv_skeleton.isDefined()) + { + LL_PROFILE_ZONE_NAMED("load personal inv") + if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; + } + } + display_startup(); + LLStartUp::setStartupState(STATE_INVENTORY_SEND2); + display_startup(); + return FALSE; + } + + if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory send2") + + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + LLSD inv_basic = response["inventory-basic"]; + if(inv_basic.isDefined()) + { + LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; + } + + LLSD buddy_list = response["buddy-list"]; + if(buddy_list.isDefined()) + { + LLAvatarTracker::buddy_map_t list; + LLUUID agent_id; + S32 has_rights = 0, given_rights = 0; + for(LLSD::array_const_iterator it = buddy_list.beginArray(), + end = buddy_list.endArray(); it != end; ++it) + { + LLSD buddy_id = (*it)["buddy_id"]; + if(buddy_id.isDefined()) + { + agent_id = buddy_id.asUUID(); + } + + LLSD buddy_rights_has = (*it)["buddy_rights_has"]; + if(buddy_rights_has.isDefined()) + { + has_rights = buddy_rights_has.asInteger(); + } + + LLSD buddy_rights_given = (*it)["buddy_rights_given"]; + if(buddy_rights_given.isDefined()) + { + given_rights = buddy_rights_given.asInteger(); + } + + list[agent_id] = new LLRelationship(given_rights, has_rights, false); + } + LLAvatarTracker::instance().addBuddyList(list); + display_startup(); + } + + bool show_hud = false; + LLSD tutorial_setting = response["tutorial_setting"]; + if(tutorial_setting.isDefined()) + { + for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), + end = tutorial_setting.endArray(); it != end; ++it) + { + LLSD tutorial_url = (*it)["tutorial_url"]; + if(tutorial_url.isDefined()) + { + // Tutorial floater will append language code + gSavedSettings.setString("TutorialURL", tutorial_url.asString()); + } + + // For Viewer 2.0 we are not using the web-based tutorial + // If we reverse that decision, put this code back and use + // login.cgi to send a different URL with content that matches + // the Viewer 2.0 UI. + //LLSD use_tutorial = (*it)["use_tutorial"]; + //if(use_tutorial.asString() == "true") + //{ + // show_hud = true; + //} + } + } + display_startup(); + + // Either we want to show tutorial because this is the first login + // to a Linden Help Island or the user quit with the tutorial + // visible. JC + if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) + { + LLFloaterReg::showInstance("hud", LLSD(), FALSE); + } + display_startup(); + + LLSD event_notifications = response["event_notifications"]; + if(event_notifications.isDefined()) + { + gEventNotifier.load(event_notifications); + } + display_startup(); + + LLSD classified_categories = response["classified_categories"]; + if(classified_categories.isDefined()) + { + LLClassifiedInfo::loadCategories(classified_categories); + } + display_startup(); + + // This method MUST be called before gInventory.findCategoryUUIDForType because of + // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. + gInventory.buildParentChildMap(); + + // If buildParentChildMap succeeded, inventory will now be in + // a usable state and gInventory.isInventoryUsable() will be + // true. + + // if inventory is unusable, show warning. + if (!gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("InventoryUnusable"); + } + + LLInventoryModelBackgroundFetch::instance().start(); + gInventory.createCommonSystemCategories(); + LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); + display_startup(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // STATE_INVENTORY_CALLBACKS + //--------------------------------------------------------------------- + if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) + { + if (!LLInventoryModel::isSysFoldersReady()) + { + display_startup(); + return FALSE; + } + LLInventoryModelBackgroundFetch::instance().start(); + LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); + if (cof + && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // Special case, dupplicate request prevention. + // Cof folder will be requested via FetchCOF + // in appearance manager, prevent recursive fetch + cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); + } + + + // It's debatable whether this flag is a good idea - sets all + // bits, and in general it isn't true that inventory + // initialization generates all types of changes. Maybe add an + // INITIALIZE mask bit instead? + gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); + gInventory.notifyObservers(); + + display_startup(); + + // set up callbacks + LL_INFOS() << "Registering Callbacks" << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + LL_INFOS() << " Inventory" << LL_ENDL; + LLInventoryModel::registerCallbacks(msg); + LL_INFOS() << " AvatarTracker" << LL_ENDL; + LLAvatarTracker::instance().registerCallbacks(msg); + LL_INFOS() << " Landmark" << LL_ENDL; + LLLandmark::registerCallbacks(msg); + display_startup(); + + // request all group information + LL_INFOS() << "Requesting Agent Data" << LL_ENDL; + gAgent.sendAgentDataUpdateRequest(); + display_startup(); + // Create the inventory views + LL_INFOS() << "Creating Inventory Views" << LL_ENDL; + LLFloaterReg::getInstance("inventory"); + display_startup(); + LLStartUp::setStartupState( STATE_MISC ); + display_startup(); + + return FALSE; + } + - LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); - display_startup(); - - LLViewerObject::initVOClasses(); - display_startup(); - - // Initialize all our tools. Must be done after saved settings loaded. - // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. - LLToolMgr::getInstance()->initTools(); - display_startup(); - - // Pre-load floaters, like the world map, that are slow to spawn - // due to XML complexity. - gViewerWindow->initWorldUI(); - - display_startup(); - - // This is where we used to initialize gWorldp. Original comment said: - // World initialization must be done after above window init - - // User might have overridden far clip - LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); - display_startup(); - // Before we create the first region, we need to set the agent's mOriginGlobal - // This is necessary because creating objects before this is set will result in a - // bad mPositionAgent cache. - - gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); - display_startup(); - - LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); - display_startup(); - - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); - LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; - - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " - << gFirstSimSeedCap << LL_ENDL; - regionp->setSeedCapability(gFirstSimSeedCap); - LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; - display_startup(); - // Set agent's initial region to be the one we just created. - gAgent.setRegion(regionp); - display_startup(); - // Set agent's initial position, which will be read by LLVOAvatar when the avatar - // object is created. I think this must be done after setting the region. JC - gAgent.setPositionAgent(agent_start_position_region); - - display_startup(); - LLStartUp::initExperiences(); - - display_startup(); - - // If logging should be enebled, turns it on and loads history from disk - // Note: does not happen on init of singleton because preferences can use - // this instance without logging in - LLConversationLog::getInstance()->initLoggingState(); - - LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); - - return FALSE; - } - - - //--------------------------------------------------------------------- - // Load QuickTime/GStreamer and other multimedia engines, can be slow. - // Do it while we're waiting on the network for our seed capability. JC - //--------------------------------------------------------------------- - if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) - { - LLStartUp::multimediaInit(); - LLStartUp::setStartupState( STATE_FONT_INIT ); - display_startup(); - return FALSE; - } - - // Loading fonts takes several seconds - if (STATE_FONT_INIT == LLStartUp::getStartupState()) - { - LLStartUp::fontInit(); - LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); - display_startup(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Wait for Seed Cap Grant - //--------------------------------------------------------------------- - if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); - if (regionp->capabilitiesReceived()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - else if (regionp->capabilitiesError()) + //--------------------------------------------------------------------- + // Misc + //--------------------------------------------------------------------- + if (STATE_MISC == LLStartUp::getStartupState()) + { + // We have a region, and just did a big inventory download. + // We can estimate the user's connection speed, and set their + // max bandwidth accordingly. JC + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { - LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) + // This is actually a pessimistic computation, because TCP may not have enough + // time to ramp up on the (small) default inventory file to truly measure max + // bandwidth. JC + F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); + const F32 FAST_RATE_BPS = 600.f * 1024.f; + const F32 FASTER_RATE_BPS = 750.f * 1024.f; + F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); + if (rate_bps > FASTER_RATE_BPS + && rate_bps > max_bandwidth) { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FASTER_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); } - else + else if (rate_bps > FAST_RATE_BPS + && rate_bps > max_bandwidth) { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FAST_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); } - reset_login(); - } - else - { - U32 num_retries = regionp->getNumSeedCapRetries(); - if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) + + if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) { - LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); + gSavedSettings.setBOOL("HelpFloaterOpen", TRUE); } - else if (num_retries > 0) - { - LLStringUtil::format_map_t args; - args["[NUMBER]"] = llformat("%d", num_retries + 1); - set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); - } - else - { - set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); - } - } - display_startup(); - return FALSE; - } - - - //--------------------------------------------------------------------- - // Seed Capability Granted - // no newMessage calls should happen before this point - //--------------------------------------------------------------------- - if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) - { - display_startup(); - // These textures are not warrantied to be cached, so needs - // to hapen with caps granted - gTextureList.doPrefetchImages(); - - // will init images, should be done with caps, but before gSky.init() - LLEnvironment::getInstance()->initSingleton(); + // Set the show start location to true, now that the user has logged + // on with this install. + gSavedSettings.setBOOL("ShowStartLocation", TRUE); + } display_startup(); - update_texture_fetch(); - display_startup(); - - if ( gViewerWindow != NULL) - { // This isn't the first logon attempt, so show the UI - gViewerWindow->setNormalControlsVisible( TRUE ); - } - gLoginMenuBarView->setVisible( FALSE ); - gLoginMenuBarView->setEnabled( FALSE ); - display_startup(); - - // direct logging to the debug console's line buffer - LLError::logToFixedBuffer(gDebugView->mDebugConsolep); - display_startup(); - - // set initial visibility of debug console - gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); - display_startup(); - - // - // Set message handlers - // - LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; - - // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted - register_viewer_callbacks(gMessageSystem); - display_startup(); - - // Debugging info parameters - gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms - display_startup(); - - #ifndef LL_RELEASE_FOR_DOWNLOAD - gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg - gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode - #endif - display_startup(); - - gXferManager->registerCallbacks(gMessageSystem); - display_startup(); - - LLStartUp::initNameCache(); - display_startup(); - - // update the voice settings *after* gCacheName initialization - // so that we can construct voice UI that relies on the name cache - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->updateSettings(); - } - display_startup(); - - // create a container's instance for start a controlling conversation windows - // by the voice's events - LLFloaterIMContainer::getInstance(); - if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) - { - LLViewerParcelAskPlay::getInstance()->loadSettings(); - } - - gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); - - // *Note: this is where gWorldMap used to be initialized. - - // register null callbacks for audio until the audio system is initialized - gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); - display_startup(); - - //reset statistics - LLViewerStats::instance().resetStats(); - - display_startup(); - // - // Set up region and surface defaults - // - - - // Sets up the parameters for the first simulator - - LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; - gFrameTime = totalTime(); - F32Seconds last_time = gFrameTimeSeconds; - gFrameTimeSeconds = (gFrameTime - gStartTime); - - gFrameIntervalSeconds = gFrameTimeSeconds - last_time; - if (gFrameIntervalSeconds < 0.f) - { - gFrameIntervalSeconds = 0.f; - } - - // Make sure agent knows correct aspect ratio - // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below - LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); - LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); - // Initialize FOV - LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); - display_startup(); - - // Move agent to starting location. The position handed to us by - // the space server is in global coordinates, but the agent frame - // is in region local coordinates. Therefore, we need to adjust - // the coordinates handed to us to fit in the local region. - - gAgent.setPositionAgent(agent_start_position_region); - gAgent.resetAxes(gAgentStartLookAt); - gAgentCamera.stopCameraAnimation(); - gAgentCamera.resetCamera(); - display_startup(); - - // Initialize global class data needed for surfaces (i.e. textures) - LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; - // Initialize all of the viewer object classes for the first time (doing things like texture fetches. - LLGLState::checkStates(); - - gSky.init(); - - LLGLState::checkStates(); - - display_startup(); - - LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; - // For all images pre-loaded into viewer cache, init - // priorities and fetching using decodeAllImages. - // Most of the fetching and decoding likely to be done - // by update_texture_fetch() later, while viewer waits. - // - // Need to do this AFTER we init the sky - const S32 DECODE_TIME_SEC = 2; - for (int i = 0; i < DECODE_TIME_SEC; i++) - { - F32 frac = (F32)i / (F32)DECODE_TIME_SEC; - set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); - display_startup(); - gTextureList.decodeAllImages(1.f); - } - LLStartUp::setStartupState( STATE_WORLD_WAIT ); - - display_startup(); - - // JC - Do this as late as possible to increase likelihood Purify - // will run. - LLMessageSystem* msg = gMessageSystem; - if (!msg->mOurCircuitCode) - { - LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; - } - - gUseCircuitCallbackCalled = false; - - msg->enableCircuit(gFirstSim, TRUE); - // now, use the circuit info to tell simulator about us! - LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable( - gFirstSim, - gSavedSettings.getS32("UseCircuitCodeMaxRetries"), - FALSE, - (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), - use_circuit_callback, - NULL); - - timeout.reset(); - display_startup(); - - return FALSE; - } - - //--------------------------------------------------------------------- - // World Wait - //--------------------------------------------------------------------- - if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; - set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); - if(gGotUseCircuitCodeAck) - { - LLStartUp::setStartupState( STATE_AGENT_SEND ); - } - pump_idle_startup_network(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Agent Send - //--------------------------------------------------------------------- - if (STATE_AGENT_SEND == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; - set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); - display_startup(); - // register with the message system so it knows we're - // expecting this message - LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFuncFast( - _PREHASH_AgentMovementComplete, - process_agent_movement_complete); - LLViewerRegion* regionp = gAgent.getRegion(); - if(regionp) - { - send_complete_agent_movement(regionp->getHost()); - gAssetStorage->setUpstream(regionp->getHost()); - gCacheName->setUpstream(regionp->getHost()); - } - display_startup(); - - // Create login effect - // But not on first login, because you can't see your avatar then - if (!gAgent.isFirstLogin()) - { - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - } - - LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT - - timeout.reset(); - display_startup(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Agent Wait - //--------------------------------------------------------------------- - if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) - { - { - LockMessageChecker lmc(gMessageSystem); - while (lmc.checkAllMessages(gFrameCount, gServicePump)) - { - if (gAgentMovementCompleted) - { - // Sometimes we have more than one message in the - // queue. break out of this loop and continue - // processing. If we don't, then this could skip one - // or more login steps. - break; - } - else - { - LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " - << gMessageSystem->getMessageName() << LL_ENDL; - } - display_startup(); - } - lmc.processAcks(); - } - - display_startup(); - - if (gAgentMovementCompleted) - { - LLStartUp::setStartupState( STATE_INVENTORY_SEND ); - } - display_startup(); - - if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) - { - LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); - } - return FALSE; - } - - //--------------------------------------------------------------------- - // Inventory Send - //--------------------------------------------------------------------- - if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) - { - LL_PROFILE_ZONE_NAMED("State inventory send") - display_startup(); - // request mute list - LL_INFOS() << "Requesting Mute List" << LL_ENDL; - LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + // Load stored local environment if needed. + LLEnvironment::instance().loadFromSettings(); - // Get L$ and ownership credit information - LL_INFOS() << "Requesting Money Balance" << LL_ENDL; - LLStatusBar::sendMoneyBalanceRequest(); + // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) + //check_merchant_status(); display_startup(); - // Inform simulator of our language preference - LLAgentLanguage::update(); - - display_startup(); - // unpack thin inventory - LLSD response = LLLoginInstance::getInstance()->getResponse(); - //bool dump_buffer = false; - - LLSD inv_lib_root = response["inventory-lib-root"]; - if(inv_lib_root.isDefined()) - { - // should only be one - LLSD id = inv_lib_root[0]["folder_id"]; - if(id.isDefined()) - { - gInventory.setLibraryRootFolderID(id.asUUID()); - } - } - display_startup(); - - LLSD inv_lib_owner = response["inventory-lib-owner"]; - if(inv_lib_owner.isDefined()) - { - // should only be one - LLSD id = inv_lib_owner[0]["agent_id"]; - if(id.isDefined()) - { - gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); - } - } - display_startup(); - LLStartUp::setStartupState(STATE_INVENTORY_SKEL); - display_startup(); - return FALSE; - } + if (gSavedSettings.getBOOL("HelpFloaterOpen")) + { + // show default topic + LLViewerHelp::instance().showTopic(""); + } - if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) - { - LL_PROFILE_ZONE_NAMED("State inventory load skeleton") + display_startup(); - LLSD response = LLLoginInstance::getInstance()->getResponse(); + // We're successfully logged in. + gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); - LLSD inv_skel_lib = response["inventory-skel-lib"]; - if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + LLFloaterReg::showInitialVisibleInstances(); + + LLFloaterGridStatus::getInstance()->startGridStatusTimer(); + + display_startup(); + + display_startup(); + // JC: Initializing audio requests many sounds for download. + init_audio(); + display_startup(); + + // JC: Initialize "active" gestures. This may also trigger + // many gesture downloads, if this is the user's first + // time on this machine or -purge has been run. + LLSD gesture_options + = LLLoginInstance::getInstance()->getResponse("gestures"); + if (gesture_options.isDefined()) { - LL_PROFILE_ZONE_NAMED("load library inv") - if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() + << LL_ENDL; + uuid_vec_t item_ids; + for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), + end = gesture_options.endArray(); resp_it != end; ++resp_it) { - LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + // If the id is not specifed in the LLSD, + // the LLSD operator[]() will return a null LLUUID. + LLUUID item_id = (*resp_it)["item_id"]; + LLUUID asset_id = (*resp_it)["asset_id"]; + + if (item_id.notNull() && asset_id.notNull()) + { + // Could schedule and delay these for later. + const BOOL no_inform_server = FALSE; + const BOOL no_deactivate_similar = FALSE; + LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, + no_inform_server, + no_deactivate_similar); + // We need to fetch the inventory items for these gestures + // so we have the names to populate the UI. + item_ids.push_back(item_id); + } } + // no need to add gesture to inventory observer, it's already made in constructor + LLGestureMgr::instance().setFetchIDs(item_ids); + LLGestureMgr::instance().startFetch(); } + gDisplaySwapBuffers = TRUE; display_startup(); - LLSD inv_skeleton = response["inventory-skeleton"]; - if (inv_skeleton.isDefined()) + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); + msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); + + LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; + + LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; + gRenderStartTime.reset(); + gForegroundTime.reset(); + + // HACK: Inform simulator of window size. + // Do this here so it's less likely to race with RegisterNewAgent. + // TODO: Put this into RegisterNewAgent + // JC - 7/20/2002 + gViewerWindow->sendShapeToSim(); + + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + + // The reason we show the alert is because we want to + // reduce confusion for when you log in and your provided + // location is not your expected location. So, if this is + // your first login, then you do not have an expectation, + // thus, do not show this alert. + if (!gAgent.isFirstLogin()) { - LL_PROFILE_ZONE_NAMED("load personal inv") - if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; + LLSLURL start_slurl = LLStartUp::getStartSLURL(); + LL_DEBUGS("AppInit") << "start slurl "<<start_slurl.asString()<<LL_ENDL; + + if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || + ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || + ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) { - LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; + if (start_slurl.getType() == LLSLURL::LAST_LOCATION + && gAgentStartLocation == "last" + && gSavedSettings.getBOOL("RestoreCameraPosOnLogin")) + { + // restore old camera pos + gAgentCamera.setFocusOnAvatar(FALSE, FALSE); + gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null); + BOOL limit_hit = FALSE; + gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit); + if (limit_hit) + { + gAgentCamera.setFocusOnAvatar(TRUE, FALSE); + } + gAgentCamera.stopCameraAnimation(); + } + } + else + { + std::string msg; + switch(start_slurl.getType()) + { + case LLSLURL::LOCATION: + { + + msg = "AvatarMovedDesired"; + break; + } + case LLSLURL::HOME_LOCATION: + { + msg = "AvatarMovedHome"; + break; + } + default: + { + msg = "AvatarMovedLast"; + } + } + LLNotificationsUtil::add(msg); } } + display_startup(); - LLStartUp::setStartupState(STATE_INVENTORY_SEND2); + //DEV-17797. get null folder. Any items found here moved to Lost and Found + LLInventoryModelBackgroundFetch::instance().findLostItems(); display_startup(); + + LLStartUp::setStartupState( STATE_PRECACHE ); + timeout.reset(); return FALSE; } - if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState()) + if (STATE_PRECACHE == LLStartUp::getStartupState()) { - LL_PROFILE_ZONE_NAMED("State inventory send2") + display_startup(); + F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; + + // We now have an inventory skeleton, so if this is a user's first + // login, we can start setting up their clothing and avatar + // appearance. This helps to avoid the generic "Ruth" avatar in + // the orientation island tutorial experience. JC + if (gAgent.isFirstLogin() + && !sInitialOutfit.empty() // registration set up an outfit + && !sInitialOutfitGender.empty() // and a gender + && isAgentAvatarValid() // can't wear clothes without object + && !gAgent.isOutfitChosen()) // nothing already loading + { + // Start loading the wearables, textures, gestures + LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); + } + // If not first login, we need to fetch COF contents and + // compute appearance from that. + if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) + { + gAgentWearables.notifyLoadingStarted(); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); + callAfterCOFFetch(set_flags_and_update_appearance); + } - LLSD response = LLLoginInstance::getInstance()->getResponse(); - - LLSD inv_basic = response["inventory-basic"]; - if(inv_basic.isDefined()) - { - LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; - } - - LLSD buddy_list = response["buddy-list"]; - if(buddy_list.isDefined()) - { - LLAvatarTracker::buddy_map_t list; - LLUUID agent_id; - S32 has_rights = 0, given_rights = 0; - for(LLSD::array_const_iterator it = buddy_list.beginArray(), - end = buddy_list.endArray(); it != end; ++it) - { - LLSD buddy_id = (*it)["buddy_id"]; - if(buddy_id.isDefined()) - { - agent_id = buddy_id.asUUID(); - } - - LLSD buddy_rights_has = (*it)["buddy_rights_has"]; - if(buddy_rights_has.isDefined()) - { - has_rights = buddy_rights_has.asInteger(); - } - - LLSD buddy_rights_given = (*it)["buddy_rights_given"]; - if(buddy_rights_given.isDefined()) - { - given_rights = buddy_rights_given.asInteger(); - } - - list[agent_id] = new LLRelationship(given_rights, has_rights, false); - } - LLAvatarTracker::instance().addBuddyList(list); - display_startup(); - } - - bool show_hud = false; - LLSD tutorial_setting = response["tutorial_setting"]; - if(tutorial_setting.isDefined()) - { - for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), - end = tutorial_setting.endArray(); it != end; ++it) - { - LLSD tutorial_url = (*it)["tutorial_url"]; - if(tutorial_url.isDefined()) - { - // Tutorial floater will append language code - gSavedSettings.setString("TutorialURL", tutorial_url.asString()); - } - - // For Viewer 2.0 we are not using the web-based tutorial - // If we reverse that decision, put this code back and use - // login.cgi to send a different URL with content that matches - // the Viewer 2.0 UI. - //LLSD use_tutorial = (*it)["use_tutorial"]; - //if(use_tutorial.asString() == "true") - //{ - // show_hud = true; - //} - } - } - display_startup(); - - // Either we want to show tutorial because this is the first login - // to a Linden Help Island or the user quit with the tutorial - // visible. JC - if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) - { - LLFloaterReg::showInstance("hud", LLSD(), FALSE); - } - display_startup(); - - LLSD event_notifications = response["event_notifications"]; - if(event_notifications.isDefined()) - { - gEventNotifier.load(event_notifications); - } - display_startup(); - - LLSD classified_categories = response["classified_categories"]; - if(classified_categories.isDefined()) - { - LLClassifiedInfo::loadCategories(classified_categories); - } - display_startup(); - - // This method MUST be called before gInventory.findCategoryUUIDForType because of - // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. - gInventory.buildParentChildMap(); - - // If buildParentChildMap succeeded, inventory will now be in - // a usable state and gInventory.isInventoryUsable() will be - // true. - - // if inventory is unusable, show warning. - if (!gInventory.isInventoryUsable()) - { - LLNotificationsUtil::add("InventoryUnusable"); - } - - LLInventoryModelBackgroundFetch::instance().start(); - gInventory.createCommonSystemCategories(); - LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); display_startup(); - return FALSE; + // wait precache-delay and for agent's avatar or a lot longer. + if ((timeout_frac > 1.f) && isAgentAvatarValid()) + { + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else if (timeout_frac > 10.f) + { + // If we exceed the wait above while isAgentAvatarValid is + // not true yet, we will change startup state and + // eventually (once avatar does get created) wind up at + // the gender chooser. This should occur only in very + // unusual circumstances, so set the timeout fairly high + // to minimize mistaken hits here. + LL_WARNS() << "Wait for valid avatar state exceeded " + << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else + { + update_texture_fetch(); + set_startup_status(0.60f + 0.30f * timeout_frac, + LLTrans::getString("LoginPrecaching"), + gAgent.mMOTD.c_str()); + display_startup(); + } + + return TRUE; } - //--------------------------------------------------------------------- - // STATE_INVENTORY_CALLBACKS - //--------------------------------------------------------------------- - if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) + if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) { - if (!LLInventoryModel::isSysFoldersReady()) + static LLFrameTimer wearables_timer; + + const F32 wearables_time = wearables_timer.getElapsedTimeF32(); + static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); + + if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { - display_startup(); - return FALSE; + // No point in waiting for clothing, we don't even know + // what outfit we want. Pop up a gender chooser dialog to + // ask and proceed to draw the world. JC + // + // *NOTE: We might hit this case even if we have an + // initial outfit, but if the load hasn't started + // already then something is wrong so fall back + // to generic outfits. JC + LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), + callback_choose_gender); + LLStartUp::setStartupState( STATE_CLEANUP ); } - LLInventoryModelBackgroundFetch::instance().start(); - LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); - if (cof - && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + + display_startup(); + + if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) { - // Special case, dupplicate request prevention. - // Cof folder will be requested via FetchCOF - // in appearance manager, prevent recursive fetch - cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); + if (gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("ClothingLoading"); + } + record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); + LLStartUp::setStartupState( STATE_CLEANUP ); + } + else if (gAgent.isFirstLogin() + && isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + // wait for avatar to be completely loaded + if (isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + } + else + { + // OK to just get the wearables + if ( gAgentWearables.areWearablesLoaded() ) + { + // We have our clothing, proceed. + LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } + //fall through this frame to STATE_CLEANUP + } + if (STATE_CLEANUP == LLStartUp::getStartupState()) + { + set_startup_status(1.0, "", ""); + display_startup(); - // It's debatable whether this flag is a good idea - sets all - // bits, and in general it isn't true that inventory - // initialization generates all types of changes. Maybe add an - // INITIALIZE mask bit instead? - gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); - gInventory.notifyObservers(); - - display_startup(); - - // set up callbacks - LL_INFOS() << "Registering Callbacks" << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - LL_INFOS() << " Inventory" << LL_ENDL; - LLInventoryModel::registerCallbacks(msg); - LL_INFOS() << " AvatarTracker" << LL_ENDL; - LLAvatarTracker::instance().registerCallbacks(msg); - LL_INFOS() << " Landmark" << LL_ENDL; - LLLandmark::registerCallbacks(msg); - display_startup(); - - // request all group information - LL_INFOS() << "Requesting Agent Data" << LL_ENDL; - gAgent.sendAgentDataUpdateRequest(); - display_startup(); - // Create the inventory views - LL_INFOS() << "Creating Inventory Views" << LL_ENDL; - LLFloaterReg::getInstance("inventory"); - display_startup(); - LLStartUp::setStartupState( STATE_MISC ); - display_startup(); - - return FALSE; - } - - - //--------------------------------------------------------------------- - // Misc - //--------------------------------------------------------------------- - if (STATE_MISC == LLStartUp::getStartupState()) - { - // We have a region, and just did a big inventory download. - // We can estimate the user's connection speed, and set their - // max bandwidth accordingly. JC - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) - { - // This is actually a pessimistic computation, because TCP may not have enough - // time to ramp up on the (small) default inventory file to truly measure max - // bandwidth. JC - F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); - const F32 FAST_RATE_BPS = 600.f * 1024.f; - const F32 FASTER_RATE_BPS = 750.f * 1024.f; - F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); - if (rate_bps > FASTER_RATE_BPS - && rate_bps > max_bandwidth) - { - LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " - << FASTER_RATE_BPS/1024.f - << " kbps" << LL_ENDL; - gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); - } - else if (rate_bps > FAST_RATE_BPS - && rate_bps > max_bandwidth) - { - LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " - << FAST_RATE_BPS/1024.f - << " kbps" << LL_ENDL; - gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); - } - - if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) - { - gSavedSettings.setBOOL("HelpFloaterOpen", TRUE); - } - - // Set the show start location to true, now that the user has logged - // on with this install. - gSavedSettings.setBOOL("ShowStartLocation", TRUE); - } - - display_startup(); + if (!mBenefitsSuccessfullyInit) + { + LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); + } - // Load stored local environment if needed. - LLEnvironment::instance().loadFromSettings(); + // Let the map know about the inventory. + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if(floater_world_map) + { + floater_world_map->observeInventory(&gInventory); + floater_world_map->observeFriends(); + } + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->resetBusyCount(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; + //gViewerWindow->revealIntroPanel(); + gViewerWindow->setStartupComplete(); + gViewerWindow->setProgressCancelButtonVisible(FALSE); + display_startup(); - // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) - //check_merchant_status(); + // We're not away from keyboard, even though login might have taken + // a while. JC + gAgent.clearAFK(); - display_startup(); - - if (gSavedSettings.getBOOL("HelpFloaterOpen")) - { - // show default topic - LLViewerHelp::instance().showTopic(""); - } - - display_startup(); - - // We're successfully logged in. - gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); - - LLFloaterReg::showInitialVisibleInstances(); - - LLFloaterGridStatus::getInstance()->startGridStatusTimer(); - - display_startup(); - - display_startup(); - // JC: Initializing audio requests many sounds for download. - init_audio(); - display_startup(); - - // JC: Initialize "active" gestures. This may also trigger - // many gesture downloads, if this is the user's first - // time on this machine or -purge has been run. - LLSD gesture_options - = LLLoginInstance::getInstance()->getResponse("gestures"); - if (gesture_options.isDefined()) - { - LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() - << LL_ENDL; - uuid_vec_t item_ids; - for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), - end = gesture_options.endArray(); resp_it != end; ++resp_it) - { - // If the id is not specifed in the LLSD, - // the LLSD operator[]() will return a null LLUUID. - LLUUID item_id = (*resp_it)["item_id"]; - LLUUID asset_id = (*resp_it)["asset_id"]; - - if (item_id.notNull() && asset_id.notNull()) - { - // Could schedule and delay these for later. - const BOOL no_inform_server = FALSE; - const BOOL no_deactivate_similar = FALSE; - LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, - no_inform_server, - no_deactivate_similar); - // We need to fetch the inventory items for these gestures - // so we have the names to populate the UI. - item_ids.push_back(item_id); - } - } - // no need to add gesture to inventory observer, it's already made in constructor - LLGestureMgr::instance().setFetchIDs(item_ids); - LLGestureMgr::instance().startFetch(); - } - gDisplaySwapBuffers = TRUE; - display_startup(); - - LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); - msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); - msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); - msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); - - LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; - - LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; - gRenderStartTime.reset(); - gForegroundTime.reset(); - - // HACK: Inform simulator of window size. - // Do this here so it's less likely to race with RegisterNewAgent. - // TODO: Put this into RegisterNewAgent - // JC - 7/20/2002 - gViewerWindow->sendShapeToSim(); - - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); - - // The reason we show the alert is because we want to - // reduce confusion for when you log in and your provided - // location is not your expected location. So, if this is - // your first login, then you do not have an expectation, - // thus, do not show this alert. - if (!gAgent.isFirstLogin()) - { - LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; - LLSLURL start_slurl = LLStartUp::getStartSLURL(); - LL_DEBUGS("AppInit") << "start slurl "<<start_slurl.asString()<<LL_ENDL; - - if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || - ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || - ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) - { - if (start_slurl.getType() == LLSLURL::LAST_LOCATION - && gAgentStartLocation == "last" - && gSavedSettings.getBOOL("RestoreCameraPosOnLogin")) - { - // restore old camera pos - gAgentCamera.setFocusOnAvatar(FALSE, FALSE); - gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null); - BOOL limit_hit = FALSE; - gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit); - if (limit_hit) - { - gAgentCamera.setFocusOnAvatar(TRUE, FALSE); - } - gAgentCamera.stopCameraAnimation(); - } - } - else - { - std::string msg; - switch(start_slurl.getType()) - { - case LLSLURL::LOCATION: - { - - msg = "AvatarMovedDesired"; - break; - } - case LLSLURL::HOME_LOCATION: - { - msg = "AvatarMovedHome"; - break; - } - default: - { - msg = "AvatarMovedLast"; - } - } - LLNotificationsUtil::add(msg); - } - } - - display_startup(); - //DEV-17797. get null folder. Any items found here moved to Lost and Found - LLInventoryModelBackgroundFetch::instance().findLostItems(); - display_startup(); - - LLStartUp::setStartupState( STATE_PRECACHE ); - timeout.reset(); - return FALSE; - } - - if (STATE_PRECACHE == LLStartUp::getStartupState()) - { - display_startup(); - F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; - - // We now have an inventory skeleton, so if this is a user's first - // login, we can start setting up their clothing and avatar - // appearance. This helps to avoid the generic "Ruth" avatar in - // the orientation island tutorial experience. JC - if (gAgent.isFirstLogin() - && !sInitialOutfit.empty() // registration set up an outfit - && !sInitialOutfitGender.empty() // and a gender - && isAgentAvatarValid() // can't wear clothes without object - && !gAgent.isOutfitChosen()) // nothing already loading - { - // Start loading the wearables, textures, gestures - LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); - } - // If not first login, we need to fetch COF contents and - // compute appearance from that. - if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) - { - gAgentWearables.notifyLoadingStarted(); - gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); - callAfterCOFFetch(set_flags_and_update_appearance); - } - - display_startup(); - - // wait precache-delay and for agent's avatar or a lot longer. - if ((timeout_frac > 1.f) && isAgentAvatarValid()) - { - LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); - } - else if (timeout_frac > 10.f) - { - // If we exceed the wait above while isAgentAvatarValid is - // not true yet, we will change startup state and - // eventually (once avatar does get created) wind up at - // the gender chooser. This should occur only in very - // unusual circumstances, so set the timeout fairly high - // to minimize mistaken hits here. - LL_WARNS() << "Wait for valid avatar state exceeded " - << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; - LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); - } - else - { - update_texture_fetch(); - set_startup_status(0.60f + 0.30f * timeout_frac, - LLTrans::getString("LoginPrecaching"), - gAgent.mMOTD.c_str()); - display_startup(); - } - - return TRUE; - } - - if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) - { - static LLFrameTimer wearables_timer; - - const F32 wearables_time = wearables_timer.getElapsedTimeF32(); - static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); - - if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) - { - // No point in waiting for clothing, we don't even know - // what outfit we want. Pop up a gender chooser dialog to - // ask and proceed to draw the world. JC - // - // *NOTE: We might hit this case even if we have an - // initial outfit, but if the load hasn't started - // already then something is wrong so fall back - // to generic outfits. JC - LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), - callback_choose_gender); - LLStartUp::setStartupState( STATE_CLEANUP ); - } - - display_startup(); - - if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) - { - if (gInventory.isInventoryUsable()) - { - LLNotificationsUtil::add("ClothingLoading"); - } - record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); - LLStartUp::setStartupState( STATE_CLEANUP ); - } - else if (gAgent.isFirstLogin() - && isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - // wait for avatar to be completely loaded - if (isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } - } - else - { - // OK to just get the wearables - if ( gAgentWearables.areWearablesLoaded() ) - { - // We have our clothing, proceed. - LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } - } - //fall through this frame to STATE_CLEANUP - } - - if (STATE_CLEANUP == LLStartUp::getStartupState()) - { - set_startup_status(1.0, "", ""); - display_startup(); - - if (!mBenefitsSuccessfullyInit) - { - LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); - } - - // Let the map know about the inventory. - LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); - if(floater_world_map) - { - floater_world_map->observeInventory(&gInventory); - floater_world_map->observeFriends(); - } - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->resetBusyCount(); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; - //gViewerWindow->revealIntroPanel(); - gViewerWindow->setStartupComplete(); - gViewerWindow->setProgressCancelButtonVisible(FALSE); - display_startup(); - - // We're not away from keyboard, even though login might have taken - // a while. JC - gAgent.clearAFK(); - - // Have the agent start watching the friends list so we can update proxies - gAgent.observeFriends(); - - // Start automatic replay if the flag is set. - if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) - { - LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; - gAgentPilot.startPlayback(); - } - - show_debug_menus(); // Debug menu visiblity and First Use trigger - - // If we've got a startup URL, dispatch it - //LLStartUp::dispatchURL(); - - // Retrieve information about the land data - // (just accessing this the first time will fetch it, - // then the data is cached for the viewer's lifetime) - LLProductInfoRequestManager::instance(); - - // *FIX:Mani - What do I do here? - // Need we really clear the Auth response data? - // Clean up the userauth stuff. - // LLUserAuth::getInstance()->reset(); - - LLStartUp::setStartupState( STATE_STARTED ); - display_startup(); - - // Unmute audio if desired and setup volumes. - // This is a not-uncommon crash site, so surround it with - // LL_INFOS() output to aid diagnosis. - LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; - audio_update_volume(); - LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; - - // reset keyboard focus to sane state of pointing at world - gFocusMgr.setKeyboardFocus(NULL); - - LLAppViewer::instance()->handleLoginComplete(); - - LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); - - display_startup(); - - llassert(LLPathfindingManager::getInstance() != NULL); - LLPathfindingManager::getInstance()->initSystem(); - - gAgentAvatarp->sendHoverHeight(); - - // look for parcels we own - send_places_query(LLUUID::null, - LLUUID::null, - "", - DFQ_AGENT_OWNED, - LLParcel::C_ANY, - ""); - - LLUIUsage::instance().clear(); + // Have the agent start watching the friends list so we can update proxies + gAgent.observeFriends(); + + // Start automatic replay if the flag is set. + if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) + { + LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; + gAgentPilot.startPlayback(); + } + + show_debug_menus(); // Debug menu visiblity and First Use trigger + + // If we've got a startup URL, dispatch it + //LLStartUp::dispatchURL(); + + // Retrieve information about the land data + // (just accessing this the first time will fetch it, + // then the data is cached for the viewer's lifetime) + LLProductInfoRequestManager::instance(); + + // *FIX:Mani - What do I do here? + // Need we really clear the Auth response data? + // Clean up the userauth stuff. + // LLUserAuth::getInstance()->reset(); + + LLStartUp::setStartupState( STATE_STARTED ); + display_startup(); + + // Unmute audio if desired and setup volumes. + // This is a not-uncommon crash site, so surround it with + // LL_INFOS() output to aid diagnosis. + LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; + audio_update_volume(); + LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; + + // reset keyboard focus to sane state of pointing at world + gFocusMgr.setKeyboardFocus(NULL); + + LLAppViewer::instance()->handleLoginComplete(); + + LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); + + display_startup(); + + llassert(LLPathfindingManager::getInstance() != NULL); + LLPathfindingManager::getInstance()->initSystem(); + + gAgentAvatarp->sendHoverHeight(); + + // look for parcels we own + send_places_query(LLUUID::null, + LLUUID::null, + "", + DFQ_AGENT_OWNED, + LLParcel::C_ANY, + ""); + + LLUIUsage::instance().clear(); LLPerfStats::StatsRecorder::setAutotuneInit(); LLLUAmanager::runScriptOnLogin(); - return TRUE; - } + return TRUE; + } - return TRUE; + return TRUE; } // @@ -2434,50 +2434,50 @@ bool idle_startup() void login_show() { - LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; - - // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region - if (gToolBarView) - { - gToolBarView->setVisible(FALSE); - } - - LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); + LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; + + // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region + if (gToolBarView) + { + gToolBarView->setVisible(FALSE); + } + + LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); } // Callback for when login screen is closed. Option 0 = connect, option 1 = quit. void login_callback(S32 option, void *userdata) { - const S32 CONNECT_OPTION = 0; - const S32 QUIT_OPTION = 1; - - if (CONNECT_OPTION == option) - { - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - return; - } - else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION - { - if (!gSavedSettings.getBOOL("RememberPassword")) - { - // turn off the setting and write out to disk - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); - LLUIColorTable::instance().saveUserSettings(); - } - - // Next iteration through main loop should shut down the app cleanly. - LLAppViewer::instance()->userQuit(); - - if (LLAppViewer::instance()->quitRequested()) - { - LLPanelLogin::closePanel(); - } - return; - } - else - { - LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; - } + const S32 CONNECT_OPTION = 0; + const S32 QUIT_OPTION = 1; + + if (CONNECT_OPTION == option) + { + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + return; + } + else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION + { + if (!gSavedSettings.getBOOL("RememberPassword")) + { + // turn off the setting and write out to disk + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); + } + + // Next iteration through main loop should shut down the app cleanly. + LLAppViewer::instance()->userQuit(); + + if (LLAppViewer::instance()->quitRequested()) + { + LLPanelLogin::closePanel(); + } + return; + } + else + { + LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; + } } void release_notes_coro(const std::string url) @@ -2559,35 +2559,35 @@ void show_release_notes_if_required() void show_first_run_dialog() { - LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); + LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); } bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; - LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); - } - - LLPanelLogin::giveFocus(); - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; + LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); + } + + LLPanelLogin::giveFocus(); + return false; } void set_startup_status(const F32 frac, const std::string& string, const std::string& msg) { - gViewerWindow->setProgressPercent(frac*100); - gViewerWindow->setProgressString(string); + gViewerWindow->setProgressPercent(frac*100); + gViewerWindow->setProgressString(string); - gViewerWindow->setProgressMessage(msg); + gViewerWindow->setProgressMessage(msg); } bool login_alert_status(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // Buttons switch( option ) { @@ -2598,222 +2598,222 @@ bool login_alert_status(const LLSD& notification, const LLSD& response) // break; case 2: // Teleport // Restart the login process, starting at our home locaton - LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; default: LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL; } - LLPanelLogin::giveFocus(); - return false; + LLPanelLogin::giveFocus(); + return false; } void use_circuit_callback(void**, S32 result) { - // bail if we're quitting. - if(LLApp::isExiting()) return; - if( !gUseCircuitCallbackCalled ) - { - gUseCircuitCallbackCalled = true; - if (result) - { - // Make sure user knows something bad happened. JC - LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); - } - else - { - gGotUseCircuitCodeAck = true; - } - } + // bail if we're quitting. + if(LLApp::isExiting()) return; + if( !gUseCircuitCallbackCalled ) + { + gUseCircuitCallbackCalled = true; + if (result) + { + // Make sure user knows something bad happened. JC + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else + { + gGotUseCircuitCodeAck = true; + } + } } void register_viewer_callbacks(LLMessageSystem* msg) { - msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); - msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); - msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); - msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); - msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); - msg->setHandlerFunc("SimStats", process_sim_stats); - msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); - msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); - msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); - - msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); - msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); - msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); - msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); - msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); - msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); - - msg->setHandlerFunc("CrossedRegion", process_crossed_region); - msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); - - msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); - msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); - msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); - msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); - - msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); - msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); - msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); - msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); - msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); - msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); - msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); - msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); - msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); - - msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); - msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); - msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); - msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); - msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); - - msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); - msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); - msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); - msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); - msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, - &LLLiveLSLEditor::processScriptRunningReply); - - msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); - - msg->setHandlerFunc("LogoutReply", process_logout_reply); - - //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, - // &LLAgent::processAddModifyAbility); - //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, - // &LLAgent::processRemoveModifyAbility); - msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, - &LLAgent::processAgentDataUpdate); - msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, - &LLAgent::processAgentGroupDataUpdate); - msg->setHandlerFunc("AgentDropGroup", - &LLAgent::processAgentDropGroup); - // land ownership messages - msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, - LLViewerParcelMgr::processParcelOverlay); - msg->setHandlerFuncFast(_PREHASH_ParcelProperties, - LLViewerParcelMgr::processParcelProperties); - msg->setHandlerFunc("ParcelAccessListReply", - LLViewerParcelMgr::processParcelAccessListReply); - msg->setHandlerFunc("ParcelDwellReply", - LLViewerParcelMgr::processParcelDwellReply); - - msg->setHandlerFunc("AvatarPropertiesReply", - &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); - msg->setHandlerFunc("AvatarInterestsReply", - &LLAvatarPropertiesProcessor::processAvatarInterestsReply); - msg->setHandlerFunc("AvatarGroupsReply", - &LLAvatarPropertiesProcessor::processAvatarGroupsReply); - // ratings deprecated - //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, - // LLPanelAvatar::processAvatarStatisticsReply); - msg->setHandlerFunc("AvatarNotesReply", - &LLAvatarPropertiesProcessor::processAvatarNotesReply); - msg->setHandlerFunc("AvatarPicksReply", - &LLAvatarPropertiesProcessor::processAvatarPicksReply); - msg->setHandlerFunc("AvatarClassifiedReply", - &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); - - msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, - LLGroupMgr::processCreateGroupReply); - msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, - LLGroupMgr::processJoinGroupReply); - msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, - LLGroupMgr::processEjectGroupMemberReply); - msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, - LLGroupMgr::processLeaveGroupReply); - msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, - LLGroupMgr::processGroupPropertiesReply); - - // ratings deprecated - // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, - // LLFloaterRate::processReputationIndividualReply); - - msg->setHandlerFunc("ScriptControlChange", - LLAgent::processScriptControlChange ); - - msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); - - msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); - - msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, - LLPanelGroupLandMoney::processGroupAccountSummaryReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, - LLPanelGroupLandMoney::processGroupAccountDetailsReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, - LLPanelGroupLandMoney::processGroupAccountTransactionsReply); - - msg->setHandlerFuncFast(_PREHASH_UserInfoReply, - process_user_info_reply); - - msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); - - msg->setHandlerFunc("TeleportStart", process_teleport_start ); - msg->setHandlerFunc("TeleportProgress", process_teleport_progress); - msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); - msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); - - msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); - - msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, - LLGroupMgr::processGroupMembersReply); - msg->setHandlerFunc("GroupRoleDataReply", - LLGroupMgr::processGroupRoleDataReply); - msg->setHandlerFunc("GroupRoleMembersReply", - LLGroupMgr::processGroupRoleMembersReply); - msg->setHandlerFunc("GroupTitlesReply", - LLGroupMgr::processGroupTitlesReply); - // Special handler as this message is sometimes used for group land. - msg->setHandlerFunc("PlacesReply", process_places_reply); - msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); - - msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); - - msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); - msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); - msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); - - msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); - msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); - msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); - msg->setHandlerFunc("ScriptDialog", process_script_dialog); - msg->setHandlerFunc("LoadURL", process_load_url); - msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); - msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); - - // calling cards - msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); - msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); - msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); - - msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); - - msg->setHandlerFunc("InitiateDownload", process_initiate_download); - msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); + msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); + msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); + msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); + msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); + msg->setHandlerFunc("SimStats", process_sim_stats); + msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); + msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); + msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); + + msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); + msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); + msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); + msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); + msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); + msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); + + msg->setHandlerFunc("CrossedRegion", process_crossed_region); + msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); + + msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); + msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); + msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); + msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); + + msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); + msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); + msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); + msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); + msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); + msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); + msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); + msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); + + msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); + msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); + msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); + msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); + msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); + + msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); + msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); + msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); + msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); + msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, + &LLLiveLSLEditor::processScriptRunningReply); + + msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); + + msg->setHandlerFunc("LogoutReply", process_logout_reply); + + //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, + // &LLAgent::processAddModifyAbility); + //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, + // &LLAgent::processRemoveModifyAbility); + msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, + &LLAgent::processAgentDataUpdate); + msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, + &LLAgent::processAgentGroupDataUpdate); + msg->setHandlerFunc("AgentDropGroup", + &LLAgent::processAgentDropGroup); + // land ownership messages + msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, + LLViewerParcelMgr::processParcelOverlay); + msg->setHandlerFuncFast(_PREHASH_ParcelProperties, + LLViewerParcelMgr::processParcelProperties); + msg->setHandlerFunc("ParcelAccessListReply", + LLViewerParcelMgr::processParcelAccessListReply); + msg->setHandlerFunc("ParcelDwellReply", + LLViewerParcelMgr::processParcelDwellReply); + + msg->setHandlerFunc("AvatarPropertiesReply", + &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); + msg->setHandlerFunc("AvatarInterestsReply", + &LLAvatarPropertiesProcessor::processAvatarInterestsReply); + msg->setHandlerFunc("AvatarGroupsReply", + &LLAvatarPropertiesProcessor::processAvatarGroupsReply); + // ratings deprecated + //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, + // LLPanelAvatar::processAvatarStatisticsReply); + msg->setHandlerFunc("AvatarNotesReply", + &LLAvatarPropertiesProcessor::processAvatarNotesReply); + msg->setHandlerFunc("AvatarPicksReply", + &LLAvatarPropertiesProcessor::processAvatarPicksReply); + msg->setHandlerFunc("AvatarClassifiedReply", + &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); + + msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, + LLGroupMgr::processCreateGroupReply); + msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, + LLGroupMgr::processJoinGroupReply); + msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, + LLGroupMgr::processEjectGroupMemberReply); + msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, + LLGroupMgr::processLeaveGroupReply); + msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, + LLGroupMgr::processGroupPropertiesReply); + + // ratings deprecated + // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, + // LLFloaterRate::processReputationIndividualReply); + + msg->setHandlerFunc("ScriptControlChange", + LLAgent::processScriptControlChange ); + + msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); + + msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); + + msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, + LLPanelGroupLandMoney::processGroupAccountSummaryReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, + LLPanelGroupLandMoney::processGroupAccountDetailsReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, + LLPanelGroupLandMoney::processGroupAccountTransactionsReply); + + msg->setHandlerFuncFast(_PREHASH_UserInfoReply, + process_user_info_reply); + + msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); + + msg->setHandlerFunc("TeleportStart", process_teleport_start ); + msg->setHandlerFunc("TeleportProgress", process_teleport_progress); + msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); + msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); + + msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); + + msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, + LLGroupMgr::processGroupMembersReply); + msg->setHandlerFunc("GroupRoleDataReply", + LLGroupMgr::processGroupRoleDataReply); + msg->setHandlerFunc("GroupRoleMembersReply", + LLGroupMgr::processGroupRoleMembersReply); + msg->setHandlerFunc("GroupTitlesReply", + LLGroupMgr::processGroupTitlesReply); + // Special handler as this message is sometimes used for group land. + msg->setHandlerFunc("PlacesReply", process_places_reply); + msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); + + msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); + + msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); + msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); + msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); + + msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); + msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); + msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); + msg->setHandlerFunc("ScriptDialog", process_script_dialog); + msg->setHandlerFunc("LoadURL", process_load_url); + msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); + msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); + + // calling cards + msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); + msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); + msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); + + msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); + + msg->setHandlerFunc("InitiateDownload", process_initiate_download); + msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); msg->setHandlerFunc("GenericMessage", process_generic_message); msg->setHandlerFunc("GenericStreamingMessage", process_generic_streaming_message); msg->setHandlerFunc("LargeGenericMessage", process_large_generic_message); - msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); + msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32) { - // nothing + // nothing } const S32 OPT_CLOSED_WINDOW = -1; @@ -2821,27 +2821,27 @@ const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; const S32 OPT_TRUST_CERT = 0; const S32 OPT_CANCEL_TRUST = 1; - + bool callback_choose_gender(const LLSD& notification, const LLSD& response) { - - // These defaults are returned from the server on login. They are set in login.xml. - // If no default is returned from the server, they are retrieved from settings.xml. - - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case OPT_MALE: - LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); - break; - + + // These defaults are returned from the server on login. They are set in login.xml. + // If no default is returned from the server, they are retrieved from settings.xml. + + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_MALE: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); + break; + case OPT_FEMALE: case OPT_CLOSED_WINDOW: default: - LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); - break; - } - return false; + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); + break; + } + return false; } std::string get_screen_filename(const std::string& pattern) @@ -2873,66 +2873,66 @@ std::string LLStartUp::getScreenHomeFilename() //static void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, - const std::string& gender_name ) + const std::string& gender_name ) { - LL_DEBUGS() << "starting" << LL_ENDL; - - // Not going through the processAgentInitialWearables path, so need to set this here. - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - // Initiate creation of COF, since we're also bypassing that. - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); - - ESex gender; - if (gender_name == "male") - { - LL_DEBUGS() << "male" << LL_ENDL; - gender = SEX_MALE; - } - else - { - LL_DEBUGS() << "female" << LL_ENDL; - gender = SEX_FEMALE; - } - - if (!isAgentAvatarValid()) - { - LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; - return; - } - - gAgentAvatarp->setSex(gender); - - // try to find the requested outfit or folder - - // -- check for existing outfit in My Outfits - bool do_copy = false; - LLUUID cat_id = findDescendentCategoryIDByName( - gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), - outfit_folder_name); - - // -- check for existing folder in Library - if (cat_id.isNull()) - { - cat_id = findDescendentCategoryIDByName( - gInventory.getLibraryRootFolderID(), - outfit_folder_name); - if (!cat_id.isNull()) - { - do_copy = true; - } - } - - if (cat_id.isNull()) - { - // -- final fallback: create standard wearables - LL_DEBUGS() << "standard wearables" << LL_ENDL; - gAgentWearables.createStandardWearables(); - } - else - { - bool do_append = false; - LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); - // Need to fetch cof contents before we can wear. + LL_DEBUGS() << "starting" << LL_ENDL; + + // Not going through the processAgentInitialWearables path, so need to set this here. + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + // Initiate creation of COF, since we're also bypassing that. + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + + ESex gender; + if (gender_name == "male") + { + LL_DEBUGS() << "male" << LL_ENDL; + gender = SEX_MALE; + } + else + { + LL_DEBUGS() << "female" << LL_ENDL; + gender = SEX_FEMALE; + } + + if (!isAgentAvatarValid()) + { + LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; + return; + } + + gAgentAvatarp->setSex(gender); + + // try to find the requested outfit or folder + + // -- check for existing outfit in My Outfits + bool do_copy = false; + LLUUID cat_id = findDescendentCategoryIDByName( + gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), + outfit_folder_name); + + // -- check for existing folder in Library + if (cat_id.isNull()) + { + cat_id = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + if (!cat_id.isNull()) + { + do_copy = true; + } + } + + if (cat_id.isNull()) + { + // -- final fallback: create standard wearables + LL_DEBUGS() << "standard wearables" << LL_ENDL; + gAgentWearables.createStandardWearables(); + } + else + { + bool do_append = false; + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + // Need to fetch cof contents before we can wear. if (do_copy) { callAfterCOFFetch(boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); @@ -2941,16 +2941,16 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, { callAfterCategoryLinksFetch(cat_id, boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); } - LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; - } + LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; + } - gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); } std::string& LLStartUp::getInitialOutfitName() { - return sInitialOutfit; + return sInitialOutfit; } std::string LLStartUp::getUserId() @@ -2966,8 +2966,8 @@ std::string LLStartUp::getUserId() // frees the bitmap void release_start_screen() { - LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; - gStartTexture = NULL; + LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; + gStartTexture = NULL; } @@ -2975,77 +2975,77 @@ void release_start_screen() std::string LLStartUp::startupStateToString(EStartupState state) { #define RTNENUM(E) case E: return #E - switch(state){ - RTNENUM( STATE_FIRST ); - RTNENUM( STATE_BROWSER_INIT ); - RTNENUM( STATE_LOGIN_SHOW ); - RTNENUM( STATE_LOGIN_WAIT ); - RTNENUM( STATE_LOGIN_CLEANUP ); - RTNENUM( STATE_LOGIN_AUTH_INIT ); - RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); - RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); - RTNENUM( STATE_WORLD_INIT ); - RTNENUM( STATE_MULTIMEDIA_INIT ); - RTNENUM( STATE_FONT_INIT ); - RTNENUM( STATE_SEED_GRANTED_WAIT ); - RTNENUM( STATE_SEED_CAP_GRANTED ); - RTNENUM( STATE_WORLD_WAIT ); - RTNENUM( STATE_AGENT_SEND ); - RTNENUM( STATE_AGENT_WAIT ); - RTNENUM( STATE_INVENTORY_SEND ); + switch(state){ + RTNENUM( STATE_FIRST ); + RTNENUM( STATE_BROWSER_INIT ); + RTNENUM( STATE_LOGIN_SHOW ); + RTNENUM( STATE_LOGIN_WAIT ); + RTNENUM( STATE_LOGIN_CLEANUP ); + RTNENUM( STATE_LOGIN_AUTH_INIT ); + RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); + RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); + RTNENUM( STATE_WORLD_INIT ); + RTNENUM( STATE_MULTIMEDIA_INIT ); + RTNENUM( STATE_FONT_INIT ); + RTNENUM( STATE_SEED_GRANTED_WAIT ); + RTNENUM( STATE_SEED_CAP_GRANTED ); + RTNENUM( STATE_WORLD_WAIT ); + RTNENUM( STATE_AGENT_SEND ); + RTNENUM( STATE_AGENT_WAIT ); + RTNENUM( STATE_INVENTORY_SEND ); RTNENUM(STATE_INVENTORY_CALLBACKS ); - RTNENUM( STATE_MISC ); - RTNENUM( STATE_PRECACHE ); - RTNENUM( STATE_WEARABLES_WAIT ); - RTNENUM( STATE_CLEANUP ); - RTNENUM( STATE_STARTED ); - default: - return llformat("(state #%d)", state); - } + RTNENUM( STATE_MISC ); + RTNENUM( STATE_PRECACHE ); + RTNENUM( STATE_WEARABLES_WAIT ); + RTNENUM( STATE_CLEANUP ); + RTNENUM( STATE_STARTED ); + default: + return llformat("(state #%d)", state); + } #undef RTNENUM } // static void LLStartUp::setStartupState( EStartupState state ) { - LL_INFOS("AppInit") << "Startup state changing from " << - getStartupStateString() << " to " << - startupStateToString(state) << LL_ENDL; + LL_INFOS("AppInit") << "Startup state changing from " << + getStartupStateString() << " to " << + startupStateToString(state) << LL_ENDL; - getPhases().stopPhase(getStartupStateString()); - gStartupState = state; - getPhases().startPhase(getStartupStateString()); + getPhases().stopPhase(getStartupStateString()); + gStartupState = state; + getPhases().startPhase(getStartupStateString()); - postStartupState(); + postStartupState(); } void LLStartUp::postStartupState() { - LLSD stateInfo; - stateInfo["str"] = getStartupStateString(); - stateInfo["enum"] = gStartupState; - sStateWatcher->post(stateInfo); - gDebugInfo["StartupState"] = getStartupStateString(); + LLSD stateInfo; + stateInfo["str"] = getStartupStateString(); + stateInfo["enum"] = gStartupState; + sStateWatcher->post(stateInfo); + gDebugInfo["StartupState"] = getStartupStateString(); } void reset_login() { - gAgentWearables.cleanup(); - gAgentCamera.cleanup(); - gAgent.cleanup(); + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + gAgent.cleanup(); gSky.cleanup(); // mVOSkyp is an inworld object. - LLWorld::getInstance()->resetClass(); + LLWorld::getInstance()->resetClass(); - if ( gViewerWindow ) - { // Hide menus and normal buttons - gViewerWindow->setNormalControlsVisible( FALSE ); - gLoginMenuBarView->setVisible( TRUE ); - gLoginMenuBarView->setEnabled( TRUE ); - } + if ( gViewerWindow ) + { // Hide menus and normal buttons + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + } - // Hide any other stuff - LLFloaterReg::hideVisibleInstances(); + // Hide any other stuff + LLFloaterReg::hideVisibleInstances(); LLStartUp::setStartupState( STATE_BROWSER_INIT ); if (LLVoiceClient::instanceExists()) @@ -3065,117 +3065,117 @@ void reset_login() // early, before the login screen). JC void LLStartUp::multimediaInit() { - LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingMultimedia"); - set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); + LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingMultimedia"); + set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); } void LLStartUp::fontInit() { - LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingFonts"); - set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); + LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingFonts"); + set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); - LLFontGL::loadDefaultFonts(); + LLFontGL::loadDefaultFonts(); } void LLStartUp::initNameCache() { - // Can be called multiple times - if ( gCacheName ) return; - - gCacheName = new LLCacheName(gMessageSystem); - gCacheName->addObserver(&callback_cache_name); - gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); - gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); - gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); - // Load stored cache if possible - LLAppViewer::instance()->loadNameCache(); - - // Start cache in not-running state until we figure out if we have - // capabilities for display name lookup - LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); - cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); - cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); - cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + // Can be called multiple times + if ( gCacheName ) return; + + gCacheName = new LLCacheName(gMessageSystem); + gCacheName->addObserver(&callback_cache_name); + gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); + gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); + gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); + // Load stored cache if possible + LLAppViewer::instance()->loadNameCache(); + + // Start cache in not-running state until we figure out if we have + // capabilities for display name lookup + LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); + cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); + cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); + cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); } void LLStartUp::initExperiences() -{ +{ // Should trigger loading the cache. LLExperienceCache::instance().setCapabilityQuery( boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); - LLExperienceLog::instance().initialize(); + LLExperienceLog::instance().initialize(); } void LLStartUp::cleanupNameCache() { - delete gCacheName; - gCacheName = NULL; + delete gCacheName; + gCacheName = NULL; } bool LLStartUp::dispatchURL() { - // ok, if we've gotten this far and have a startup URL + // ok, if we've gotten this far and have a startup URL if (!getStartSLURL().isValid()) - { - return false; - } + { + return false; + } if(getStartSLURL().getType() != LLSLURL::APP) - { - - // If we started with a location, but we're already - // at that location, don't pop dialogs open. - LLVector3 pos = gAgent.getPositionAgent(); - LLVector3 slurlpos = getStartSLURL().getPosition(); - F32 dx = pos.mV[VX] - slurlpos.mV[VX]; - F32 dy = pos.mV[VY] - slurlpos.mV[VY]; - const F32 SLOP = 2.f; // meters - - if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() - || (dx*dx > SLOP*SLOP) - || (dy*dy > SLOP*SLOP) ) - { - LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, - NULL, false); - } - return true; - } - return false; + { + + // If we started with a location, but we're already + // at that location, don't pop dialogs open. + LLVector3 pos = gAgent.getPositionAgent(); + LLVector3 slurlpos = getStartSLURL().getPosition(); + F32 dx = pos.mV[VX] - slurlpos.mV[VX]; + F32 dy = pos.mV[VY] - slurlpos.mV[VY]; + const F32 SLOP = 2.f; // meters + + if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() + || (dx*dx > SLOP*SLOP) + || (dy*dy > SLOP*SLOP) ) + { + LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, + NULL, false); + } + return true; + } + return false; } -void LLStartUp::setStartSLURL(const LLSLURL& slurl) +void LLStartUp::setStartSLURL(const LLSLURL& slurl) { - LL_DEBUGS("AppInit")<<slurl.asString()<<LL_ENDL; - - if ( slurl.isSpatial() ) - { - std::string new_start = slurl.getSLURLString(); - LL_DEBUGS("AppInit")<<new_start<<LL_ENDL; - sStartSLURL = slurl; - LLPanelLogin::onUpdateStartSLURL(slurl); // updates grid if needed - - // remember that this is where we wanted to log in...if the login fails, - // the next attempt will default to the same place. - gSavedSettings.setString("NextLoginLocation", new_start); - // following a successful login, this is cleared - // and the default reverts to LoginLocation - } - else - { - LL_WARNS("AppInit")<<"Invalid start SLURL (ignored): "<<slurl.asString()<<LL_ENDL; - } + LL_DEBUGS("AppInit")<<slurl.asString()<<LL_ENDL; + + if ( slurl.isSpatial() ) + { + std::string new_start = slurl.getSLURLString(); + LL_DEBUGS("AppInit")<<new_start<<LL_ENDL; + sStartSLURL = slurl; + LLPanelLogin::onUpdateStartSLURL(slurl); // updates grid if needed + + // remember that this is where we wanted to log in...if the login fails, + // the next attempt will default to the same place. + gSavedSettings.setString("NextLoginLocation", new_start); + // following a successful login, this is cleared + // and the default reverts to LoginLocation + } + else + { + LL_WARNS("AppInit")<<"Invalid start SLURL (ignored): "<<slurl.asString()<<LL_ENDL; + } } // static LLSLURL& LLStartUp::getStartSLURL() { - return sStartSLURL; -} + return sStartSLURL; +} /** * Read all proxy configuration settings and set up both the HTTP proxy and @@ -3188,680 +3188,680 @@ LLSLURL& LLStartUp::getStartSLURL() */ bool LLStartUp::startLLProxy() { - bool proxy_ok = true; - std::string httpProxyType = gSavedSettings.getString("HttpProxyType"); - - // Set up SOCKS proxy (if needed) - if (gSavedSettings.getBOOL("Socks5ProxyEnabled")) - { - // Determine and update LLProxy with the saved authentication system - std::string auth_type = gSavedSettings.getString("Socks5AuthType"); - - if (auth_type.compare("UserPass") == 0) - { - LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); - std::string socks_user = socks_cred->getIdentifier()["username"].asString(); - std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); - - bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); - - if (!ok) - { - LLNotificationsUtil::add("SOCKS_BAD_CREDS"); - proxy_ok = false; - } - } - else if (auth_type.compare("None") == 0) - { - LLProxy::getInstance()->setAuthNone(); - } - else - { - LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; - - // Unknown or missing setting. - gSavedSettings.setString("Socks5AuthType", "None"); - - // Clear the SOCKS credentials. - LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5"); - gSecAPIHandler->deleteCredential(socks_cred); - - LLProxy::getInstance()->setAuthNone(); - } - - if (proxy_ok) - { - // Start the proxy and check for errors - // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. - LLHost socks_host; - socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); - socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); - int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); - - if (status != SOCKS_OK) - { - LLSD subs; - subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); - subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); - - std::string error_string; - - switch(status) - { - case SOCKS_CONNECT_ERROR: // TCP Fail - error_string = "SOCKS_CONNECT_ERROR"; - break; - - case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection - error_string = "SOCKS_NOT_PERMITTED"; - break; - - case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server - error_string = "SOCKS_NOT_ACCEPTABLE"; - break; - - case SOCKS_AUTH_FAIL: // Authentication failed - error_string = "SOCKS_AUTH_FAIL"; - break; - - case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed - error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; - break; - - case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server - error_string = "SOCKS_HOST_CONNECT_FAILED"; - break; - - case SOCKS_INVALID_HOST: // Improperly formatted host address or port. - error_string = "SOCKS_INVALID_HOST"; - break; - - default: - error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, - LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; - break; - } - - LLNotificationsUtil::add(error_string, subs); - proxy_ok = false; - } - } - } - else - { - LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up - } - - if (proxy_ok) - { - // Determine the HTTP proxy type (if any) - if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) - { - LLHost http_host; - http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); - http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); - if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) - { - LLSD subs; - subs["HOST"] = http_host.getIPString(); - subs["PORT"] = (S32)http_host.getPort(); - LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); - proxy_ok = false; - } - } - else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) - { - LLHost socks_host; - socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); - socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); - if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) - { - LLSD subs; - subs["HOST"] = socks_host.getIPString(); - subs["PORT"] = (S32)socks_host.getPort(); - LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); - proxy_ok = false; - } - } - else if (httpProxyType.compare("None") == 0) - { - LLProxy::getInstance()->disableHTTPProxy(); - } - else - { - LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; - - // Set the missing or wrong configuration back to something valid. - gSavedSettings.setString("HttpProxyType", "None"); - LLProxy::getInstance()->disableHTTPProxy(); - - // Leave proxy_ok alone, since this isn't necessarily fatal. - } - } - - return proxy_ok; + bool proxy_ok = true; + std::string httpProxyType = gSavedSettings.getString("HttpProxyType"); + + // Set up SOCKS proxy (if needed) + if (gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + // Determine and update LLProxy with the saved authentication system + std::string auth_type = gSavedSettings.getString("Socks5AuthType"); + + if (auth_type.compare("UserPass") == 0) + { + LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + std::string socks_user = socks_cred->getIdentifier()["username"].asString(); + std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); + + bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); + + if (!ok) + { + LLNotificationsUtil::add("SOCKS_BAD_CREDS"); + proxy_ok = false; + } + } + else if (auth_type.compare("None") == 0) + { + LLProxy::getInstance()->setAuthNone(); + } + else + { + LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; + + // Unknown or missing setting. + gSavedSettings.setString("Socks5AuthType", "None"); + + // Clear the SOCKS credentials. + LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + + LLProxy::getInstance()->setAuthNone(); + } + + if (proxy_ok) + { + // Start the proxy and check for errors + // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. + LLHost socks_host; + socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); + + if (status != SOCKS_OK) + { + LLSD subs; + subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); + subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); + + std::string error_string; + + switch(status) + { + case SOCKS_CONNECT_ERROR: // TCP Fail + error_string = "SOCKS_CONNECT_ERROR"; + break; + + case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection + error_string = "SOCKS_NOT_PERMITTED"; + break; + + case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server + error_string = "SOCKS_NOT_ACCEPTABLE"; + break; + + case SOCKS_AUTH_FAIL: // Authentication failed + error_string = "SOCKS_AUTH_FAIL"; + break; + + case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed + error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; + break; + + case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server + error_string = "SOCKS_HOST_CONNECT_FAILED"; + break; + + case SOCKS_INVALID_HOST: // Improperly formatted host address or port. + error_string = "SOCKS_INVALID_HOST"; + break; + + default: + error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, + LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; + break; + } + + LLNotificationsUtil::add(error_string, subs); + proxy_ok = false; + } + } + } + else + { + LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up + } + + if (proxy_ok) + { + // Determine the HTTP proxy type (if any) + if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) + { + LLHost http_host; + http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); + http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); + if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) + { + LLSD subs; + subs["HOST"] = http_host.getIPString(); + subs["PORT"] = (S32)http_host.getPort(); + LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); + proxy_ok = false; + } + } + else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + LLHost socks_host; + socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) + { + LLSD subs; + subs["HOST"] = socks_host.getIPString(); + subs["PORT"] = (S32)socks_host.getPort(); + LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); + proxy_ok = false; + } + } + else if (httpProxyType.compare("None") == 0) + { + LLProxy::getInstance()->disableHTTPProxy(); + } + else + { + LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; + + // Set the missing or wrong configuration back to something valid. + gSavedSettings.setString("HttpProxyType", "None"); + LLProxy::getInstance()->disableHTTPProxy(); + + // Leave proxy_ok alone, since this isn't necessarily fatal. + } + } + + return proxy_ok; } bool login_alert_done(const LLSD& notification, const LLSD& response) { - LLPanelLogin::giveFocus(); - return false; + LLPanelLogin::giveFocus(); + return false; } -// parse the certificate information into args for the +// parse the certificate information into args for the // certificate notifications LLSD transform_cert_args(LLPointer<LLCertificate> cert) { - LLSD args = LLSD::emptyMap(); - std::string value; - LLSD cert_info; - cert->getLLSD(cert_info); - // convert all of the elements in the cert into - // args for the xml dialog, so we have flexability to - // display various parts of the cert by only modifying - // the cert alert dialog xml. - for(LLSD::map_iterator iter = cert_info.beginMap(); - iter != cert_info.endMap(); - iter++) - { - // key usage and extended key usage - // are actually arrays, and we want to format them as comma separated - // strings, so special case those. - LLSDSerialize::toXML(cert_info[iter->first], std::cout); - if((iter->first == std::string(CERT_KEY_USAGE)) || - (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) - { - value = ""; - LLSD usage = cert_info[iter->first]; - for (LLSD::array_iterator usage_iter = usage.beginArray(); - usage_iter != usage.endArray(); - usage_iter++) - { - - if(usage_iter != usage.beginArray()) - { - value += ", "; - } - - value += (*usage_iter).asString(); - } - - } - else - { - value = iter->second.asString(); - } - - std::string name = iter->first; - std::transform(name.begin(), name.end(), name.begin(), - (int(*)(int))toupper); - args[name.c_str()] = value; - } - return args; + LLSD args = LLSD::emptyMap(); + std::string value; + LLSD cert_info; + cert->getLLSD(cert_info); + // convert all of the elements in the cert into + // args for the xml dialog, so we have flexability to + // display various parts of the cert by only modifying + // the cert alert dialog xml. + for(LLSD::map_iterator iter = cert_info.beginMap(); + iter != cert_info.endMap(); + iter++) + { + // key usage and extended key usage + // are actually arrays, and we want to format them as comma separated + // strings, so special case those. + LLSDSerialize::toXML(cert_info[iter->first], std::cout); + if((iter->first == std::string(CERT_KEY_USAGE)) || + (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) + { + value = ""; + LLSD usage = cert_info[iter->first]; + for (LLSD::array_iterator usage_iter = usage.beginArray(); + usage_iter != usage.endArray(); + usage_iter++) + { + + if(usage_iter != usage.beginArray()) + { + value += ", "; + } + + value += (*usage_iter).asString(); + } + + } + else + { + value = iter->second.asString(); + } + + std::string name = iter->first; + std::transform(name.begin(), name.end(), name.begin(), + (int(*)(int))toupper); + args[name.c_str()] = value; + } + return args; } // when we handle a cert error, give focus back to the login panel void general_cert_done(const LLSD& notification, const LLSD& response) { - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - LLPanelLogin::giveFocus(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + LLPanelLogin::giveFocus(); } // check to see if the user wants to trust the cert. -// if they do, add it to the cert store and +// if they do, add it to the cert store and void trust_cert_done(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case OPT_TRUST_CERT: - { - LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); - LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); - store->add(cert); - store->save(); - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - break; - } - case OPT_CANCEL_TRUST: - reset_login(); - gSavedSettings.setBOOL("AutoLogin", FALSE); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - default: - LLPanelLogin::giveFocus(); - break; - } + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_TRUST_CERT: + { + LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); + LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); + store->add(cert); + store->save(); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + break; + } + case OPT_CANCEL_TRUST: + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + default: + LLPanelLogin::giveFocus(); + break; + } } void apply_udp_blacklist(const std::string& csv) { - std::string::size_type start = 0; - std::string::size_type comma = 0; - do - { - comma = csv.find(",", start); - if (comma == std::string::npos) - { - comma = csv.length(); - } - std::string item(csv, start, comma-start); - - LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; - gMessageSystem->banUdpMessage(item); - - start = comma + 1; - - } - while(comma < csv.length()); - + std::string::size_type start = 0; + std::string::size_type comma = 0; + do + { + comma = csv.find(",", start); + if (comma == std::string::npos) + { + comma = csv.length(); + } + std::string item(csv, start, comma-start); + + LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; + gMessageSystem->banUdpMessage(item); + + start = comma + 1; + + } + while(comma < csv.length()); + } void on_benefits_failed_callback(const LLSD& notification, const LLSD& response) { - LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; + LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; } bool init_benefits(LLSD& response) { - bool succ = true; - - std::string package_name = response["account_type"].asString(); - const LLSD& benefits_sd = response["account_level_benefits"]; - if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || - !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) - { - succ = false; - } - else - { - LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; - } - const LLSD& packages_sd = response["premium_packages"]; - for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); - package_iter != packages_sd.endMap(); - ++package_iter) - { - std::string package_name = package_iter->first; - const LLSD& benefits_sd = package_iter->second["benefits"]; - if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) - { - LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; - } - else - { - LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; - succ = false; - } - } - - if (!LLAgentBenefitsMgr::has("Base")) - { - LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; - succ = false; - } - if (!LLAgentBenefitsMgr::has("Premium")) - { - LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; - succ = false; - } - - return succ; + bool succ = true; + + std::string package_name = response["account_type"].asString(); + const LLSD& benefits_sd = response["account_level_benefits"]; + if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || + !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) + { + succ = false; + } + else + { + LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; + } + const LLSD& packages_sd = response["premium_packages"]; + for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); + package_iter != packages_sd.endMap(); + ++package_iter) + { + std::string package_name = package_iter->first; + const LLSD& benefits_sd = package_iter->second["benefits"]; + if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) + { + LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; + } + else + { + LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; + succ = false; + } + } + + if (!LLAgentBenefitsMgr::has("Base")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; + succ = false; + } + if (!LLAgentBenefitsMgr::has("Premium")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; + succ = false; + } + + return succ; } bool process_login_success_response() { - LLSD response = LLLoginInstance::getInstance()->getResponse(); - - mBenefitsSuccessfullyInit = init_benefits(response); - - std::string text(response["udp_blacklist"]); - if(!text.empty()) - { - apply_udp_blacklist(text); - } - - // unpack login data needed by the application - text = response["agent_id"].asString(); - if(!text.empty()) gAgentID.set(text); - gDebugInfo["AgentID"] = text; - - LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); - LLPerfStats::StatsRecorder::setFocusAv(gAgentID); - - // Agent id needed for parcel info request in LLUrlEntryParcel - // to resolve parcel name. - LLUrlEntryParcel::setAgentID(gAgentID); - - text = response["session_id"].asString(); - if(!text.empty()) gAgentSessionID.set(text); - gDebugInfo["SessionID"] = text; - - // Session id needed for parcel info request in LLUrlEntryParcel - // to resolve parcel name. - LLUrlEntryParcel::setSessionID(gAgentSessionID); - - text = response["secure_session_id"].asString(); - if(!text.empty()) gAgent.mSecureSessionID.set(text); - - // if the response contains a display name, use that, - // otherwise if the response contains a first and/or last name, - // use those. Otherwise use the credential identifier - - gDisplayName = ""; - if (response.has("display_name")) - { - gDisplayName.assign(response["display_name"].asString()); - if(!gDisplayName.empty()) - { - // Remove quotes from string. Login.cgi sends these to force - // names that look like numbers into strings. - LLStringUtil::replaceChar(gDisplayName, '"', ' '); - LLStringUtil::trim(gDisplayName); - } - } - std::string first_name; - if(response.has("first_name")) - { - first_name = response["first_name"].asString(); - LLStringUtil::replaceChar(first_name, '"', ' '); - LLStringUtil::trim(first_name); - gAgentUsername = first_name; - } - - if(response.has("last_name") && !gAgentUsername.empty()) - { - std::string last_name = response["last_name"].asString(); - if (last_name != "Resident") - { - LLStringUtil::replaceChar(last_name, '"', ' '); - LLStringUtil::trim(last_name); - gAgentUsername = gAgentUsername + " " + last_name; - } - } - - if(gDisplayName.empty()) - { - if(response.has("first_name")) - { - gDisplayName.assign(response["first_name"].asString()); - LLStringUtil::replaceChar(gDisplayName, '"', ' '); - LLStringUtil::trim(gDisplayName); - } - if(response.has("last_name")) - { - text.assign(response["last_name"].asString()); - LLStringUtil::replaceChar(text, '"', ' '); - LLStringUtil::trim(text); - if(!gDisplayName.empty()) - { - gDisplayName += " "; - } - gDisplayName += text; - } - } - - if(gDisplayName.empty()) - { - gDisplayName.assign(gUserCredential->asString()); - } - - // this is their actual ability to access content - text = response["agent_access_max"].asString(); - if (!text.empty()) - { - // agent_access can be 'A', 'M', and 'PG'. - gAgent.setMaturity(text[0]); - } - - // this is the value of their preference setting for that content - // which will always be <= agent_access_max - text = response["agent_region_access"].asString(); - if (!text.empty()) - { - U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); - - gSavedSettings.setU32("PreferredMaturity", preferredMaturity); - } - - text = response["start_location"].asString(); - if(!text.empty()) - { - gAgentStartLocation.assign(text); - } - - text = response["circuit_code"].asString(); - if(!text.empty()) - { - gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); - } - std::string sim_ip_str = response["sim_ip"]; - std::string sim_port_str = response["sim_port"]; - if(!sim_ip_str.empty() && !sim_port_str.empty()) - { - U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); - gFirstSim.set(sim_ip_str, sim_port); - if (gFirstSim.isOk()) - { - gMessageSystem->enableCircuit(gFirstSim, TRUE); - } - } - std::string region_x_str = response["region_x"]; - std::string region_y_str = response["region_y"]; - if(!region_x_str.empty() && !region_y_str.empty()) - { - U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); - U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); - gFirstSimHandle = to_region_handle(region_x, region_y); - } - - const std::string look_at_str = response["look_at"]; - if (!look_at_str.empty()) - { - size_t len = look_at_str.size(); - LLMemoryStream mstr((U8*)look_at_str.c_str(), len); - LLSD sd = LLSDSerialize::fromNotation(mstr, len); - gAgentStartLookAt = ll_vector3_from_sd(sd); - } - - text = response["seed_capability"].asString(); - if (!text.empty()) gFirstSimSeedCap = text; - - text = response["seconds_since_epoch"].asString(); - if(!text.empty()) - { - U32 server_utc_time = strtoul(text.c_str(), NULL, 10); - if(server_utc_time) - { - time_t now = time(NULL); - gUTCOffset = (server_utc_time - now); - - // Print server timestamp - LLSD substitution; - substitution["datetime"] = (S32)server_utc_time; - std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; - LLStringUtil::format(timeStr, substitution); - LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; - } - } - - // this is the base used to construct help URLs - text = response["help_url_format"].asString(); - if (!text.empty()) - { - // replace the default help URL format - gSavedSettings.setString("HelpURLFormat",text); - } - - std::string home_location = response["home"]; - if(!home_location.empty()) - { - size_t len = home_location.size(); - LLMemoryStream mstr((U8*)home_location.c_str(), len); - LLSD sd = LLSDSerialize::fromNotation(mstr, len); - S32 region_x = sd["region_handle"][0].asInteger(); - S32 region_y = sd["region_handle"][1].asInteger(); - U64 region_handle = to_region_handle(region_x, region_y); - LLVector3 position = ll_vector3_from_sd(sd["position"]); - gAgent.setHomePosRegion(region_handle, position); - } - - gAgent.mMOTD.assign(response["message"]); - - // Options... - // Each 'option' is an array of submaps. - // It appears that we only ever use the first element of the array. - LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; - if(inv_root_folder_id.notNull()) - { - gInventory.setRootFolderID(inv_root_folder_id); - //gInventory.mock(gAgent.getInventoryRootID()); - } - - LLSD login_flags = response["login-flags"][0]; - if(login_flags.size()) - { - std::string flag = login_flags["ever_logged_in"]; - if(!flag.empty()) - { - gAgent.setFirstLogin(flag == "N"); - } - - /* Flag is currently ignored by the viewer. - flag = login_flags["stipend_since_login"]; - if(flag == "Y") - { - stipend_since_login = true; - } - */ - - flag = login_flags["gendered"].asString(); - if(flag == "Y") - { - // We don't care about this flag anymore; now base whether - // outfit is chosen on COF contents, initial outfit - // requested and available, etc. - - //gAgent.setGenderChosen(TRUE); - } - - bool pacific_daylight_time = false; - flag = login_flags["daylight_savings"].asString(); - if(flag == "Y") - { - pacific_daylight_time = (flag == "Y"); - } - - //setup map of datetime strings to codes and slt & local time offset from utc - LLStringOps::setupDatetimeInfo(pacific_daylight_time); - } - - // set up the voice configuration. Ultimately, we should pass this up as part of each voice - // channel if we need to move to multiple voice servers per grid. - LLSD voice_config_info = response["voice-config"]; - if(voice_config_info.has("VoiceServerType")) - { - gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); - } - - // Request the map server url - std::string map_server_url = response["map-server-url"]; - if(!map_server_url.empty()) - { - // We got an answer from the grid -> use that for map for the current session - gSavedSettings.setString("CurrentMapServerURL", map_server_url); - LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; - } - else - { - // No answer from the grid -> use the default setting for current session - map_server_url = gSavedSettings.getString("MapServerURL"); - gSavedSettings.setString("CurrentMapServerURL", map_server_url); - LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; - } - - // Default male and female avatars allowing the user to choose their avatar on first login. - // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard - // "new ruth." Not to be confused with 'initial-outfit' below - LLSD newuser_config = response["newuser-config"][0]; - if(newuser_config.has("DefaultFemaleAvatar")) - { - gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); - } - if(newuser_config.has("DefaultMaleAvatar")) - { - gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); - } - - // Initial outfit for the user. - LLSD initial_outfit = response["initial-outfit"][0]; - if(initial_outfit.size()) - { - std::string flag = initial_outfit["folder_name"]; - if(!flag.empty()) - { - // Initial outfit is a folder in your inventory, - // must be an exact folder-name match. - sInitialOutfit = flag; - } - - flag = initial_outfit["gender"].asString(); - if(!flag.empty()) - { - sInitialOutfitGender = flag; - } - } - - std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); - if (!fake_initial_outfit_name.empty()) - { - gAgent.setFirstLogin(true); - sInitialOutfit = fake_initial_outfit_name; - if (sInitialOutfitGender.empty()) - { - sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. - } - - LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; - } - - // set the location of the Agent Appearance service, from which we can request - // avatar baked textures if they are supported by the current region - std::string agent_appearance_url = response["agent_appearance_service"]; - if (!agent_appearance_url.empty()) - { - LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); - } - - // Set the location of the snapshot sharing config endpoint - std::string snapshot_config_url = response["snapshot_config_url"]; - if(!snapshot_config_url.empty()) - { - gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); - } - - // Start the process of fetching the OpenID session cookie for this user login - std::string openid_url = response["openid_url"]; - if(!openid_url.empty()) - { - std::string openid_token = response["openid_token"]; - LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); - } - - - // Only save mfa_hash for future logins if the user wants their info remembered. - if(response.has("mfa_hash") + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + mBenefitsSuccessfullyInit = init_benefits(response); + + std::string text(response["udp_blacklist"]); + if(!text.empty()) + { + apply_udp_blacklist(text); + } + + // unpack login data needed by the application + text = response["agent_id"].asString(); + if(!text.empty()) gAgentID.set(text); + gDebugInfo["AgentID"] = text; + + LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); + LLPerfStats::StatsRecorder::setFocusAv(gAgentID); + + // Agent id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setAgentID(gAgentID); + + text = response["session_id"].asString(); + if(!text.empty()) gAgentSessionID.set(text); + gDebugInfo["SessionID"] = text; + + // Session id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setSessionID(gAgentSessionID); + + text = response["secure_session_id"].asString(); + if(!text.empty()) gAgent.mSecureSessionID.set(text); + + // if the response contains a display name, use that, + // otherwise if the response contains a first and/or last name, + // use those. Otherwise use the credential identifier + + gDisplayName = ""; + if (response.has("display_name")) + { + gDisplayName.assign(response["display_name"].asString()); + if(!gDisplayName.empty()) + { + // Remove quotes from string. Login.cgi sends these to force + // names that look like numbers into strings. + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + } + std::string first_name; + if(response.has("first_name")) + { + first_name = response["first_name"].asString(); + LLStringUtil::replaceChar(first_name, '"', ' '); + LLStringUtil::trim(first_name); + gAgentUsername = first_name; + } + + if(response.has("last_name") && !gAgentUsername.empty()) + { + std::string last_name = response["last_name"].asString(); + if (last_name != "Resident") + { + LLStringUtil::replaceChar(last_name, '"', ' '); + LLStringUtil::trim(last_name); + gAgentUsername = gAgentUsername + " " + last_name; + } + } + + if(gDisplayName.empty()) + { + if(response.has("first_name")) + { + gDisplayName.assign(response["first_name"].asString()); + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + if(response.has("last_name")) + { + text.assign(response["last_name"].asString()); + LLStringUtil::replaceChar(text, '"', ' '); + LLStringUtil::trim(text); + if(!gDisplayName.empty()) + { + gDisplayName += " "; + } + gDisplayName += text; + } + } + + if(gDisplayName.empty()) + { + gDisplayName.assign(gUserCredential->asString()); + } + + // this is their actual ability to access content + text = response["agent_access_max"].asString(); + if (!text.empty()) + { + // agent_access can be 'A', 'M', and 'PG'. + gAgent.setMaturity(text[0]); + } + + // this is the value of their preference setting for that content + // which will always be <= agent_access_max + text = response["agent_region_access"].asString(); + if (!text.empty()) + { + U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); + + gSavedSettings.setU32("PreferredMaturity", preferredMaturity); + } + + text = response["start_location"].asString(); + if(!text.empty()) + { + gAgentStartLocation.assign(text); + } + + text = response["circuit_code"].asString(); + if(!text.empty()) + { + gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); + } + std::string sim_ip_str = response["sim_ip"]; + std::string sim_port_str = response["sim_port"]; + if(!sim_ip_str.empty() && !sim_port_str.empty()) + { + U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); + gFirstSim.set(sim_ip_str, sim_port); + if (gFirstSim.isOk()) + { + gMessageSystem->enableCircuit(gFirstSim, TRUE); + } + } + std::string region_x_str = response["region_x"]; + std::string region_y_str = response["region_y"]; + if(!region_x_str.empty() && !region_y_str.empty()) + { + U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); + U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); + gFirstSimHandle = to_region_handle(region_x, region_y); + } + + const std::string look_at_str = response["look_at"]; + if (!look_at_str.empty()) + { + size_t len = look_at_str.size(); + LLMemoryStream mstr((U8*)look_at_str.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + gAgentStartLookAt = ll_vector3_from_sd(sd); + } + + text = response["seed_capability"].asString(); + if (!text.empty()) gFirstSimSeedCap = text; + + text = response["seconds_since_epoch"].asString(); + if(!text.empty()) + { + U32 server_utc_time = strtoul(text.c_str(), NULL, 10); + if(server_utc_time) + { + time_t now = time(NULL); + gUTCOffset = (server_utc_time - now); + + // Print server timestamp + LLSD substitution; + substitution["datetime"] = (S32)server_utc_time; + std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; + LLStringUtil::format(timeStr, substitution); + LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; + } + } + + // this is the base used to construct help URLs + text = response["help_url_format"].asString(); + if (!text.empty()) + { + // replace the default help URL format + gSavedSettings.setString("HelpURLFormat",text); + } + + std::string home_location = response["home"]; + if(!home_location.empty()) + { + size_t len = home_location.size(); + LLMemoryStream mstr((U8*)home_location.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + S32 region_x = sd["region_handle"][0].asInteger(); + S32 region_y = sd["region_handle"][1].asInteger(); + U64 region_handle = to_region_handle(region_x, region_y); + LLVector3 position = ll_vector3_from_sd(sd["position"]); + gAgent.setHomePosRegion(region_handle, position); + } + + gAgent.mMOTD.assign(response["message"]); + + // Options... + // Each 'option' is an array of submaps. + // It appears that we only ever use the first element of the array. + LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; + if(inv_root_folder_id.notNull()) + { + gInventory.setRootFolderID(inv_root_folder_id); + //gInventory.mock(gAgent.getInventoryRootID()); + } + + LLSD login_flags = response["login-flags"][0]; + if(login_flags.size()) + { + std::string flag = login_flags["ever_logged_in"]; + if(!flag.empty()) + { + gAgent.setFirstLogin(flag == "N"); + } + + /* Flag is currently ignored by the viewer. + flag = login_flags["stipend_since_login"]; + if(flag == "Y") + { + stipend_since_login = true; + } + */ + + flag = login_flags["gendered"].asString(); + if(flag == "Y") + { + // We don't care about this flag anymore; now base whether + // outfit is chosen on COF contents, initial outfit + // requested and available, etc. + + //gAgent.setGenderChosen(TRUE); + } + + bool pacific_daylight_time = false; + flag = login_flags["daylight_savings"].asString(); + if(flag == "Y") + { + pacific_daylight_time = (flag == "Y"); + } + + //setup map of datetime strings to codes and slt & local time offset from utc + LLStringOps::setupDatetimeInfo(pacific_daylight_time); + } + + // set up the voice configuration. Ultimately, we should pass this up as part of each voice + // channel if we need to move to multiple voice servers per grid. + LLSD voice_config_info = response["voice-config"]; + if(voice_config_info.has("VoiceServerType")) + { + gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); + } + + // Request the map server url + std::string map_server_url = response["map-server-url"]; + if(!map_server_url.empty()) + { + // We got an answer from the grid -> use that for map for the current session + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; + } + else + { + // No answer from the grid -> use the default setting for current session + map_server_url = gSavedSettings.getString("MapServerURL"); + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; + } + + // Default male and female avatars allowing the user to choose their avatar on first login. + // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard + // "new ruth." Not to be confused with 'initial-outfit' below + LLSD newuser_config = response["newuser-config"][0]; + if(newuser_config.has("DefaultFemaleAvatar")) + { + gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); + } + if(newuser_config.has("DefaultMaleAvatar")) + { + gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); + } + + // Initial outfit for the user. + LLSD initial_outfit = response["initial-outfit"][0]; + if(initial_outfit.size()) + { + std::string flag = initial_outfit["folder_name"]; + if(!flag.empty()) + { + // Initial outfit is a folder in your inventory, + // must be an exact folder-name match. + sInitialOutfit = flag; + } + + flag = initial_outfit["gender"].asString(); + if(!flag.empty()) + { + sInitialOutfitGender = flag; + } + } + + std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); + if (!fake_initial_outfit_name.empty()) + { + gAgent.setFirstLogin(true); + sInitialOutfit = fake_initial_outfit_name; + if (sInitialOutfitGender.empty()) + { + sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. + } + + LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; + } + + // set the location of the Agent Appearance service, from which we can request + // avatar baked textures if they are supported by the current region + std::string agent_appearance_url = response["agent_appearance_service"]; + if (!agent_appearance_url.empty()) + { + LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); + } + + // Set the location of the snapshot sharing config endpoint + std::string snapshot_config_url = response["snapshot_config_url"]; + if(!snapshot_config_url.empty()) + { + gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); + } + + // Start the process of fetching the OpenID session cookie for this user login + std::string openid_url = response["openid_url"]; + if(!openid_url.empty()) + { + std::string openid_token = response["openid_token"]; + LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); + } + + + // Only save mfa_hash for future logins if the user wants their info remembered. + if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && LLLoginInstance::getInstance()->saveMFA()) - { - std::string grid(LLGridManager::getInstance()->getGridId()); - std::string user_id(gUserCredential->userID()); - gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); - // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically - gSecAPIHandler->syncProtectedMap(); - } + { + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id(gUserCredential->userID()); + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); + // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically + gSecAPIHandler->syncProtectedMap(); + } else if (!LLLoginInstance::getInstance()->saveMFA()) { std::string grid(LLGridManager::getInstance()->getGridId()); @@ -3870,26 +3870,26 @@ bool process_login_success_response() gSecAPIHandler->syncProtectedMap(); } - bool success = false; - // JC: gesture loading done below, when we have an asset system - // in place. Don't delete/clear gUserCredentials until then. - if(gAgentID.notNull() - && gAgentSessionID.notNull() - && gMessageSystem->mOurCircuitCode - && gFirstSim.isOk() - && gInventory.getRootFolderID().notNull()) - { - success = true; - } + bool success = false; + // JC: gesture loading done below, when we have an asset system + // in place. Don't delete/clear gUserCredentials until then. + if(gAgentID.notNull() + && gAgentSessionID.notNull() + && gMessageSystem->mOurCircuitCode + && gFirstSim.isOk() + && gInventory.getRootFolderID().notNull()) + { + success = true; + } LLAppViewer* pApp = LLAppViewer::instance(); - pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. - return success; + pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. + return success; } void transition_back_to_login_panel(const std::string& emsg) { - // Bounce back to the login screen. - reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - gSavedSettings.setBOOL("AutoLogin", FALSE); + // Bounce back to the login screen. + reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + gSavedSettings.setBOOL("AutoLogin", FALSE); } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index a4e6d20181..94aa4a61ac 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltoolplacer.cpp * @brief Tool for placing new objects into the world * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -60,480 +60,480 @@ // linden library headers #include "llprimitive.h" -#include "llwindow.h" // incBusyCount() +#include "llwindow.h" // incBusyCount() #include "material_codes.h" #include "lluiusage.h" const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f); -//static -LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; +//static +LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; LLToolPlacer::LLToolPlacer() -: LLTool( "Create" ) +: LLTool( "Create" ) { } -BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, - BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) +BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, + BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) { - F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; - - // Viewer-side pick to find the right sim to create the object on. - // First find the surface the object will be created on. - LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); - - // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok - // representations (if any) are NOT the same as their viewer representation. - if (pick.mPickType == LLPickInfo::PICK_FLORA) - { - *hit_obj = NULL; - *hit_face = -1; - } - else - { - *hit_obj = pick.getObject(); - *hit_face = pick.mObjectFace; - } - *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); - LLVector3d land_pos_global = pick.mPosGlobal; - - // Make sure there's a surface to place the new object on. - BOOL bypass_sim_raycast = FALSE; - LLVector3d surface_pos_global; - if (*b_hit_land) - { - surface_pos_global = land_pos_global; - bypass_sim_raycast = TRUE; - } - else - if (*hit_obj) - { - surface_pos_global = (*hit_obj)->getPositionGlobal(); - } - else - { - return FALSE; - } - - // Make sure the surface isn't too far away. - LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); - F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); - if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) - { - return FALSE; - } - - // Find the sim where the surface lives. - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); - if (!regionp) - { - LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; - return FALSE; - } - - // Find the simulator-side ray that will be used to place the object accurately - LLVector3d mouse_direction; - mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); - - *region = regionp; - *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); - F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. - *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; - - if( bypass_sim_raycast ) - { - // Hack to work around Havok's inability to ray cast onto height fields - *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point - } - else - { - LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. - *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); - } - - return TRUE; + F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; + + // Viewer-side pick to find the right sim to create the object on. + // First find the surface the object will be created on. + LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); + + // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok + // representations (if any) are NOT the same as their viewer representation. + if (pick.mPickType == LLPickInfo::PICK_FLORA) + { + *hit_obj = NULL; + *hit_face = -1; + } + else + { + *hit_obj = pick.getObject(); + *hit_face = pick.mObjectFace; + } + *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); + LLVector3d land_pos_global = pick.mPosGlobal; + + // Make sure there's a surface to place the new object on. + BOOL bypass_sim_raycast = FALSE; + LLVector3d surface_pos_global; + if (*b_hit_land) + { + surface_pos_global = land_pos_global; + bypass_sim_raycast = TRUE; + } + else + if (*hit_obj) + { + surface_pos_global = (*hit_obj)->getPositionGlobal(); + } + else + { + return FALSE; + } + + // Make sure the surface isn't too far away. + LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); + F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); + if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) + { + return FALSE; + } + + // Find the sim where the surface lives. + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); + if (!regionp) + { + LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; + return FALSE; + } + + // Find the simulator-side ray that will be used to place the object accurately + LLVector3d mouse_direction; + mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); + + *region = regionp; + *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); + F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. + *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; + + if( bypass_sim_raycast ) + { + // Hack to work around Havok's inability to ray cast onto height fields + *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point + } + else + { + LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. + *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); + } + + return TRUE; } BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - BOOL b_hit_land = FALSE; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - return FALSE; - } + LLVector3 ray_start_region; + LLVector3 ray_end_region; + LLViewerRegion* regionp = NULL; + BOOL b_hit_land = FALSE; + S32 hit_face = -1; + LLViewerObject* hit_obj = NULL; + BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); + if( !success ) + { + return FALSE; + } return rezNewObject(pcode,hit_obj, hit_face, b_hit_land, ray_start_region, ray_end_region, regionp, use_physics); } BOOL LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion* regionp, U8 use_physics) { - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - return FALSE; - } - - if (NULL == regionp) - { - LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; - return FALSE; - } - - if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) - { - //LLFirstUse::useSandbox(); - } - - // Set params for new object based on its PCode. - LLQuaternion rotation; - LLVector3 scale = DEFAULT_OBJECT_SCALE; - U8 material = LL_MCODE_WOOD; - BOOL create_selected = FALSE; - LLVolumeParams volume_params; + if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) + { + // Can't create objects on avatars or attachments + return FALSE; + } + + if (NULL == regionp) + { + LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; + return FALSE; + } + + if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) + { + //LLFirstUse::useSandbox(); + } + + // Set params for new object based on its PCode. + LLQuaternion rotation; + LLVector3 scale = DEFAULT_OBJECT_SCALE; + U8 material = LL_MCODE_WOOD; + BOOL create_selected = FALSE; + LLVolumeParams volume_params; U8 state = 0; - - switch (pcode) - { - case LL_PCODE_LEGACY_GRASS: - // Randomize size of grass patch - scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); - state = rand() % LLVOGrass::sMaxGrassSpecies; - break; - - - case LL_PCODE_LEGACY_TREE: - case LL_PCODE_TREE_NEW: - state = rand() % LLVOTree::sMaxTreeSpecies; - break; - - case LL_PCODE_SPHERE: - case LL_PCODE_CONE: - case LL_PCODE_CUBE: - case LL_PCODE_CYLINDER: - case LL_PCODE_TORUS: - case LLViewerObject::LL_VO_SQUARE_TORUS: - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - default: - create_selected = TRUE; - break; - } - - // Play creation sound - if (gAudiop) - { - gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), - gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - } - - LLUIUsage::instance().logCommand("Build.ObjectAdd"); - gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU8Fast(_PREHASH_Material, material); - - U32 flags = 0; // not selected - if (use_physics) - { - flags |= FLAGS_USE_PHYSICS; - } - if (create_selected) - { - flags |= FLAGS_CREATE_SELECTED; - } - gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); - - LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error - switch (pcode) - { - case LL_PCODE_SPHERE: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_SQUARE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_SPHERE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - //volume_params.setBeginAndEndS( 0.5f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 0.5f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CUBE: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PRISM: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 1 ); - volume_params.setShear ( -0.5f, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PYRAMID: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TETRAHEDRON: - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - default: - LLVolumeMessage::packVolumeParams(0, gMessageSystem); - volume_pcode = pcode; - break; - } - gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); - - gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); - gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); - gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); - gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); - gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); - gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); - gMessageSystem->addU8Fast(_PREHASH_State, state); - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); - - // Pack in name value pairs - gMessageSystem->sendReliable(regionp->getHost()); - - // Spawns a message, so must be after above send - if (create_selected) - { - LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->getWindow()->incBusyCount(); - } - - // VEFFECT: AddObject - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); - effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); - effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); - effectp->setDuration(LL_HUD_DUR_SHORT); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - - add(LLStatViewer::OBJECT_CREATE, 1); - - return TRUE; + + switch (pcode) + { + case LL_PCODE_LEGACY_GRASS: + // Randomize size of grass patch + scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); + state = rand() % LLVOGrass::sMaxGrassSpecies; + break; + + + case LL_PCODE_LEGACY_TREE: + case LL_PCODE_TREE_NEW: + state = rand() % LLVOTree::sMaxTreeSpecies; + break; + + case LL_PCODE_SPHERE: + case LL_PCODE_CONE: + case LL_PCODE_CUBE: + case LL_PCODE_CYLINDER: + case LL_PCODE_TORUS: + case LLViewerObject::LL_VO_SQUARE_TORUS: + case LLViewerObject::LL_VO_TRIANGLE_TORUS: + default: + create_selected = TRUE; + break; + } + + // Play creation sound + if (gAudiop) + { + gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), + gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + } + + LLUIUsage::instance().logCommand("Build.ObjectAdd"); + gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU8Fast(_PREHASH_Material, material); + + U32 flags = 0; // not selected + if (use_physics) + { + flags |= FLAGS_USE_PHYSICS; + } + if (create_selected) + { + flags |= FLAGS_CREATE_SELECTED; + } + gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); + + LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error + switch (pcode) + { + case LL_PCODE_SPHERE: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LLViewerObject::LL_VO_SQUARE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LLViewerObject::LL_VO_TRIANGLE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_SPHERE_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); + //volume_params.setBeginAndEndS( 0.5f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 0.5f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CUBE: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_PRISM: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 1 ); + volume_params.setShear ( -0.5f, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_PYRAMID: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_TETRAHEDRON: + volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CYLINDER: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CYLINDER_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.25f, 0.75f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CONE: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CONE_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.25f, 0.75f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + default: + LLVolumeMessage::packVolumeParams(0, gMessageSystem); + volume_pcode = pcode; + break; + } + gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); + + gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); + gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); + gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); + gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); + gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); + gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); + gMessageSystem->addU8Fast(_PREHASH_State, state); + + // Limit raycast to a single object. + // Speeds up server raycast + avoid problems with server ray hitting objects + // that were clipped by the near plane or culled on the viewer. + LLUUID ray_target_id; + if( hit_obj ) + { + ray_target_id = hit_obj->getID(); + } + else + { + ray_target_id.setNull(); + } + gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); + + // Pack in name value pairs + gMessageSystem->sendReliable(regionp->getHost()); + + // Spawns a message, so must be after above send + if (create_selected) + { + LLSelectMgr::getInstance()->deselectAll(); + gViewerWindow->getWindow()->incBusyCount(); + } + + // VEFFECT: AddObject + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); + effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); + effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + + add(LLStatViewer::OBJECT_CREATE, 1); + + return TRUE; } // Used by the placer tool to add copies of the current selection. // Inspired by add_object(). JC BOOL LLToolPlacer::addDuplicate(S32 x, S32 y) { - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - BOOL b_hit_land = FALSE; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - make_ui_sound("UISndInvalidOp"); - return FALSE; - } - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - make_ui_sound("UISndInvalidOp"); - return FALSE; - } - - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - - LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, - ray_end_region, - b_hit_land, // suppress raycast - FALSE, // intersection - ray_target_id, - gSavedSettings.getBOOL("CreateToolCopyCenters"), - gSavedSettings.getBOOL("CreateToolCopyRotates"), - FALSE); // select copy - - if (regionp - && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) - { - //LLFirstUse::useSandbox(); - } - - return TRUE; + LLVector3 ray_start_region; + LLVector3 ray_end_region; + LLViewerRegion* regionp = NULL; + BOOL b_hit_land = FALSE; + S32 hit_face = -1; + LLViewerObject* hit_obj = NULL; + BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); + if( !success ) + { + make_ui_sound("UISndInvalidOp"); + return FALSE; + } + if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) + { + // Can't create objects on avatars or attachments + make_ui_sound("UISndInvalidOp"); + return FALSE; + } + + + // Limit raycast to a single object. + // Speeds up server raycast + avoid problems with server ray hitting objects + // that were clipped by the near plane or culled on the viewer. + LLUUID ray_target_id; + if( hit_obj ) + { + ray_target_id = hit_obj->getID(); + } + else + { + ray_target_id.setNull(); + } + + LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, + ray_end_region, + b_hit_land, // suppress raycast + FALSE, // intersection + ray_target_id, + gSavedSettings.getBOOL("CreateToolCopyCenters"), + gSavedSettings.getBOOL("CreateToolCopyRotates"), + FALSE); // select copy + + if (regionp + && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) + { + //LLFirstUse::useSandbox(); + } + + return TRUE; } BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) { - BOOL added = TRUE; - - if (gSavedSettings.getBOOL("CreateToolCopySelection")) - { - added = addDuplicate(x, y); - } - else - { - added = addObject( sObjectType, x, y, FALSE ); - } - - // ...and go back to the default tool - if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) - { - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); - } - - return added; + BOOL added = TRUE; + + if (gSavedSettings.getBOOL("CreateToolCopySelection")) + { + added = addDuplicate(x, y); + } + else + { + added = addObject( sObjectType, x, y, FALSE ); + } + + // ...and go back to the default tool + if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) + { + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); + } + + return added; } BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask) { - LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; - gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); - return TRUE; + LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; + gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); + return TRUE; } void LLToolPlacer::handleSelect() { - gFloaterTools->setStatusText("place"); + gFloaterTools->setStatusText("place"); } void LLToolPlacer::handleDeselect() diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index d20d682710..8b56790f7d 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -1,25 +1,25 @@ -/** +/** * @file lltoolplacer.h * @brief Tool for placing new objects into the world * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,31 +37,31 @@ class LLViewerRegion; // LLToolPlacer class LLToolPlacer - : public LLTool + : public LLTool { public: - LLToolPlacer(); + LLToolPlacer(); - virtual BOOL placeObject(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual void handleSelect(); // do stuff when your tool is selected - virtual void handleDeselect(); // clean up when your tool is deselected + virtual BOOL placeObject(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual void handleSelect(); // do stuff when your tool is selected + virtual void handleDeselect(); // clean up when your tool is deselected - static void setObjectType( LLPCode type ) { sObjectType = type; } - static LLPCode getObjectType() { return sObjectType; } + static void setObjectType( LLPCode type ) { sObjectType = type; } + static LLPCode getObjectType() { return sObjectType; } static BOOL addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics); static BOOL rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion *regionp, U8 use_physics); protected: - static LLPCode sObjectType; + static LLPCode sObjectType; private: - - static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, - BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); - BOOL addDuplicate(S32 x, S32 y); + + static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, + BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); + BOOL addDuplicate(S32 x, S32 y); }; #endif diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 16c4084a77..4e39b03903 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2009-07-09 * @brief Implementation for llviewercontrollistener. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,182 +44,182 @@ LLViewerControlListener sSavedSettingsListener; } // unnamed namespace LLViewerControlListener::LLViewerControlListener() - : LLEventAPI("LLViewerControl", - "LLViewerControl listener: set, toggle or set default for various controls") + : LLEventAPI("LLViewerControl", + "LLViewerControl listener: set, toggle or set default for various controls") { - std::ostringstream groupnames; - groupnames << "[\"group\"] is one of "; - const char* delim = ""; - for (const auto& key : LLControlGroup::key_snapshot()) - { - groupnames << delim << '"' << key << '"'; - delim = ", "; - } - groupnames << '\n'; - std::string grouphelp(groupnames.str()); - std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); - - add("set", - std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" - "If [\"value\"] omitted, set to control's defined default value\n") + - grouphelp + replyhelp, - &LLViewerControlListener::set, - LLSDMap("group", LLSD())("key", LLSD())); - add("toggle", - std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, - &LLViewerControlListener::toggle, - LLSDMap("group", LLSD())("key", LLSD())); - add("get", - std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + - grouphelp, - &LLViewerControlListener::get, - LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); - add("groups", - "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", - &LLViewerControlListener::groups, - LLSDMap("reply", LLSD())); - add("vars", - std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" - "each of whose entries looks like:\n" - " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, - &LLViewerControlListener::vars, - LLSDMap("group", LLSD())("reply", LLSD())); + std::ostringstream groupnames; + groupnames << "[\"group\"] is one of "; + const char* delim = ""; + for (const auto& key : LLControlGroup::key_snapshot()) + { + groupnames << delim << '"' << key << '"'; + delim = ", "; + } + groupnames << '\n'; + std::string grouphelp(groupnames.str()); + std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); + + add("set", + std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" + "If [\"value\"] omitted, set to control's defined default value\n") + + grouphelp + replyhelp, + &LLViewerControlListener::set, + LLSDMap("group", LLSD())("key", LLSD())); + add("toggle", + std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, + &LLViewerControlListener::toggle, + LLSDMap("group", LLSD())("key", LLSD())); + add("get", + std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + + grouphelp, + &LLViewerControlListener::get, + LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); + add("groups", + "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", + &LLViewerControlListener::groups, + LLSDMap("reply", LLSD())); + add("vars", + std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" + "each of whose entries looks like:\n" + " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, + &LLViewerControlListener::vars, + LLSDMap("group", LLSD())("reply", LLSD())); } struct Info { - Info(const LLSD& request): - response(LLSD(), request), - groupname(request["group"]), - group(LLControlGroup::getInstance(groupname)), - key(request["key"]), - control(NULL) - { - if (! group) - { - response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); - return; - } - - control = group->getControl(key); - if (! control) - { - response.error(STRINGIZE("In group '" << groupname - << "', unrecognized control key '" << key << "'")); - } - } - - ~Info() - { - // If in fact the request passed to our constructor names a valid - // group and key, grab the final value of the indicated control and - // stuff it in our response. Since this outer destructor runs before - // the contained Response destructor, this data will go into the - // response we send. - if (control) - { - response["name"] = control->getName(); - response["type"] = LLControlGroup::typeEnumToString(control->type()); - response["value"] = control->get(); - response["comment"] = control->getComment(); - } - } - - LLEventAPI::Response response; - std::string groupname; - LLControlGroup::ptr_t group; - std::string key; - LLControlVariable* control; + Info(const LLSD& request): + response(LLSD(), request), + groupname(request["group"]), + group(LLControlGroup::getInstance(groupname)), + key(request["key"]), + control(NULL) + { + if (! group) + { + response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); + return; + } + + control = group->getControl(key); + if (! control) + { + response.error(STRINGIZE("In group '" << groupname + << "', unrecognized control key '" << key << "'")); + } + } + + ~Info() + { + // If in fact the request passed to our constructor names a valid + // group and key, grab the final value of the indicated control and + // stuff it in our response. Since this outer destructor runs before + // the contained Response destructor, this data will go into the + // response we send. + if (control) + { + response["name"] = control->getName(); + response["type"] = LLControlGroup::typeEnumToString(control->type()); + response["value"] = control->get(); + response["comment"] = control->getComment(); + } + } + + LLEventAPI::Response response; + std::string groupname; + LLControlGroup::ptr_t group; + std::string key; + LLControlVariable* control; }; //static void LLViewerControlListener::set(LLSD const & request) { - Info info(request); - if (! info.control) - return; + Info info(request); + if (! info.control) + return; - if (request.has("value")) - { + if (request.has("value")) + { LL_WARNS("LLViewerControlListener") << "Changing debug setting " << std::quoted(info.key) << " to " << request["value"] << LL_ENDL; - info.control->setValue(request["value"], false); - } - else - { - info.control->resetToDefault(); - } + info.control->setValue(request["value"], false); + } + else + { + info.control->resetToDefault(); + } } //static void LLViewerControlListener::toggle(LLSD const & request) { - Info info(request); - if (! info.control) - return; + Info info(request); + if (! info.control) + return; - if (info.control->isType(TYPE_BOOLEAN)) - { + if (info.control->isType(TYPE_BOOLEAN)) + { bool value = !info.control->get().asBoolean(); LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << " to " << value << LL_ENDL; info.control->set(value, false); - } - else - { - info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname - << "' control '" << info.key - << "', type is " - << LLControlGroup::typeEnumToString(info.control->type()))); - } + } + else + { + info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname + << "' control '" << info.key + << "', type is " + << LLControlGroup::typeEnumToString(info.control->type()))); + } } void LLViewerControlListener::get(LLSD const & request) { - // The Info constructor and destructor actually do all the work here. - Info info(request); + // The Info constructor and destructor actually do all the work here. + Info info(request); } void LLViewerControlListener::groups(LLSD const & request) { - // No Info, we're not looking up either a group or a control name. - Response response(LLSD(), request); - for (const auto& key : LLControlGroup::key_snapshot()) - { - response["groups"].append(key); - } + // No Info, we're not looking up either a group or a control name. + Response response(LLSD(), request); + for (const auto& key : LLControlGroup::key_snapshot()) + { + response["groups"].append(key); + } } struct CollectVars: public LLControlGroup::ApplyFunctor { - CollectVars(LLControlGroup::ptr_t g): - mGroup(g) - {} - - virtual void apply(const std::string& name, LLControlVariable* control) - { - vars.append(LLSDMap - ("name", name) - ("type", LLControlGroup::typeEnumToString(control->type())) - ("value", control->get()) - ("comment", control->getComment())); - } - - LLControlGroup::ptr_t mGroup; - LLSD vars; + CollectVars(LLControlGroup::ptr_t g): + mGroup(g) + {} + + virtual void apply(const std::string& name, LLControlVariable* control) + { + vars.append(LLSDMap + ("name", name) + ("type", LLControlGroup::typeEnumToString(control->type())) + ("value", control->get()) + ("comment", control->getComment())); + } + + LLControlGroup::ptr_t mGroup; + LLSD vars; }; void LLViewerControlListener::vars(LLSD const & request) { - // This method doesn't use Info, because we're not looking up a specific - // control name. - Response response(LLSD(), request); - std::string groupname(request["group"]); - auto group(LLControlGroup::getInstance(groupname)); - if (! group) - { - return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); - } - - CollectVars collector(group); - group->applyToAll(&collector); - response["vars"] = collector.vars; + // This method doesn't use Info, because we're not looking up a specific + // control name. + Response response(LLSD(), request); + std::string groupname(request["group"]); + auto group(LLControlGroup::getInstance(groupname)); + if (! group) + { + return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); + } + + CollectVars collector(group); + group->applyToAll(&collector); + response["vars"] = collector.vars; } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 60add691c5..67da34e071 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerfloaterreg.cpp * @brief LLViewerFloaterReg class registers floaters used in the viewer * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -182,8 +182,8 @@ const std::string FLOATER_PROFILE("profile"); class LLFloaterOpenHandler : public LLCommandHandler { public: - // requires trusted browser to trigger or an explicit click - LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } + // requires trusted browser to trigger or an explicit click + LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } bool canHandleUntrusted( const LLSD& params, @@ -195,7 +195,7 @@ public: { return true; // will fail silently } - + std::string fl_name = params[0].asString(); // External browsers explicitly ask user about opening links @@ -282,237 +282,237 @@ public: return true; } - bool handle( + bool handle( const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) override - { - if (params.size() != 1) - { - return false; - } + { + if (params.size() != 1) + { + return false; + } - const std::string floater_name = LLURI::unescape(params[0].asString()); + const std::string floater_name = LLURI::unescape(params[0].asString()); LLSD key; if (floater_name == FLOATER_PROFILE) { key["id"] = gAgentID; } - LLFloaterReg::showInstance(floater_name, key); + LLFloaterReg::showInstance(floater_name, key); - return true; - } + return true; + } }; LLFloaterOpenHandler gFloaterOpenHandler; void LLViewerFloaterReg::registerFloaters() { - if (gNonInteractive) - { - return; - } - // *NOTE: Please keep these alphabetized for easier merges - - LLFloaterAboutUtil::registerFloater(); - LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater360Capture>); - LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFastTimerView>); - LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLand>); - LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAddPaymentMethod>); - LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAssociateListing>); - LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAuction>); - LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatar>); - LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarPicker>); - LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarRenderSettings>); - LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarTextures>); - - LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build<LLFloaterBanDuration>); - LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBeacons>); - LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBulkPermission>); - LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); - LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyCurrencyHTML>); - LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); - LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuy>); - LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyContents>); - LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTools>); - LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuildOptions>); - LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); - - LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>); - LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>); - LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); + if (gNonInteractive) + { + return; + } + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterAboutUtil::registerFloater(); + LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater360Capture>); + LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFastTimerView>); + LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLand>); + LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAddPaymentMethod>); + LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAssociateListing>); + LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAuction>); + LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatar>); + LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarPicker>); + LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarRenderSettings>); + LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarTextures>); + + LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build<LLFloaterBanDuration>); + LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBeacons>); + LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBulkPermission>); + LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); + LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyCurrencyHTML>); + LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); + LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuy>); + LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyContents>); + LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTools>); + LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuildOptions>); + LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); + + LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>); + LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>); + LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); LLFloaterReg::add("change_item_thumbnail", "floater_change_item_thumbnail.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChangeItemThumbnail>); - LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); - LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>); - LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); - LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>); - LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>); - - LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>); - LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); - - LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>); - LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>); - LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); - - LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); - LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); - - LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); - - LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); - LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); - - LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); - LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>); - LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperienceProfile>); - LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); - - LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); - LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); - - LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); - LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); - LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGridStatus>); - LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>); - - LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>); - LLFloaterReg::add("edit_hover_height", "floater_edit_hover_height.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHoverHeight>); - LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); - - LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMSession>); - LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMContainer>); - LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>); - LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); - LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); + LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); + LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>); + LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); + LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>); + LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>); + + LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>); + LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); + + LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>); + LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>); + LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); + + LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); + LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); + + LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); + + LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); + LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); + + LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); + LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>); + LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperienceProfile>); + LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); + + LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); + + LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); + LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); + LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGridStatus>); + LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>); + + LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>); + LLFloaterReg::add("edit_hover_height", "floater_edit_hover_height.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHoverHeight>); + LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); + + LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMSession>); + LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMContainer>); + LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>); + LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); + LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); LLFloaterReg::add("inventory_thumbnails_helper", "floater_inventory_thumbnails_helper.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterInventoryThumbnailsHelper>); - LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>); + LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>); LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>); LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventorySettings>); - LLInspectAvatarUtil::registerFloater(); - LLInspectGroupUtil::registerFloater(); - LLInspectObjectUtil::registerFloater(); - LLInspectRemoteObjectUtil::registerFloater(); - LLFloaterVoiceVolumeUtil::registerFloater(); - LLNotificationsUI::registerFloater(); - LLFloaterDisplayNameUtil::registerFloater(); - - LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>); - LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); - LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLinkReplace>); - LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>); + LLInspectAvatarUtil::registerFloater(); + LLInspectGroupUtil::registerFloater(); + LLInspectObjectUtil::registerFloater(); + LLInspectRemoteObjectUtil::registerFloater(); + LLFloaterVoiceVolumeUtil::registerFloater(); + LLNotificationsUI::registerFloater(); + LLFloaterDisplayNameUtil::registerFloater(); + + LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>); + LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); + LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLinkReplace>); + LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>); LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUADebug>); LLFloaterReg::add("lua_scripts", "floater_lua_scripts.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUAScripts>); - - LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); - - LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>); - LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>); - LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>); - LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); - LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); - LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); - LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); - LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); + + LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); + + LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>); + LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>); + LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>); + LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); + LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); + LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); + LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); + LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); LLFloaterReg::add("new_feature_notification", "floater_new_feature_notification.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNewFeatureNotification>); - LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); - - LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>); - - LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>); - LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); - LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); - LLFloaterPayUtil::registerFloater(); - - LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>); - LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); - LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); - LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerformance>); - LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPermsDefault>); - LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); - LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceGraphicsAdvanced>); - LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceViewAdvanced>); - LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>); - LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>); - LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>); - LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>); - LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>); - LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>); - LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewAnim>, "preview"); - LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationPreview>); - LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewGesture>, "preview"); - LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewNotecard>, "preview"); - LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewLSL>, "preview"); - LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLLiveLSLEditor>, "preview"); - LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewSound>, "preview"); - LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewTexture>, "preview"); - LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreviewTrash>); - LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>); - LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>); - LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>); - LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>); + LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); + + LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>); + + LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>); + LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); + LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); + LLFloaterPayUtil::registerFloater(); + + LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>); + LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); + LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); + LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerformance>); + LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPermsDefault>); + LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); + LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceGraphicsAdvanced>); + LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceViewAdvanced>); + LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>); + LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>); + LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>); + LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>); + LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>); + LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>); + LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewAnim>, "preview"); + LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationPreview>); + LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewGesture>, "preview"); + LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewNotecard>, "preview"); + LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewLSL>, "preview"); + LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLLiveLSLEditor>, "preview"); + LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewSound>, "preview"); + LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewTexture>, "preview"); + LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreviewTrash>); + LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>); + LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>); + LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>); + LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>); LLFloaterReg::add("material_editor", "floater_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLMaterialEditor>); LLFloaterReg::add("live_material_editor", "floater_live_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLMaterialEditor>); - - LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>); - LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build<LLFloaterTestInspectors>); - //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build<LLFloaterTestListView>); - LLFloaterReg::add("test_textbox", "floater_test_textbox.xml", &LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("test_text_editor", "floater_test_text_editor.xml", &LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTopObjects>); - LLFloaterReg::add("toybox", "floater_toybox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterToybox>); - - LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>); - LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>); - LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); - LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); - LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); - - LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); - LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); - LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); - LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptLimits>); - LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyScripts>); - LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); - LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>); - LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>); - LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>); - LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>); - LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>); - LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>); + + LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>); + LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build<LLFloaterTestInspectors>); + //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build<LLFloaterTestListView>); + LLFloaterReg::add("test_textbox", "floater_test_textbox.xml", &LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("test_text_editor", "floater_test_text_editor.xml", &LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTopObjects>); + LLFloaterReg::add("toybox", "floater_toybox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterToybox>); + + LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>); + LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>); + LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); + LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); + LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); + + LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); + LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); + LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); + LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptLimits>); + LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyScripts>); + LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); + LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>); + LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>); + LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>); + LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>); + LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>); + LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>); LLFloaterReg::add("simple_snapshot", "floater_simple_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleSnapshot>); LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>); LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProfile>); - LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>); - - LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>); - - LLFloaterUIPreviewUtil::registerFloater(); - LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload"); - LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); - LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); - LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); - LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptPreview>, "upload"); - LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); - - LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); - - LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); - LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); - LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build<LLFloaterWindowSize>); - LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); - - // *NOTE: Please keep these alphabetized for easier merges - - LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving + LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>); + + LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>); + + LLFloaterUIPreviewUtil::registerFloater(); + LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload"); + LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); + LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); + LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); + LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptPreview>, "upload"); + LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); + + LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); + + LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); + LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); + LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build<LLFloaterWindowSize>); + LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); + + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 52128a09ab..9f43fa1ac2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenu.cpp * @brief Builds menus out of items. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,7 +30,7 @@ #include "vld.h" #endif -#include "llviewermenu.h" +#include "llviewermenu.h" // linden library includes #include "llavatarnamecache.h" // IDEVO (I Are Not Men!) @@ -115,7 +115,7 @@ #include "llviewerdisplay.h" //for gWindowResized #include "llviewergenericmessage.h" #include "llviewerhelp.h" -#include "llviewermenufile.h" // init_menu_file() +#include "llviewermenufile.h" // init_menu_file() #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" @@ -159,7 +159,7 @@ void handle_test_load_url(void*); // // Evil hackish imported globals -//extern BOOL gHideSelectedObjects; +//extern BOOL gHideSelectedObjects; //extern BOOL gAllowSelectAvatar; //extern BOOL gDebugAvatarRotation; extern BOOL gDebugClicks; @@ -175,20 +175,20 @@ extern BOOL gShaderProfileFrame; LLUIListener sUIListener; -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuGL *gPopupMenuView = NULL; -LLMenuGL *gEditMenu = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; +LLMenuBarGL *gMenuBarView = NULL; +LLViewerMenuHolderGL *gMenuHolder = NULL; +LLMenuGL *gPopupMenuView = NULL; +LLMenuGL *gEditMenu = NULL; +LLMenuBarGL *gLoginMenuBarView = NULL; // Pie menus -LLContextMenu *gMenuAvatarSelf = NULL; -LLContextMenu *gMenuAvatarOther = NULL; -LLContextMenu *gMenuObject = NULL; -LLContextMenu *gMenuAttachmentSelf = NULL; -LLContextMenu *gMenuAttachmentOther = NULL; -LLContextMenu *gMenuLand = NULL; -LLContextMenu *gMenuMuteParticle = NULL; +LLContextMenu *gMenuAvatarSelf = NULL; +LLContextMenu *gMenuAvatarOther = NULL; +LLContextMenu *gMenuObject = NULL; +LLContextMenu *gMenuAttachmentSelf = NULL; +LLContextMenu *gMenuAttachmentOther = NULL; +LLContextMenu *gMenuLand = NULL; +LLContextMenu *gMenuMuteParticle = NULL; const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); @@ -286,7 +286,7 @@ void handle_force_parcel_owner_to_me(void*); void handle_force_parcel_to_content(void*); void handle_claim_public_land(void*); -void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry +void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry void reload_vertex_shader(void *); void handle_disconnect_viewer(void *); @@ -346,26 +346,26 @@ void menu_toggle_attached_particles(void* user_data); class LLMenuParcelObserver : public LLParcelObserver { public: - LLMenuParcelObserver(); - ~LLMenuParcelObserver(); - virtual void changed(); + LLMenuParcelObserver(); + ~LLMenuParcelObserver(); + virtual void changed(); }; static LLMenuParcelObserver* gMenuParcelObserver = NULL; LLMenuParcelObserver::LLMenuParcelObserver() { - LLViewerParcelMgr::getInstance()->addObserver(this); + LLViewerParcelMgr::getInstance()->addObserver(this); } LLMenuParcelObserver::~LLMenuParcelObserver() { - LLViewerParcelMgr::getInstance()->removeObserver(this); + LLViewerParcelMgr::getInstance()->removeObserver(this); } void LLMenuParcelObserver::changed() { - LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); if (gMenuLand && parcel) { LLView* child = gMenuLand->findChild<LLView>("Land Buy Pass"); @@ -438,131 +438,131 @@ void check_merchant_status(bool force) void init_menus() { - // Initialize actions - initialize_menus(); - - /// - /// Popup menu - /// - /// The popup menu is now populated by the show_context_menu() - /// method. - - LLMenuGL::Params menu_params; - menu_params.name = "Popup"; - menu_params.visible = false; - gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params); - gMenuHolder->addChild( gPopupMenuView ); - - /// - /// Context menus - /// - - const widget_registry_t& registry = - LLViewerMenuHolderGL::child_registry_t::instance(); - gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry); - gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_avatar_self.xml", gMenuHolder, registry); - gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_avatar_other.xml", gMenuHolder, registry); - - gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true); - gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true); - - gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_object.xml", gMenuHolder, registry); - - gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD"); - gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach"); - - gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_attachment_self.xml", gMenuHolder, registry); - gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_attachment_other.xml", gMenuHolder, registry); - - gDetachHUDAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self HUD", true); - gDetachAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self", true); - - gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_land.xml", gMenuHolder, registry); - - gMenuMuteParticle = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_mute_particle.xml", gMenuHolder, registry); - - /// - /// set up the colors - /// - LLColor4 color; - - LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); - - gMenuAvatarSelf->setBackgroundColor( context_menu_color ); - gMenuAvatarOther->setBackgroundColor( context_menu_color ); - gMenuObject->setBackgroundColor( context_menu_color ); - gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); - gMenuAttachmentOther->setBackgroundColor( context_menu_color ); - - gMenuLand->setBackgroundColor( context_menu_color ); - - color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); - gPopupMenuView->setBackgroundColor( color ); - - // If we are not in production, use a different color to make it apparent. - if (LLGridManager::getInstance()->isInProductionGrid()) - { - color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); - } - else - { - color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); - } - - LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); - - gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); - gMenuBarView->setBackgroundColor( color ); - - menu_bar_holder->addChild(gMenuBarView); - - gViewerWindow->setMenuBackgroundColor(false, + // Initialize actions + initialize_menus(); + + /// + /// Popup menu + /// + /// The popup menu is now populated by the show_context_menu() + /// method. + + LLMenuGL::Params menu_params; + menu_params.name = "Popup"; + menu_params.visible = false; + gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params); + gMenuHolder->addChild( gPopupMenuView ); + + /// + /// Context menus + /// + + const widget_registry_t& registry = + LLViewerMenuHolderGL::child_registry_t::instance(); + gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry); + gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_avatar_self.xml", gMenuHolder, registry); + gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_avatar_other.xml", gMenuHolder, registry); + + gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true); + gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true); + + gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_object.xml", gMenuHolder, registry); + + gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD"); + gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach"); + + gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_attachment_self.xml", gMenuHolder, registry); + gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_attachment_other.xml", gMenuHolder, registry); + + gDetachHUDAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self HUD", true); + gDetachAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self", true); + + gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_land.xml", gMenuHolder, registry); + + gMenuMuteParticle = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_mute_particle.xml", gMenuHolder, registry); + + /// + /// set up the colors + /// + LLColor4 color; + + LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); + + gMenuAvatarSelf->setBackgroundColor( context_menu_color ); + gMenuAvatarOther->setBackgroundColor( context_menu_color ); + gMenuObject->setBackgroundColor( context_menu_color ); + gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); + gMenuAttachmentOther->setBackgroundColor( context_menu_color ); + + gMenuLand->setBackgroundColor( context_menu_color ); + + color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); + gPopupMenuView->setBackgroundColor( color ); + + // If we are not in production, use a different color to make it apparent. + if (LLGridManager::getInstance()->isInProductionGrid()) + { + color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); + } + else + { + color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); + } + + LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); + + gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); + gMenuBarView->setBackgroundColor( color ); + + menu_bar_holder->addChild(gMenuBarView); + + gViewerWindow->setMenuBackgroundColor(false, LLGridManager::getInstance()->isInProductionGrid()); - // *TODO:Also fix cost in llfolderview.cpp for Inventory menus - const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); - const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); - const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); - - gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); - gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); - - gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true); - gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true); - - // Don't display the Memory console menu if the feature is turned off - LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); - if (memoryMenu) - { - memoryMenu->setVisible(FALSE); - } - - gMenuBarView->createJumpKeys(); - - // Let land based option enable when parcel changes - gMenuParcelObserver = new LLMenuParcelObserver(); - - gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gLoginMenuBarView->arrangeAndClear(); - LLRect menuBarRect = gLoginMenuBarView->getRect(); - menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); - gLoginMenuBarView->setRect(menuBarRect); - gLoginMenuBarView->setBackgroundColor( color ); - menu_bar_holder->addChild(gLoginMenuBarView); - - // tooltips are on top of EVERYTHING, including menus - gViewerWindow->getRootView()->sendChildToFront(gToolTipView); + // *TODO:Also fix cost in llfolderview.cpp for Inventory menus + const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); + const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); + const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); + gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); + + gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); + gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); + + gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true); + gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true); + + // Don't display the Memory console menu if the feature is turned off + LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); + if (memoryMenu) + { + memoryMenu->setVisible(FALSE); + } + + gMenuBarView->createJumpKeys(); + + // Let land based option enable when parcel changes + gMenuParcelObserver = new LLMenuParcelObserver(); + + gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gLoginMenuBarView->arrangeAndClear(); + LLRect menuBarRect = gLoginMenuBarView->getRect(); + menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); + gLoginMenuBarView->setRect(menuBarRect); + gLoginMenuBarView->setBackgroundColor( color ); + menu_bar_holder->addChild(gLoginMenuBarView); + + // tooltips are on top of EVERYTHING, including menus + gViewerWindow->getRootView()->sendChildToFront(gToolTipView); } /////////////////// @@ -572,62 +572,62 @@ void init_menus() class LLAdvancedToggleConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - if ("texture" == console_type) - { - toggle_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep)); - } - else if ("fast timers" == console_type) - { - LLFloaterReg::toggleInstance("block_timers"); - } - else if ("scene view" == console_type) - { - toggle_visibility( (void*)gSceneView); - } - else if ("scene monitor" == console_type) - { - toggle_visibility( (void*)gSceneMonitorView); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string console_type = userdata.asString(); + if ("texture" == console_type) + { + toggle_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep)); + } + else if ("fast timers" == console_type) + { + LLFloaterReg::toggleInstance("block_timers"); + } + else if ("scene view" == console_type) + { + toggle_visibility( (void*)gSceneView); + } + else if ("scene monitor" == console_type) + { + toggle_visibility( (void*)gSceneMonitorView); + } + + return true; + } }; class LLAdvancedCheckConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - bool new_value = false; - if ("texture" == console_type) - { - new_value = get_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); - } - else if ("fast timers" == console_type) - { - new_value = LLFloaterReg::instanceVisible("block_timers"); - } - else if ("scene view" == console_type) - { - new_value = get_visibility( (void*) gSceneView); - } - else if ("scene monitor" == console_type) - { - new_value = get_visibility( (void*) gSceneMonitorView); - } - - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string console_type = userdata.asString(); + bool new_value = false; + if ("texture" == console_type) + { + new_value = get_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); + } + else if ("fast timers" == console_type) + { + new_value = LLFloaterReg::instanceVisible("block_timers"); + } + else if ("scene view" == console_type) + { + new_value = get_visibility( (void*) gSceneView); + } + else if ("scene monitor" == console_type) + { + new_value = get_visibility( (void*) gSceneMonitorView); + } + + return new_value; + } }; @@ -638,24 +638,24 @@ class LLAdvancedCheckConsole : public view_listener_t class LLAdvancedDumpInfoToConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugView->mDebugConsolep->setVisible(TRUE); - std::string info_type = userdata.asString(); - if ("region" == info_type) - { - handle_region_dump_settings(NULL); - } - else if ("group" == info_type) - { - handle_dump_group_info(NULL); - } - else if ("capabilities" == info_type) - { - handle_dump_capabilities_info(NULL); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugView->mDebugConsolep->setVisible(TRUE); + std::string info_type = userdata.asString(); + if ("region" == info_type) + { + handle_region_dump_settings(NULL); + } + else if ("group" == info_type) + { + handle_dump_group_info(NULL); + } + else if ("capabilities" == info_type) + { + handle_dump_capabilities_info(NULL); + } + return true; + } }; @@ -666,54 +666,54 @@ class LLAdvancedDumpInfoToConsole : public view_listener_t class LLAdvancedToggleHUDInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - - if ("camera" == info_type) - { - gDisplayCameraPos = !(gDisplayCameraPos); - } - else if ("wind" == info_type) - { - gDisplayWindInfo = !(gDisplayWindInfo); - } - else if ("fov" == info_type) - { - gDisplayFOV = !(gDisplayFOV); - } - else if ("badge" == info_type) - { - gDisplayBadge = !(gDisplayBadge); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + + if ("camera" == info_type) + { + gDisplayCameraPos = !(gDisplayCameraPos); + } + else if ("wind" == info_type) + { + gDisplayWindInfo = !(gDisplayWindInfo); + } + else if ("fov" == info_type) + { + gDisplayFOV = !(gDisplayFOV); + } + else if ("badge" == info_type) + { + gDisplayBadge = !(gDisplayBadge); + } + return true; + } }; class LLAdvancedCheckHUDInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - bool new_value = false; - if ("camera" == info_type) - { - new_value = gDisplayCameraPos; - } - else if ("wind" == info_type) - { - new_value = gDisplayWindInfo; - } - else if ("fov" == info_type) - { - new_value = gDisplayFOV; - } - else if ("badge" == info_type) - { - new_value = gDisplayBadge; - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + bool new_value = false; + if ("camera" == info_type) + { + new_value = gDisplayCameraPos; + } + else if ("wind" == info_type) + { + new_value = gDisplayWindInfo; + } + else if ("fov" == info_type) + { + new_value = gDisplayFOV; + } + else if ("badge" == info_type) + { + new_value = gDisplayBadge; + } + return new_value; + } }; @@ -723,11 +723,11 @@ class LLAdvancedCheckHUDInfo : public view_listener_t class LLAdvancedClearGroupCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLGroupMgr::debugClearAllGroups(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLGroupMgr::debugClearAllGroups(NULL); + return true; + } }; @@ -738,97 +738,97 @@ class LLAdvancedClearGroupCache : public view_listener_t ///////////////// U32 render_type_from_string(std::string render_type) { - if ("simple" == render_type) - { - return LLPipeline::RENDER_TYPE_SIMPLE; - } - else if ("alpha" == render_type) - { - return LLPipeline::RENDER_TYPE_ALPHA; - } - else if ("tree" == render_type) - { - return LLPipeline::RENDER_TYPE_TREE; - } - else if ("character" == render_type) - { - return LLPipeline::RENDER_TYPE_AVATAR; - } - else if ("controlAV" == render_type) // Animesh - { - return LLPipeline::RENDER_TYPE_CONTROL_AV; - } - else if ("surfacePatch" == render_type) - { - return LLPipeline::RENDER_TYPE_TERRAIN; - } - else if ("sky" == render_type) - { - return LLPipeline::RENDER_TYPE_SKY; - } - else if ("water" == render_type) - { - return LLPipeline::RENDER_TYPE_WATER; - } - else if ("volume" == render_type) - { - return LLPipeline::RENDER_TYPE_VOLUME; - } - else if ("grass" == render_type) - { - return LLPipeline::RENDER_TYPE_GRASS; - } - else if ("clouds" == render_type) - { - return LLPipeline::RENDER_TYPE_CLOUDS; - } - else if ("particles" == render_type) - { - return LLPipeline::RENDER_TYPE_PARTICLES; - } - else if ("bump" == render_type) - { - return LLPipeline::RENDER_TYPE_BUMP; - } - else if ("pbr" == render_type) + if ("simple" == render_type) + { + return LLPipeline::RENDER_TYPE_SIMPLE; + } + else if ("alpha" == render_type) + { + return LLPipeline::RENDER_TYPE_ALPHA; + } + else if ("tree" == render_type) + { + return LLPipeline::RENDER_TYPE_TREE; + } + else if ("character" == render_type) + { + return LLPipeline::RENDER_TYPE_AVATAR; + } + else if ("controlAV" == render_type) // Animesh + { + return LLPipeline::RENDER_TYPE_CONTROL_AV; + } + else if ("surfacePatch" == render_type) + { + return LLPipeline::RENDER_TYPE_TERRAIN; + } + else if ("sky" == render_type) + { + return LLPipeline::RENDER_TYPE_SKY; + } + else if ("water" == render_type) + { + return LLPipeline::RENDER_TYPE_WATER; + } + else if ("volume" == render_type) + { + return LLPipeline::RENDER_TYPE_VOLUME; + } + else if ("grass" == render_type) + { + return LLPipeline::RENDER_TYPE_GRASS; + } + else if ("clouds" == render_type) + { + return LLPipeline::RENDER_TYPE_CLOUDS; + } + else if ("particles" == render_type) + { + return LLPipeline::RENDER_TYPE_PARTICLES; + } + else if ("bump" == render_type) + { + return LLPipeline::RENDER_TYPE_BUMP; + } + else if ("pbr" == render_type) { return LLPipeline::RENDER_TYPE_GLTF_PBR; } - else - { - return 0; - } + else + { + return 0; + } } class LLAdvancedToggleRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - if ( render_type != 0 ) - { - LLPipeline::toggleRenderTypeControl( render_type ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + if ( render_type != 0 ) + { + LLPipeline::toggleRenderTypeControl( render_type ); + } + return true; + } }; class LLAdvancedCheckRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - bool new_value = false; + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + bool new_value = false; - if ( render_type != 0 ) - { - new_value = LLPipeline::hasRenderTypeControl( render_type ); - } + if ( render_type != 0 ) + { + new_value = LLPipeline::hasRenderTypeControl( render_type ); + } - return new_value; - } + return new_value; + } }; @@ -836,140 +836,140 @@ class LLAdvancedCheckRenderType : public view_listener_t // FEATURE // ///////////// U32 feature_from_string(std::string feature) -{ - if ("ui" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_UI; - } - else if ("selected" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; - } - else if ("highlighted" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; - } - else if ("dynamic textures" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; - } - else if ("foot shadows" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; - } - else if ("fog" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOG; - } - else if ("fr info" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; - } - else if ("flexible" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; - } - else - { - return 0; - } +{ + if ("ui" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_UI; + } + else if ("selected" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; + } + else if ("highlighted" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; + } + else if ("dynamic textures" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; + } + else if ("foot shadows" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; + } + else if ("fog" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOG; + } + else if ("fr info" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; + } + else if ("flexible" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; + } + else + { + return 0; + } }; class LLAdvancedToggleFeature : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 feature = feature_from_string( userdata.asString() ); - if ( feature != 0 ) - { - LLPipeline::toggleRenderDebugFeature( feature ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 feature = feature_from_string( userdata.asString() ); + if ( feature != 0 ) + { + LLPipeline::toggleRenderDebugFeature( feature ); + } + return true; + } }; class LLAdvancedCheckFeature : public view_listener_t { - bool handleEvent(const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - U32 feature = feature_from_string( userdata.asString() ); - bool new_value = false; + U32 feature = feature_from_string( userdata.asString() ); + bool new_value = false; - if ( feature != 0 ) - { - new_value = LLPipeline::toggleRenderDebugFeatureControl( feature ); - } + if ( feature != 0 ) + { + new_value = LLPipeline::toggleRenderDebugFeatureControl( feature ); + } - return new_value; + return new_value; } }; class LLAdvancedCheckDisplayTextureDensity : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string mode = userdata.asString(); - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) - { - return mode == "none"; - } - if (mode == "current") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_CURRENT; - } - else if (mode == "desired") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_DESIRED; - } - else if (mode == "full") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_FULL; - } - return false; - } + bool handleEvent(const LLSD& userdata) + { + std::string mode = userdata.asString(); + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) + { + return mode == "none"; + } + if (mode == "current") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_CURRENT; + } + else if (mode == "desired") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_DESIRED; + } + else if (mode == "full") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_FULL; + } + return false; + } }; class LLAdvancedSetDisplayTextureDensity : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string mode = userdata.asString(); - if (mode == "none") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == TRUE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; - } - else if (mode == "current") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_CURRENT; - } - else if (mode == "desired") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY, true); - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_DESIRED; - } - else if (mode == "full") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_FULL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string mode = userdata.asString(); + if (mode == "none") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == TRUE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; + } + else if (mode == "current") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_CURRENT; + } + else if (mode == "desired") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY, true); + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_DESIRED; + } + else if (mode == "full") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_FULL; + } + return true; + } }; @@ -978,232 +978,232 @@ class LLAdvancedSetDisplayTextureDensity : public view_listener_t ////////////////// U64 info_display_from_string(std::string info_display) { - if ("verify" == info_display) - { - return LLPipeline::RENDER_DEBUG_VERIFY; - } - else if ("bboxes" == info_display) - { - return LLPipeline::RENDER_DEBUG_BBOXES; - } - else if ("normals" == info_display) - { - return LLPipeline::RENDER_DEBUG_NORMALS; - } - else if ("points" == info_display) - { - return LLPipeline::RENDER_DEBUG_POINTS; - } - else if ("octree" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCTREE; - } - else if ("shadow frusta" == info_display) - { - return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; - } - else if ("physics shapes" == info_display) - { - return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; - } - else if ("occlusion" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCCLUSION; - } - else if ("render batches" == info_display) - { - return LLPipeline::RENDER_DEBUG_BATCH_SIZE; - } - else if ("update type" == info_display) - { - return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; - } - else if ("texture anim" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; - } - else if ("texture priority" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; - } - else if ("texture area" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; - } - else if ("face area" == info_display) - { - return LLPipeline::RENDER_DEBUG_FACE_AREA; - } - else if ("lod info" == info_display) - { - return LLPipeline::RENDER_DEBUG_LOD_INFO; - } - else if ("lights" == info_display) - { - return LLPipeline::RENDER_DEBUG_LIGHTS; - } - else if ("particles" == info_display) - { - return LLPipeline::RENDER_DEBUG_PARTICLES; - } - else if ("composition" == info_display) - { - return LLPipeline::RENDER_DEBUG_COMPOSITION; - } - else if ("avatardrawinfo" == info_display) - { - return (LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO); - } - else if ("glow" == info_display) - { - return LLPipeline::RENDER_DEBUG_GLOW; - } - else if ("collision skeleton" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; - } - else if ("joints" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS; - } - else if ("raycast" == info_display) - { - return LLPipeline::RENDER_DEBUG_RAYCAST; - } - else if ("agent target" == info_display) - { - return LLPipeline::RENDER_DEBUG_AGENT_TARGET; - } - else if ("sculpt" == info_display) - { - return LLPipeline::RENDER_DEBUG_SCULPTED; - } - else if ("wind vectors" == info_display) - { - return LLPipeline::RENDER_DEBUG_WIND_VECTORS; - } - else if ("texel density" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY; - } - else if ("triangle count" == info_display) - { - return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; - } - else if ("impostors" == info_display) - { - return LLPipeline::RENDER_DEBUG_IMPOSTORS; - } - else if ("reflection probes" == info_display) + if ("verify" == info_display) { - return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + return LLPipeline::RENDER_DEBUG_VERIFY; } - else if ("probe updates" == info_display) + else if ("bboxes" == info_display) { - return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; + return LLPipeline::RENDER_DEBUG_BBOXES; } - else - { - LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; - return 0; - } -}; - -class LLAdvancedToggleInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U64 info_display = info_display_from_string( userdata.asString() ); - - LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; - - if ( info_display != 0 ) - { - LLPipeline::toggleRenderDebug( info_display ); - } - - return true; - } -}; - - -class LLAdvancedCheckInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U64 info_display = info_display_from_string( userdata.asString() ); - bool new_value = false; - - if ( info_display != 0 ) - { - new_value = LLPipeline::toggleRenderDebugControl( info_display ); - } - - return new_value; - } -}; - - -/////////////////////////// -//// RANDOMIZE FRAMERATE // -/////////////////////////// - - -class LLAdvancedToggleRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gRandomizeFramerate = !(gRandomizeFramerate); - return true; - } -}; - -class LLAdvancedCheckRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gRandomizeFramerate; - return new_value; - } -}; - -/////////////////////////// -//// PERIODIC SLOW FRAME // -/////////////////////////// - - -class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gPeriodicSlowFrame = !(gPeriodicSlowFrame); - return true; - } -}; - -class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gPeriodicSlowFrame; - return new_value; - } -}; - - -/////////////////////////// -// SELECTED TEXTURE INFO // -// + else if ("normals" == info_display) + { + return LLPipeline::RENDER_DEBUG_NORMALS; + } + else if ("points" == info_display) + { + return LLPipeline::RENDER_DEBUG_POINTS; + } + else if ("octree" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCTREE; + } + else if ("shadow frusta" == info_display) + { + return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; + } + else if ("physics shapes" == info_display) + { + return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; + } + else if ("occlusion" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCCLUSION; + } + else if ("render batches" == info_display) + { + return LLPipeline::RENDER_DEBUG_BATCH_SIZE; + } + else if ("update type" == info_display) + { + return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; + } + else if ("texture anim" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; + } + else if ("texture priority" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; + } + else if ("texture area" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; + } + else if ("face area" == info_display) + { + return LLPipeline::RENDER_DEBUG_FACE_AREA; + } + else if ("lod info" == info_display) + { + return LLPipeline::RENDER_DEBUG_LOD_INFO; + } + else if ("lights" == info_display) + { + return LLPipeline::RENDER_DEBUG_LIGHTS; + } + else if ("particles" == info_display) + { + return LLPipeline::RENDER_DEBUG_PARTICLES; + } + else if ("composition" == info_display) + { + return LLPipeline::RENDER_DEBUG_COMPOSITION; + } + else if ("avatardrawinfo" == info_display) + { + return (LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO); + } + else if ("glow" == info_display) + { + return LLPipeline::RENDER_DEBUG_GLOW; + } + else if ("collision skeleton" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; + } + else if ("joints" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS; + } + else if ("raycast" == info_display) + { + return LLPipeline::RENDER_DEBUG_RAYCAST; + } + else if ("agent target" == info_display) + { + return LLPipeline::RENDER_DEBUG_AGENT_TARGET; + } + else if ("sculpt" == info_display) + { + return LLPipeline::RENDER_DEBUG_SCULPTED; + } + else if ("wind vectors" == info_display) + { + return LLPipeline::RENDER_DEBUG_WIND_VECTORS; + } + else if ("texel density" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY; + } + else if ("triangle count" == info_display) + { + return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; + } + else if ("impostors" == info_display) + { + return LLPipeline::RENDER_DEBUG_IMPOSTORS; + } + else if ("reflection probes" == info_display) + { + return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + } + else if ("probe updates" == info_display) + { + return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; + } + else + { + LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; + return 0; + } +}; + +class LLAdvancedToggleInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); + + LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; + + if ( info_display != 0 ) + { + LLPipeline::toggleRenderDebug( info_display ); + } + + return true; + } +}; + + +class LLAdvancedCheckInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); + bool new_value = false; + + if ( info_display != 0 ) + { + new_value = LLPipeline::toggleRenderDebugControl( info_display ); + } + + return new_value; + } +}; + + +/////////////////////////// +//// RANDOMIZE FRAMERATE // +/////////////////////////// + + +class LLAdvancedToggleRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gRandomizeFramerate = !(gRandomizeFramerate); + return true; + } +}; + +class LLAdvancedCheckRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gRandomizeFramerate; + return new_value; + } +}; + +/////////////////////////// +//// PERIODIC SLOW FRAME // +/////////////////////////// + + +class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gPeriodicSlowFrame = !(gPeriodicSlowFrame); + return true; + } +}; + +class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gPeriodicSlowFrame; + return new_value; + } +}; + + +/////////////////////////// +// SELECTED TEXTURE INFO // +// /////////////////////////// class LLAdvancedSelectedTextureInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_selected_texture_info(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_selected_texture_info(NULL); + return true; + } }; ////////////////////// @@ -1212,33 +1212,33 @@ class LLAdvancedSelectedTextureInfo : public view_listener_t class LLAdvancedToggleWireframe : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gUseWireframe = !(gUseWireframe); + bool handleEvent(const LLSD& userdata) + { + gUseWireframe = !(gUseWireframe); - return true; - } + return true; + } }; class LLAdvancedCheckWireframe : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gUseWireframe; - } + bool handleEvent(const LLSD& userdata) + { + return gUseWireframe; + } }; - + ////////////////////////// // DUMP SCRIPTED CAMERA // ////////////////////////// - + class LLAdvancedDumpScriptedCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_followcam(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_dump_followcam(NULL); + return true; } }; @@ -1251,11 +1251,11 @@ class LLAdvancedDumpScriptedCamera : public view_listener_t class LLAdvancedDumpRegionObjectCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_region_object_cache(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_dump_region_object_cache(NULL); + return true; + } }; class LLAdvancedToggleInterestList360Mode : public view_listener_t @@ -1266,22 +1266,22 @@ public: // Toggle the mode - regions will get updated if (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360) { - gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); - } - else - { - gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); - } + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); + } + else + { + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); + } return true; } }; class LLAdvancedCheckInterestList360Mode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); + } }; class LLAdvancedToggleStatsRecorder : public view_listener_t @@ -1289,13 +1289,13 @@ class LLAdvancedToggleStatsRecorder : public view_listener_t bool handleEvent(const LLSD &userdata) { if (LLViewerStatsRecorder::instance().isEnabled()) - { // Turn off both recording and logging - LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); - } - else - { // Turn on both recording and logging - LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); - } + { // Turn off both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); + } + else + { // Turn on both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); + } return true; } }; @@ -1303,7 +1303,7 @@ class LLAdvancedToggleStatsRecorder : public view_listener_t class LLAdvancedCheckStatsRecorder : public view_listener_t { bool handleEvent(const LLSD &userdata) - { // Use the logging state as the indicator of whether the stats recorder is on + { // Use the logging state as the indicator of whether the stats recorder is on return LLViewerStatsRecorder::instance().isLogging(); } }; @@ -1311,7 +1311,7 @@ class LLAdvancedCheckStatsRecorder : public view_listener_t class LLAdvancedResetInterestLists : public view_listener_t { bool handleEvent(const LLSD &userdata) - { // Reset all region interest lists + { // Reset all region interest lists handle_reset_interest_lists(NULL); return true; } @@ -1319,12 +1319,12 @@ class LLAdvancedResetInterestLists : public view_listener_t class LLAdvancedBuyCurrencyTest : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - handle_buy_currency_test(NULL); - return true; - } + { + bool handleEvent(const LLSD& userdata) + { + handle_buy_currency_test(NULL); + return true; + } }; @@ -1335,11 +1335,11 @@ class LLAdvancedBuyCurrencyTest : public view_listener_t class LLAdvancedDumpSelectMgr : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - dump_select_mgr(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + dump_select_mgr(NULL); + return true; + } }; @@ -1351,11 +1351,11 @@ class LLAdvancedDumpSelectMgr : public view_listener_t class LLAdvancedDumpInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - dump_inventory(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + dump_inventory(NULL); + return true; + } }; @@ -1367,11 +1367,11 @@ class LLAdvancedDumpInventory : public view_listener_t class LLAdvancedPrintSelectedObjectInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - print_object_info(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + print_object_info(NULL); + return true; + } }; @@ -1383,11 +1383,11 @@ class LLAdvancedPrintSelectedObjectInfo : public view_listener_t class LLAdvancedPrintAgentInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - print_agent_nvpairs(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + print_agent_nvpairs(NULL); + return true; + } }; ////////////////// @@ -1397,20 +1397,20 @@ class LLAdvancedPrintAgentInfo : public view_listener_t class LLAdvancedToggleDebugClicks : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugClicks = !(gDebugClicks); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugClicks = !(gDebugClicks); + return true; + } }; class LLAdvancedCheckDebugClicks : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugClicks; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugClicks; + return new_value; + } }; @@ -1422,20 +1422,20 @@ class LLAdvancedCheckDebugClicks : public view_listener_t class LLAdvancedToggleDebugViews : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugRects = !(LLView::sDebugRects); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugRects = !(LLView::sDebugRects); + return true; + } }; class LLAdvancedCheckDebugViews : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugRects; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugRects; + return new_value; + } }; @@ -1447,19 +1447,19 @@ class LLAdvancedCheckDebugViews : public view_listener_t class LLAdvancedToggleDebugUnicode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugUnicode = !(LLView::sDebugUnicode); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugUnicode = !(LLView::sDebugUnicode); + return true; + } }; class LLAdvancedCheckDebugUnicode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return LLView::sDebugUnicode; - } + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugUnicode; + } }; @@ -1471,20 +1471,20 @@ class LLAdvancedCheckDebugUnicode : public view_listener_t class LLAdvancedToggleDebugCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugCamera = !(LLView::sDebugCamera); - LLFloaterCamera::onDebugCameraToggled(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugCamera = !(LLView::sDebugCamera); + LLFloaterCamera::onDebugCameraToggled(); + return true; + } }; class LLAdvancedCheckDebugCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return LLView::sDebugCamera; - } + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugCamera; + } }; @@ -1496,20 +1496,20 @@ class LLAdvancedCheckDebugCamera : public view_listener_t class LLAdvancedToggleXUINameTooltips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } }; class LLAdvancedCheckXUINameTooltips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } }; @@ -1521,20 +1521,20 @@ class LLAdvancedCheckXUINameTooltips : public view_listener_t class LLAdvancedToggleDebugMouseEvents : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); + return true; + } }; class LLAdvancedCheckDebugMouseEvents : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugMouseHandling; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugMouseHandling; + return new_value; + } }; @@ -1546,22 +1546,22 @@ class LLAdvancedCheckDebugMouseEvents : public view_listener_t class LLAdvancedToggleDebugKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugKeys = !(LLView::sDebugKeys); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugKeys = !(LLView::sDebugKeys); + return true; + } }; - + class LLAdvancedCheckDebugKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugKeys; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugKeys; + return new_value; + } }; - + /////////////////////// @@ -1571,30 +1571,30 @@ class LLAdvancedCheckDebugKeys : public view_listener_t class LLAdvancedToggleDebugWindowProc : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugWindowProc = !(gDebugWindowProc); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugWindowProc = !(gDebugWindowProc); + return true; + } }; class LLAdvancedCheckDebugWindowProc : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugWindowProc; - return new_value; - } + { + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugWindowProc; + return new_value; + } }; // ------------------------------XUI MENU --------------------------- class LLAdvancedSendTestIms : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLIMModel::instance().testMessages(); - return true; + bool handleEvent(const LLSD& userdata) + { + LLIMModel::instance().testMessages(); + return true; } }; @@ -1606,22 +1606,22 @@ class LLAdvancedSendTestIms : public view_listener_t class LLAdvancedToggleXUINames : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } }; class LLAdvancedCheckXUINames : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } -}; - + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } +}; + //////////////////////// // GRAB BAKED TEXTURE // @@ -1630,71 +1630,71 @@ class LLAdvancedCheckXUINames : public view_listener_t class LLAdvancedGrabBakedTexture : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string texture_type = userdata.asString(); - if ("iris" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string texture_type = userdata.asString(); + if ("iris" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_EYES ); + } + else if ("head" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_HEAD ); + } + else if ("upper" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_UPPER ); + } + else if ("lower" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_LOWER ); + } + else if ("skirt" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_SKIRT ); + } + else if ("hair" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_HAIR ); + } + + return true; + } }; class LLAdvancedEnableGrabBakedTexture : public view_listener_t { - bool handleEvent(const LLSD& userdata) -{ - std::string texture_type = userdata.asString(); - bool new_value = false; - - if ("iris" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return new_value; + bool handleEvent(const LLSD& userdata) +{ + std::string texture_type = userdata.asString(); + bool new_value = false; + + if ("iris" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); + } + else if ("head" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); + } + else if ("upper" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); + } + else if ("lower" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); + } + else if ("skirt" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); + } + else if ("hair" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); + } + + return new_value; } }; @@ -1705,8 +1705,8 @@ class LLAdvancedEnableGrabBakedTexture : public view_listener_t class LLAdvancedEnableAppearanceToXML : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (obj && obj->isAnimatedObject() && obj->getControlAvatar()) { @@ -1721,18 +1721,18 @@ class LLAdvancedEnableAppearanceToXML : public view_listener_t // This has to be a non-control avatar, because control avs are invisible and unclickable. return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); } - else - { - return false; - } - } + else + { + return false; + } + } }; class LLAdvancedAppearanceToXML : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string emptyname; + bool handleEvent(const LLSD& userdata) + { + std::string emptyname; LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar *avatar = NULL; if (obj) @@ -1755,14 +1755,14 @@ class LLAdvancedAppearanceToXML : public view_listener_t else { // If no selection, use the self avatar. - avatar = gAgentAvatarp; + avatar = gAgentAvatarp; } if (avatar) { avatar->dumpArchetypeXML(emptyname); } - return true; - } + return true; + } }; @@ -1774,44 +1774,44 @@ class LLAdvancedAppearanceToXML : public view_listener_t class LLAdvancedToggleCharacterGeometry : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_god_request_avatar_geometry(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_god_request_avatar_geometry(NULL); + return true; } }; - ///////////////////////////// + ///////////////////////////// // TEST MALE / TEST FEMALE // ///////////////////////////// class LLAdvancedTestMale : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_test_male(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_test_male(NULL); + return true; + } }; class LLAdvancedTestFemale : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_test_female(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_test_female(NULL); + return true; + } }; class LLAdvancedForceParamsToDefault : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAgent::clearVisualParams(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAgent::clearVisualParams(NULL); + return true; + } }; @@ -1820,47 +1820,47 @@ class LLAdvancedForceParamsToDefault : public view_listener_t ////////////////////////// // Utility function to set all AV time factors to the same global value -static void set_all_animation_time_factors(F32 time_factor) +static void set_all_animation_time_factors(F32 time_factor) { - LLMotionController::setCurrentTimeFactor(time_factor); - for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - (*iter)->setAnimTimeFactor(time_factor); - } + LLMotionController::setCurrentTimeFactor(time_factor); + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + (*iter)->setAnimTimeFactor(time_factor); + } } class LLAdvancedAnimTenFaster : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //LL_INFOS() << "LLAdvancedAnimTenFaster" << LL_ENDL; - F32 time_factor = LLMotionController::getCurrentTimeFactor(); - time_factor = llmin(time_factor + 0.1f, 2.f); // Upper limit is 200% speed - set_all_animation_time_factors(time_factor); - return true; - } + bool handleEvent(const LLSD& userdata) + { + //LL_INFOS() << "LLAdvancedAnimTenFaster" << LL_ENDL; + F32 time_factor = LLMotionController::getCurrentTimeFactor(); + time_factor = llmin(time_factor + 0.1f, 2.f); // Upper limit is 200% speed + set_all_animation_time_factors(time_factor); + return true; + } }; class LLAdvancedAnimTenSlower : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //LL_INFOS() << "LLAdvancedAnimTenSlower" << LL_ENDL; - F32 time_factor = LLMotionController::getCurrentTimeFactor(); - time_factor = llmax(time_factor - 0.1f, 0.1f); // Lower limit is at 10% of normal speed - set_all_animation_time_factors(time_factor); - return true; - } + bool handleEvent(const LLSD& userdata) + { + //LL_INFOS() << "LLAdvancedAnimTenSlower" << LL_ENDL; + F32 time_factor = LLMotionController::getCurrentTimeFactor(); + time_factor = llmax(time_factor - 0.1f, 0.1f); // Lower limit is at 10% of normal speed + set_all_animation_time_factors(time_factor); + return true; + } }; class LLAdvancedAnimResetAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - set_all_animation_time_factors(1.f); - return true; - } + bool handleEvent(const LLSD& userdata) + { + set_all_animation_time_factors(1.f); + return true; + } }; @@ -1871,11 +1871,11 @@ class LLAdvancedAnimResetAll : public view_listener_t class LLAdvancedReloadVertexShader : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - reload_vertex_shader(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + reload_vertex_shader(NULL); + return true; + } }; @@ -1887,20 +1887,20 @@ class LLAdvancedReloadVertexShader : public view_listener_t class LLAdvancedToggleAnimationInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); + return true; + } }; class LLAdvancedCheckAnimationInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sShowAnimationDebug; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sShowAnimationDebug; + return new_value; + } }; @@ -1911,20 +1911,20 @@ class LLAdvancedCheckAnimationInfo : public view_listener_t class LLAdvancedToggleShowLookAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); + return true; + } }; class LLAdvancedCheckShowLookAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectLookAt::sDebugLookAt; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectLookAt::sDebugLookAt; + return new_value; + } }; @@ -1936,20 +1936,20 @@ class LLAdvancedCheckShowLookAt : public view_listener_t class LLAdvancedToggleShowPointAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); + return true; + } }; class LLAdvancedCheckShowPointAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectPointAt::sDebugPointAt; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectPointAt::sDebugPointAt; + return new_value; + } }; @@ -1961,20 +1961,20 @@ class LLAdvancedCheckShowPointAt : public view_listener_t class LLAdvancedToggleDebugJointUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); + return true; + } }; class LLAdvancedCheckDebugJointUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sJointDebug; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sJointDebug; + return new_value; + } }; @@ -1986,20 +1986,20 @@ class LLAdvancedCheckDebugJointUpdates : public view_listener_t class LLAdvancedToggleDisableLOD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); + return true; + } }; - + class LLAdvancedCheckDisableLOD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoint::sDisableLOD; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoint::sDisableLOD; + return new_value; + } }; @@ -2011,20 +2011,20 @@ class LLAdvancedCheckDisableLOD : public view_listener_t class LLAdvancedToggleDebugCharacterVis : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); + return true; + } }; class LLAdvancedCheckDebugCharacterVis : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sDebugInvisible; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sDebugInvisible; + return new_value; + } }; @@ -2032,33 +2032,33 @@ class LLAdvancedCheckDebugCharacterVis : public view_listener_t // DUMP ATTACHMENTS // ////////////////////// - + class LLAdvancedDumpAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_attachments(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_dump_attachments(NULL); + return true; + } }; - + ///////////////////// // REBAKE TEXTURES // ///////////////////// - - + + class LLAdvancedRebakeTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_rebake_textures(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_rebake_textures(NULL); + return true; + } }; - - + + #if 1 //ndef LL_RELEASE_FOR_DOWNLOAD /////////////////////////// // DEBUG AVATAR TEXTURES // @@ -2067,14 +2067,14 @@ class LLAdvancedRebakeTextures : public view_listener_t class LLAdvancedDebugAvatarTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isGodlike()) - { - handle_debug_avatar_textures(NULL); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.isGodlike()) + { + handle_debug_avatar_textures(NULL); + } + return true; + } }; //////////////////////////////// @@ -2084,17 +2084,17 @@ class LLAdvancedDebugAvatarTextures : public view_listener_t class LLAdvancedDumpAvatarLocalTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { #ifndef LL_RELEASE_FOR_DOWNLOAD - handle_dump_avatar_local_textures(NULL); + handle_dump_avatar_local_textures(NULL); #endif - return true; - } + return true; + } }; #endif - + ///////////////// // MESSAGE LOG // ///////////////// @@ -2102,20 +2102,20 @@ class LLAdvancedDumpAvatarLocalTextures : public view_listener_t class LLAdvancedEnableMessageLog : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_viewer_enable_message_log(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_viewer_enable_message_log(NULL); + return true; + } }; class LLAdvancedDisableMessageLog : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_viewer_disable_message_log(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_viewer_disable_message_log(NULL); + return true; + } }; ///////////////// @@ -2125,11 +2125,11 @@ class LLAdvancedDisableMessageLog : public view_listener_t class LLAdvancedDropPacket : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gMessageSystem->mPacketRing.dropPackets(1); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gMessageSystem->mPacketRing.dropPackets(1); + return true; + } }; ////////////////////// @@ -2139,8 +2139,8 @@ class LLAdvancedDropPacket : public view_listener_t class LLAdvancedPurgeDiskCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General"); llassert_always(main_queue); @@ -2154,8 +2154,8 @@ class LLAdvancedPurgeDiskCache : public view_listener_t }, [](){}); // Callback to main thread is empty as there is nothing left to do - return true; - } + return true; + } }; @@ -2166,12 +2166,12 @@ class LLAdvancedPurgeDiskCache : public view_listener_t class LLAdvancedPurgeShaderCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerShaderMgr::instance()->clearShaderCache(); - LLViewerShaderMgr::instance()->setShaders(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerShaderMgr::instance()->clearShaderCache(); + LLViewerShaderMgr::instance()->setShaders(); + return true; + } }; //////////////////// @@ -2181,32 +2181,32 @@ class LLAdvancedPurgeShaderCache : public view_listener_t class LLAdvancedViewerEventRecorder : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - LL_INFOS() << "Event Playback starting" << LL_ENDL; - LLViewerEventRecorder::instance().playbackRecording(); - LL_INFOS() << "Event Playback completed" << LL_ENDL; - } - else if ("stop playback" == command) - { - // Future - } - else if ("start recording" == command) - { - LLViewerEventRecorder::instance().setEventLoggingOn(); - LL_INFOS() << "Event recording started" << LL_ENDL; - } - else if ("stop recording" == command) - { - LLViewerEventRecorder::instance().setEventLoggingOff(); - LL_INFOS() << "Event recording stopped" << LL_ENDL; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + LL_INFOS() << "Event Playback starting" << LL_ENDL; + LLViewerEventRecorder::instance().playbackRecording(); + LL_INFOS() << "Event Playback completed" << LL_ENDL; + } + else if ("stop playback" == command) + { + // Future + } + else if ("start recording" == command) + { + LLViewerEventRecorder::instance().setEventLoggingOn(); + LL_INFOS() << "Event recording started" << LL_ENDL; + } + else if ("stop recording" == command) + { + LLViewerEventRecorder::instance().setEventLoggingOff(); + LL_INFOS() << "Event recording stopped" << LL_ENDL; + } + + return true; + } }; @@ -2219,29 +2219,29 @@ class LLAdvancedViewerEventRecorder : public view_listener_t class LLAdvancedAgentPilot : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - gAgentPilot.setNumRuns(-1); - gAgentPilot.startPlayback(); - } - else if ("stop playback" == command) - { - gAgentPilot.stopPlayback(); - } - else if ("start record" == command) - { - gAgentPilot.startRecord(); - } - else if ("stop record" == command) - { - gAgentPilot.stopRecord(); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + gAgentPilot.setNumRuns(-1); + gAgentPilot.startPlayback(); + } + else if ("stop playback" == command) + { + gAgentPilot.stopPlayback(); + } + else if ("start record" == command) + { + gAgentPilot.startRecord(); + } + else if ("stop record" == command) + { + gAgentPilot.stopRecord(); + } + + return true; + } }; @@ -2253,20 +2253,20 @@ class LLAdvancedAgentPilot : public view_listener_t class LLAdvancedToggleAgentPilotLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgentPilot.setLoop(!gAgentPilot.getLoop()); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgentPilot.setLoop(!gAgentPilot.getLoop()); + return true; + } }; class LLAdvancedCheckAgentPilotLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentPilot.getLoop(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgentPilot.getLoop(); + return new_value; + } }; @@ -2277,20 +2277,20 @@ class LLAdvancedCheckAgentPilotLoop : public view_listener_t class LLAdvancedToggleShowObjectUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gShowObjectUpdates = !(gShowObjectUpdates); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gShowObjectUpdates = !(gShowObjectUpdates); + return true; + } }; class LLAdvancedCheckShowObjectUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gShowObjectUpdates; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gShowObjectUpdates; + return new_value; + } }; @@ -2302,11 +2302,11 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t class LLAdvancedCompressImage : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_compress_image(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_compress_image(NULL); + return true; + } }; @@ -2332,11 +2332,11 @@ class LLAdvancedCompressFileTest : public view_listener_t class LLAdvancedShowDebugSettings : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("settings_debug",userdata); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("settings_debug",userdata); + return true; + } }; @@ -2347,40 +2347,40 @@ class LLAdvancedShowDebugSettings : public view_listener_t class LLAdvancedEnableViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // Don't enable in god mode since the admin menu is shown anyway. - // Only enable if the user has set the appropriate debug setting. - bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // Don't enable in god mode since the admin menu is shown anyway. + // Only enable if the user has set the appropriate debug setting. + bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); + return new_value; + } }; class LLAdvancedToggleViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_admin_override_toggle(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_admin_override_toggle(NULL); + return true; + } }; class LLAdvancedToggleVisualLeakDetector : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_visual_leak_detector_toggle(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_visual_leak_detector_toggle(NULL); + return true; + } }; class LLAdvancedCheckViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); + return new_value; + } }; ////////////////// @@ -2390,20 +2390,20 @@ class LLAdvancedCheckViewAdminOptions : public view_listener_t class LLAdvancedRequestAdminStatus : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_god_mode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_god_mode(NULL); + return true; + } }; class LLAdvancedLeaveAdminStatus : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_leave_god_mode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_leave_god_mode(NULL); + return true; + } }; ////////////////////////// @@ -2412,20 +2412,20 @@ class LLAdvancedLeaveAdminStatus : public view_listener_t class LLAdvancedForceErrorBreakpoint : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_breakpoint(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_breakpoint(NULL); + return true; + } }; class LLAdvancedForceErrorLlerror : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_llerror(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_llerror(NULL); + return true; + } }; class LLAdvancedForceErrorLlerrorMsg: public view_listener_t @@ -2439,11 +2439,11 @@ class LLAdvancedForceErrorLlerrorMsg: public view_listener_t class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_bad_memory_access(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_bad_memory_access(NULL); + return true; + } }; class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t @@ -2464,20 +2464,20 @@ class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t class LLAdvancedForceErrorInfiniteLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_infinite_loop(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_infinite_loop(NULL); + return true; + } }; class LLAdvancedForceErrorSoftwareException : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_software_exception(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_software_exception(NULL); + return true; + } }; class LLAdvancedForceOSException: public view_listener_t @@ -2507,11 +2507,11 @@ class LLAdvancedForceErrorSoftwareExceptionCoro : public view_listener_t class LLAdvancedForceErrorDriverCrash : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_driver_crash(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_driver_crash(NULL); + return true; + } }; class LLAdvancedForceErrorCoroutineCrash : public view_listener_t @@ -2534,10 +2534,10 @@ class LLAdvancedForceErrorThreadCrash : public view_listener_t class LLAdvancedForceErrorDisconnectViewer : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_disconnect_viewer(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_disconnect_viewer(NULL); + return true; } }; @@ -2546,29 +2546,29 @@ class LLAdvancedForceErrorDisconnectViewer : public view_listener_t class LLAdvancedHandleToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_toggle_hacked_godmode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_toggle_hacked_godmode(NULL); + return true; + } }; class LLAdvancedCheckToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - check_toggle_hacked_godmode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + check_toggle_hacked_godmode(NULL); + return true; + } }; class LLAdvancedEnableToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_toggle_hacked_godmode(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_toggle_hacked_godmode(NULL); + return new_value; + } }; #endif @@ -2585,21 +2585,21 @@ class LLAdvancedEnableToggleHackedGodmode : public view_listener_t class LLDevelopCheckLoggingLevel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 level = userdata.asInteger(); - return (static_cast<LLError::ELevel>(level) == LLError::getDefaultLevel()); - } + bool handleEvent(const LLSD& userdata) + { + U32 level = userdata.asInteger(); + return (static_cast<LLError::ELevel>(level) == LLError::getDefaultLevel()); + } }; class LLDevelopSetLoggingLevel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 level = userdata.asInteger(); - LLError::setDefaultLevel(static_cast<LLError::ELevel>(level)); - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 level = userdata.asInteger(); + LLError::setDefaultLevel(static_cast<LLError::ELevel>(level)); + return true; + } }; ////////////////// @@ -2609,100 +2609,100 @@ class LLDevelopSetLoggingLevel : public view_listener_t // Admin > Object class LLAdminForceTakeCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_take_copy(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_take_copy(NULL); + return true; + } }; class LLAdminHandleObjectOwnerSelf : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_self(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_owner_self(NULL); + return true; + } }; class LLAdminHandleObjectOwnerPermissive : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_permissive(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_owner_permissive(NULL); + return true; + } }; class LLAdminHandleForceDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_delete(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_delete(NULL); + return true; + } }; class LLAdminHandleObjectLock : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_lock(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_lock(NULL); + return true; + } }; class LLAdminHandleObjectAssetIDs: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_asset_ids(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_asset_ids(NULL); + return true; + } }; //Admin >Parcel class LLAdminHandleForceParcelOwnerToMe: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_owner_to_me(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_owner_to_me(NULL); + return true; + } }; class LLAdminHandleForceParcelToContent: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_to_content(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_to_content(NULL); + return true; + } }; class LLAdminHandleClaimPublicLand: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_claim_public_land(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_claim_public_land(NULL); + return true; + } }; // Admin > Region class LLAdminHandleRegionDumpTempAssetData: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_region_dump_temp_asset_data(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_region_dump_temp_asset_data(NULL); + return true; + } }; //Admin (Top Level) class LLAdminOnSaveState: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPanelRegionTools::onSaveState(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + LLPanelRegionTools::onSaveState(NULL); + return true; } }; @@ -2712,38 +2712,38 @@ class LLAdminOnSaveState: public view_listener_t //----------------------------------------------------------------------------- void cleanup_menus() { - delete gMenuParcelObserver; - gMenuParcelObserver = NULL; + delete gMenuParcelObserver; + gMenuParcelObserver = NULL; - delete gMenuAvatarSelf; - gMenuAvatarSelf = NULL; + delete gMenuAvatarSelf; + gMenuAvatarSelf = NULL; - delete gMenuAvatarOther; - gMenuAvatarOther = NULL; + delete gMenuAvatarOther; + gMenuAvatarOther = NULL; - delete gMenuObject; - gMenuObject = NULL; + delete gMenuObject; + gMenuObject = NULL; - delete gMenuAttachmentSelf; - gMenuAttachmentSelf = NULL; + delete gMenuAttachmentSelf; + gMenuAttachmentSelf = NULL; - delete gMenuAttachmentOther; - gMenuAttachmentSelf = NULL; + delete gMenuAttachmentOther; + gMenuAttachmentSelf = NULL; - delete gMenuLand; - gMenuLand = NULL; + delete gMenuLand; + gMenuLand = NULL; - delete gMenuMuteParticle; - gMenuMuteParticle = NULL; + delete gMenuMuteParticle; + gMenuMuteParticle = NULL; - delete gMenuBarView; - gMenuBarView = NULL; + delete gMenuBarView; + gMenuBarView = NULL; - delete gPopupMenuView; - gPopupMenuView = NULL; + delete gPopupMenuView; + gPopupMenuView = NULL; - delete gMenuHolder; - gMenuHolder = NULL; + delete gMenuHolder; + gMenuHolder = NULL; } //----------------------------------------------------------------------------- @@ -2752,40 +2752,40 @@ void cleanup_menus() class LLObjectReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReporter::showFromObject(objectp->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReporter::showFromObject(objectp->getID()); + } + return true; + } }; // Enabled it you clicked an object class LLObjectEnableReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; + return new_value; + } }; void handle_object_touch() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return; - LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLPickInfo pick = LLToolPie::getInstance()->getPick(); - // *NOTE: Hope the packets arrive safely and in order or else - // there will be some problems. - // *TODO: Just fix this bad assumption. - send_ObjectGrab_message(object, pick, LLVector3::zero); - send_ObjectDeGrab_message(object, pick); + // *NOTE: Hope the packets arrive safely and in order or else + // there will be some problems. + // *TODO: Just fix this bad assumption. + send_ObjectGrab_message(object, pick, LLVector3::zero); + send_ObjectDeGrab_message(object, pick); } void handle_object_show_original() @@ -2818,75 +2818,75 @@ void handle_object_show_original() static void init_default_item_label(LLUICtrl* ctrl) { - const std::string& item_name = ctrl->getName(); - boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); - if (it == sDefaultItemLabels.end()) - { - // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value - // (doesn't seem to matter much ATM). - LLStringExplicit default_label = ctrl->getValue().asString(); - if (!default_label.empty()) - { - sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); - } - } + const std::string& item_name = ctrl->getName(); + boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); + if (it == sDefaultItemLabels.end()) + { + // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value + // (doesn't seem to matter much ATM). + LLStringExplicit default_label = ctrl->getValue().asString(); + if (!default_label.empty()) + { + sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); + } + } } static LLStringExplicit get_default_item_label(const std::string& item_name) { - LLStringExplicit res(""); - boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); - if (it != sDefaultItemLabels.end()) - { - res = it->second; - } + LLStringExplicit res(""); + boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); + if (it != sDefaultItemLabels.end()) + { + res = it->second; + } - return res; + return res; } bool enable_object_touch(LLUICtrl* ctrl) { - bool new_value = false; - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (obj) - { - LLViewerObject* parent = (LLViewerObject*)obj->getParent(); - new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); - } + bool new_value = false; + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + LLViewerObject* parent = (LLViewerObject*)obj->getParent(); + new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); + } - init_default_item_label(ctrl); + init_default_item_label(ctrl); - // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mTouchName.empty()) - { - ctrl->setValue(node->mTouchName); - } - else - { - ctrl->setValue(get_default_item_label(ctrl->getName())); - } + // Update label based on the node touch name if available. + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mTouchName.empty()) + { + ctrl->setValue(node->mTouchName); + } + else + { + ctrl->setValue(get_default_item_label(ctrl->getName())); + } - return new_value; + return new_value; }; //void label_touch(std::string& label, void*) //{ -// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); -// if (node && node->mValid && !node->mTouchName.empty()) -// { -// label.assign(node->mTouchName); -// } -// else -// { -// label.assign("Touch"); -// } +// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); +// if (node && node->mValid && !node->mTouchName.empty()) +// { +// label.assign(node->mTouchName); +// } +// else +// { +// label.assign("Touch"); +// } //} void handle_object_open() { - LLFloaterReg::showInstance("openobject"); + LLFloaterReg::showInstance("openobject"); } bool enable_object_inspect() @@ -2941,67 +2941,67 @@ bool enable_object_edit_gltf_material() bool enable_object_open() { - // Look for contents in root object, which is all the LLFloaterOpenObject - // understands. - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!obj) return false; + // Look for contents in root object, which is all the LLFloaterOpenObject + // understands. + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!obj) return false; - LLViewerObject* root = obj->getRootEdit(); - if (!root) return false; + LLViewerObject* root = obj->getRootEdit(); + if (!root) return false; - return root->allowOpen(); + return root->allowOpen(); } class LLViewJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_toggle_flycam(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_toggle_flycam(); + return true; + } }; class LLViewCheckJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); + return new_value; + } }; void handle_toggle_flycam() { - LLViewerJoystick::getInstance()->toggleFlycam(); + LLViewerJoystick::getInstance()->toggleFlycam(); } class LLObjectBuild : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - - // Could be first use - //LLFirstUse::useBuild(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gAgentCamera.cameraZoomIn(0.666f); + gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } + + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + + // Could be first use + //LLFirstUse::useBuild(); + return true; + } }; void update_camera() @@ -3040,17 +3040,17 @@ void handle_object_edit() { update_camera(); - LLFloaterReg::showInstance("build"); - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); - - LLViewerJoystick::getInstance()->moveObjects(true); - LLViewerJoystick::getInstance()->setNeedsReset(true); - - // Could be first use - //LLFirstUse::useBuild(); - return; + LLFloaterReg::showInstance("build"); + + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); + + LLViewerJoystick::getInstance()->moveObjects(true); + LLViewerJoystick::getInstance()->setNeedsReset(true); + + // Could be first use + //LLFirstUse::useBuild(); + return; } void handle_object_edit_gltf_material() @@ -3072,68 +3072,68 @@ void handle_object_edit_gltf_material() void handle_attachment_edit(const LLUUID& inv_item_id) { - if (isAgentAvatarValid()) - { - if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) - { - LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); + if (isAgentAvatarValid()) + { + if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); - handle_object_edit(); - } - } + handle_object_edit(); + } + } } void handle_attachment_touch(const LLUUID& inv_item_id) { - if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) - { - if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) - { - LLSelectMgr::getInstance()->deselectAll(); - - LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); - if (!LLToolMgr::getInstance()->inBuildMode()) - { - struct SetTransient : public LLSelectedNodeFunctor - { - bool apply(LLSelectNode* node) - { - node->setTransient(TRUE); - return true; - } - } f; - sel->applyToNodes(&f); - } - - handle_object_touch(); - } - } + if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) + { + if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) + { + LLSelectMgr::getInstance()->deselectAll(); + + LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); + if (!LLToolMgr::getInstance()->inBuildMode()) + { + struct SetTransient : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + node->setTransient(TRUE); + return true; + } + } f; + sel->applyToNodes(&f); + } + + handle_object_touch(); + } + } } bool enable_attachment_touch(const LLUUID& inv_item_id) { - if (isAgentAvatarValid()) - { - const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); - return (attach_obj) && (attach_obj->flagHandleTouch()); - } - return false; + if (isAgentAvatarValid()) + { + const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); + return (attach_obj) && (attach_obj->flagHandleTouch()); + } + return false; } void handle_object_inspect() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* selected_objectp = selection->getFirstRootObject(); - if (selected_objectp) - { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* selected_objectp = selection->getFirstRootObject(); + if (selected_objectp) + { LLFloaterReg::showInstance("task_properties"); - } - - /* - // Old floater properties - LLFloaterReg::showInstance("inspect", LLSD()); - */ + } + + /* + // Old floater properties + LLFloaterReg::showInstance("inspect", LLSD()); + */ } //--------------------------------------------------------------------------- @@ -3141,133 +3141,133 @@ void handle_object_inspect() //--------------------------------------------------------------------------- class LLLandBuild : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerParcelMgr::getInstance()->deselectLand(); + bool handleEvent(const LLSD& userdata) + { + LLViewerParcelMgr::getInstance()->deselectLand(); - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - // otherwise just move focus - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } + if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gAgentCamera.cameraZoomIn(0.666f); + gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + // otherwise just move focus + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - // Could be first use - //LLFirstUse::useBuild(); - return true; - } + // Could be first use + //LLFirstUse::useBuild(); + return true; + } }; class LLLandBuyPass : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPanelLandGeneral::onClickBuyPass((void *)FALSE); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLPanelLandGeneral::onClickBuyPass((void *)FALSE); + return true; + } }; class LLLandEnableBuyPass : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); + return new_value; + } }; // BUG: Should really check if CLICK POINT is in a parcel where you can build. BOOL enable_land_build(void*) { - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; + if (gAgent.isGodlike()) return TRUE; + if (gAgent.inPrelude()) return FALSE; - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; + BOOL can_build = FALSE; + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel) + { + can_build = agent_parcel->getAllowModify(); + } + return can_build; } // BUG: Should really check if OBJECT is in a parcel where you can build. BOOL enable_object_build(void*) { - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; + if (gAgent.isGodlike()) return TRUE; + if (gAgent.inPrelude()) return FALSE; - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; + BOOL can_build = FALSE; + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel) + { + can_build = agent_parcel->getAllowModify(); + } + return can_build; } bool enable_object_edit() { - if (!isAgentAvatarValid()) return false; - - // *HACK: The new "prelude" Help Islands have a build sandbox area, - // so users need the Edit and Create pie menu options when they are - // there. Eventually this needs to be replaced with code that only - // lets you edit objects if you have permission to do so (edit perms, - // group edit, god). See also lltoolbar.cpp. JC - bool enable = false; - if (gAgent.inPrelude()) - { - enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() - || LLSelectMgr::getInstance()->getSelection()->isAttachment(); - } - else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) - { - enable = true; - } - - return enable; + if (!isAgentAvatarValid()) return false; + + // *HACK: The new "prelude" Help Islands have a build sandbox area, + // so users need the Edit and Create pie menu options when they are + // there. Eventually this needs to be replaced with code that only + // lets you edit objects if you have permission to do so (edit perms, + // group edit, god). See also lltoolbar.cpp. JC + bool enable = false; + if (gAgent.inPrelude()) + { + enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() + || LLSelectMgr::getInstance()->getSelection()->isAttachment(); + } + else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) + { + enable = true; + } + + return enable; } bool enable_mute_particle() { - const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); - return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID(); + return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID(); } // mutually exclusive - show either edit option or build in menu bool enable_object_build() { - return !enable_object_edit(); + return !enable_object_edit(); } bool enable_object_select_in_pathfinding_linksets() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); } bool visible_object_select_in_pathfinding_linksets() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); } bool enable_object_select_in_pathfinding_characters() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } bool enable_os_exception() @@ -3281,40 +3281,40 @@ bool enable_os_exception() class LLSelfRemoveAllAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); + return true; + } }; class LLSelfEnableRemoveAllAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - if (isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getNumObjects() > 0) - { - new_value = true; - break; - } - } - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = false; + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getNumObjects() > 0) + { + new_value = true; + break; + } + } + } + return new_value; + } }; BOOL enable_has_attachments(void*) { - return FALSE; + return FALSE; } //--------------------------------------------------------------------------- @@ -3322,229 +3322,229 @@ BOOL enable_has_attachments(void*) //--------------------------------------------------------------------------- //void handle_follow(void *userdata) //{ -// // follow a given avatar by ID -// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if (objectp) -// { -// gAgent.startFollowPilot(objectp->getID()); -// } +// // follow a given avatar by ID +// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +// if (objectp) +// { +// gAgent.startFollowPilot(objectp->getID()); +// } //} bool enable_object_mute() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && - !LLMuteList::getInstance()->isMuted(object->getID()); - } + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + // It's an avatar + LLNameValue *lastname = avatar->getNVPair("LastName"); + bool is_linden = + lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); + bool is_self = avatar->isSelf(); + return !is_linden && !is_self; + } + else + { + // Just a regular object + return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && + !LLMuteList::getInstance()->isMuted(object->getID()); + } } bool enable_object_unmute() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && - LLMuteList::getInstance()->isMuted(object->getID());; - } + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + // It's an avatar + LLNameValue *lastname = avatar->getNVPair("LastName"); + bool is_linden = + lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); + bool is_self = avatar->isSelf(); + return !is_linden && !is_self; + } + else + { + // Just a regular object + return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && + LLMuteList::getInstance()->isMuted(object->getID());; + } } // 0 = normal, 1 = always, 2 = never class LLAvatarCheckImpostorMode : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (!avatar) return false; - - U32 mode = userdata.asInteger(); - switch (mode) - { - case 0: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); - case 1: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); - case 2: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (!avatar) return false; + + U32 mode = userdata.asInteger(); + switch (mode) + { + case 0: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); + case 1: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); + case 2: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); case 4: return (avatar->getVisualMuteSettings() != LLVOAvatar::AV_RENDER_NORMALLY); - default: - return false; - } - } // handleEvent() + default: + return false; + } + } // handleEvent() }; // 0 = normal, 1 = always, 2 = never class LLAvatarSetImpostorMode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (!avatar) return false; - - U32 mode = userdata.asInteger(); - switch (mode) - { - case 0: - avatar->setVisualMuteSettings(LLVOAvatar::AV_RENDER_NORMALLY); - break; - case 1: - avatar->setVisualMuteSettings(LLVOAvatar::AV_DO_NOT_RENDER); - break; - case 2: - avatar->setVisualMuteSettings(LLVOAvatar::AV_ALWAYS_RENDER); - break; - default: - return false; - } - - LLVOAvatar::cullAvatarsByPixelArea(); - return true; - } // handleEvent() + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (!avatar) return false; + + U32 mode = userdata.asInteger(); + switch (mode) + { + case 0: + avatar->setVisualMuteSettings(LLVOAvatar::AV_RENDER_NORMALLY); + break; + case 1: + avatar->setVisualMuteSettings(LLVOAvatar::AV_DO_NOT_RENDER); + break; + case 2: + avatar->setVisualMuteSettings(LLVOAvatar::AV_ALWAYS_RENDER); + break; + default: + return false; + } + + LLVOAvatar::cullAvatarsByPixelArea(); + return true; + } // handleEvent() }; class LLObjectMute : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return true; - - LLUUID id; - std::string name; - LLMute::EType type; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - avatar->mNeedsImpostorUpdate = TRUE; - avatar->mLastImpostorUpdateReason = 9; - - id = avatar->getID(); - - LLNameValue *firstname = avatar->getNVPair("FirstName"); - LLNameValue *lastname = avatar->getNVPair("LastName"); - if (firstname && lastname) - { - name = LLCacheName::buildFullName( - firstname->getString(), lastname->getString()); - } - - type = LLMute::AGENT; - } - else - { - // it's an object - id = object->getID(); - - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node) - { - name = node->mName; - } - - type = LLMute::OBJECT; - } - - LLMute mute(id, name, type); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return true; + + LLUUID id; + std::string name; + LLMute::EType type; + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + avatar->mNeedsImpostorUpdate = TRUE; + avatar->mLastImpostorUpdateReason = 9; + + id = avatar->getID(); + + LLNameValue *firstname = avatar->getNVPair("FirstName"); + LLNameValue *lastname = avatar->getNVPair("LastName"); + if (firstname && lastname) + { + name = LLCacheName::buildFullName( + firstname->getString(), lastname->getString()); + } + + type = LLMute::AGENT; + } + else + { + // it's an object + id = object->getID(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node) + { + name = node->mName; + } + + type = LLMute::OBJECT; + } + + LLMute mute(id, name, type); + if (LLMuteList::getInstance()->isMuted(mute.mID)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + + return true; + } }; bool handle_go_to() { - // try simulator autopilot - std::vector<std::string> strings; - std::string val; - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - val = llformat("%g", pos.mdV[VX]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); - strings.push_back(val); - send_generic_message("autopilot", strings); - - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else - { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); - } - - // Could be first use - //LLFirstUse::useGoTo(); - return true; + // try simulator autopilot + std::vector<std::string> strings; + std::string val; + LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; + val = llformat("%g", pos.mdV[VX]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VY]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VZ]); + strings.push_back(val); + send_generic_message("autopilot", strings); + + LLViewerParcelMgr::getInstance()->deselectLand(); + + if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) + { + gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); + } + else + { + // Snap camera back to behind avatar + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); + } + + // Could be first use + //LLFirstUse::useGoTo(); + return true; } class LLGoToObject : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return handle_go_to(); - } + bool handleEvent(const LLSD& userdata) + { + return handle_go_to(); + } }; class LLAvatarReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLFloaterReporter::showFromObject(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLFloaterReporter::showFromObject(avatar->getID()); + } + return true; + } }; @@ -3553,230 +3553,230 @@ class LLAvatarReportAbuse : public view_listener_t //--------------------------------------------------------------------------- bool callback_freeze(const LLSD& notification, const LLSD& response) { - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option || 1 == option) - { - U32 flags = 0x0; - if (1 == option) - { - // unfreeze - flags |= 0x1; - } - - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - msg->newMessage("FreezeUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; -} + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option || 1 == option) + { + U32 flags = 0x0; + if (1 == option) + { + // unfreeze + flags |= 0x1; + } + + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + msg->newMessage("FreezeUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + return false; +} void handle_avatar_freeze(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - std::string fullname = avatar->getFullname(); - LLSD payload; - payload["avatar_id"] = avatar->getID(); - - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("FreezeAvatarFullname", - args, - payload, - callback_freeze); - } - else - { - LLNotificationsUtil::add("FreezeAvatar", - LLSD(), - payload, - callback_freeze); - } - } + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + + if( avatar ) + { + std::string fullname = avatar->getFullname(); + LLSD payload; + payload["avatar_id"] = avatar->getID(); + + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("FreezeAvatarFullname", + args, + payload, + callback_freeze); + } + else + { + LLNotificationsUtil::add("FreezeAvatar", + LLSD(), + payload, + callback_freeze); + } + } } class LLAvatarVisibleDebug : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.isGodlike(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.isGodlike(); + } }; class LLAvatarDebug : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if( avatar ) - { - if (avatar->isSelf()) - { - ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); - } - LL_INFOS() << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << LL_ENDL; - std::vector<std::string> strings; - strings.push_back(avatar->getID().asString()); - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); - LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if( avatar ) + { + if (avatar->isSelf()) + { + ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); + } + LL_INFOS() << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << LL_ENDL; + std::vector<std::string> strings; + strings.push_back(avatar->getID().asString()); + LLUUID invoice; + send_generic_message("dumptempassetdata", strings, invoice); + LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); + } + return true; + } }; bool callback_eject(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (2 == option) - { - // Cancel button. - return false; - } - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); - - if (0 == option) - { - // Eject button - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x0; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - else if (ban_enabled) - { - // This is tricky. It is similar to say if it is not an 'Eject' button, - // and it is also not an 'Cancle' button, and ban_enabled==ture, - // it should be the 'Eject and Ban' button. - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x1; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (2 == option) + { + // Cancel button. + return false; + } + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); + + if (0 == option) + { + // Eject button + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + U32 flags = 0x0; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID() ); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + else if (ban_enabled) + { + // This is tricky. It is similar to say if it is not an 'Eject' button, + // and it is also not an 'Cancle' button, and ban_enabled==ture, + // it should be the 'Eject and Ban' button. + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + U32 flags = 0x1; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID() ); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + return false; } void handle_avatar_eject(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - LLSD payload; - payload["avatar_id"] = avatar->getID(); - std::string fullname = avatar->getFullname(); - - const LLVector3d& pos = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); - - if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) - { + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + + if( avatar ) + { + LLSD payload; + payload["avatar_id"] = avatar->getID(); + std::string fullname = avatar->getFullname(); + + const LLVector3d& pos = avatar->getPositionGlobal(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); + + if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) + { payload["ban_enabled"] = true; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullname", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarFullname", - LLSD(), - payload, - callback_eject); - } - } - else - { + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("EjectAvatarFullname", + args, + payload, + callback_eject); + } + else + { + LLNotificationsUtil::add("EjectAvatarFullname", + LLSD(), + payload, + callback_eject); + } + } + else + { payload["ban_enabled"] = false; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullnameNoBan", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarNoBan", - LLSD(), - payload, - callback_eject); - } - } - } + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("EjectAvatarFullnameNoBan", + args, + payload, + callback_eject); + } + else + { + LLNotificationsUtil::add("EjectAvatarNoBan", + LLSD(), + payload, + callback_eject); + } + } + } } bool my_profile_visible() { - LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); - return floaterp && floaterp->isInVisibleChain(); + LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); + return floaterp && floaterp->isInVisibleChain(); } bool picks_tab_visible() @@ -3786,192 +3786,192 @@ bool picks_tab_visible() bool enable_freeze_eject(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - if (!avatar) return false; - - // Gods can always freeze - if (gAgent.isGodlike()) return true; - - // Estate owners / managers can freeze - // Parcel owners can also freeze - const LLVector3& pos = avatar->getPositionRegion(); - const LLVector3d& pos_global = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); - LLViewerRegion* region = avatar->getRegion(); - if (!region) return false; - - bool new_value = region->isOwnedSelf(pos); - if (!new_value || region->isOwnedGroup(pos)) - { - new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); - } - return new_value; + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + if (!avatar) return false; + + // Gods can always freeze + if (gAgent.isGodlike()) return true; + + // Estate owners / managers can freeze + // Parcel owners can also freeze + const LLVector3& pos = avatar->getPositionRegion(); + const LLVector3d& pos_global = avatar->getPositionGlobal(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); + LLViewerRegion* region = avatar->getRegion(); + if (!region) return false; + + bool new_value = region->isOwnedSelf(pos); + if (!new_value || region->isOwnedGroup(pos)) + { + new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); + } + return new_value; } bool callback_leave_group(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_LeaveGroupRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); - gAgent.sendReliableMessage(); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_LeaveGroupRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_GroupData); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); + gAgent.sendReliableMessage(); + } + return false; } void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt) { - LLAggregatePermissions::EValue val = ag_perm.getValue(bit); - std::string buffer; - switch(val) - { - case LLAggregatePermissions::AP_NONE: - buffer = llformat( "* %s None\n", txt); - break; - case LLAggregatePermissions::AP_SOME: - buffer = llformat( "* %s Some\n", txt); - break; - case LLAggregatePermissions::AP_ALL: - buffer = llformat( "* %s All\n", txt); - break; - case LLAggregatePermissions::AP_EMPTY: - default: - break; - } - string.append(buffer); + LLAggregatePermissions::EValue val = ag_perm.getValue(bit); + std::string buffer; + switch(val) + { + case LLAggregatePermissions::AP_NONE: + buffer = llformat( "* %s None\n", txt); + break; + case LLAggregatePermissions::AP_SOME: + buffer = llformat( "* %s Some\n", txt); + break; + case LLAggregatePermissions::AP_ALL: + buffer = llformat( "* %s All\n", txt); + break; + case LLAggregatePermissions::AP_EMPTY: + default: + break; + } + string.append(buffer); } bool enable_buy_object() { // In order to buy, there must only be 1 purchaseable object in // the selection manager. - if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; + if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; LLViewerObject* obj = NULL; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node) + if(node) { obj = node->getObject(); if(!obj) return false; - if( for_sale_selection(node) ) - { - // *NOTE: Is this needed? This checks to see if anyone owns the - // object, dating back to when we had "public" objects owned by - // no one. JC - if(obj->permAnyOwner()) return true; - } + if( for_sale_selection(node) ) + { + // *NOTE: Is this needed? This checks to see if anyone owns the + // object, dating back to when we had "public" objects owned by + // no one. JC + if(obj->permAnyOwner()) return true; + } } - return false; + return false; } // Note: This will only work if the selected object's data has been // received by the viewer and cached in the selection manager. void handle_buy_object(LLSaleInfo sale_info) { - if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) - { - LLNotificationsUtil::add("UnableToBuyWhileDownloading"); - return; - } + if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) + { + LLNotificationsUtil::add("UnableToBuyWhileDownloading"); + return; + } - LLUUID owner_id; - std::string owner_name; - BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); - if (!owners_identical) - { - LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); - return; - } + LLUUID owner_id; + std::string owner_name; + BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + if (!owners_identical) + { + LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); + return; + } - LLPermissions perm; - BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); - LLAggregatePermissions ag_perm; - valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); - if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) - { - LLNotificationsUtil::add("ObjectNotForSale"); - return; - } + LLPermissions perm; + BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); + LLAggregatePermissions ag_perm; + valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); + if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) + { + LLNotificationsUtil::add("ObjectNotForSale"); + return; + } - LLFloaterBuy::show(sale_info); + LLFloaterBuy::show(sale_info); } void handle_buy_contents(LLSaleInfo sale_info) { - LLFloaterBuyContents::show(sale_info); + LLFloaterBuyContents::show(sale_info); } void handle_region_dump_temp_asset_data(void*) { - LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; - std::vector<std::string> strings; - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); + LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; + std::vector<std::string> strings; + LLUUID invoice; + send_generic_message("dumptempassetdata", strings, invoice); } void handle_region_clear_temp_asset_data(void*) { - LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; - std::vector<std::string> strings; - LLUUID invoice; - send_generic_message("cleartempassetdata", strings, invoice); + LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; + std::vector<std::string> strings; + LLUUID invoice; + send_generic_message("cleartempassetdata", strings, invoice); } void handle_region_dump_settings(void*) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; + } } void handle_dump_group_info(void *) { - gAgent.dumpGroupInfo(); + gAgent.dumpGroupInfo(); } void handle_dump_capabilities_info(void *) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->logActiveCapabilities(); - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + regionp->logActiveCapabilities(); + } } void handle_dump_region_object_cache(void*) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->dumpCache(); - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + regionp->dumpCache(); + } } void handle_reset_interest_lists(void *) @@ -3992,18 +3992,18 @@ void handle_reset_interest_lists(void *) void handle_dump_focus() { - LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; + LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; } class LLSelfStandUp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.standUp(); + return true; + } }; bool enable_standup_self() @@ -4024,202 +4024,202 @@ class LLSelfSitDown : public view_listener_t bool show_sitdown_self() { - return isAgentAvatarValid() && !gAgentAvatarp->isSitting(); + return isAgentAvatarValid() && !gAgentAvatarp->isSitting(); } bool enable_sitdown_self() { - return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); + return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } class LLSelfToggleSitStand : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (isAgentAvatarValid()) - { - if (gAgentAvatarp->isSitting()) - { - gAgent.standUp(); - } - else - { - gAgent.sitDown(); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (isAgentAvatarValid()) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + } + else + { + gAgent.sitDown(); + } + } + return true; + } }; bool enable_sit_stand() { - return enable_sitdown_self() || enable_standup_self(); + return enable_sitdown_self() || enable_standup_self(); } bool enable_fly_land() { - return gAgent.getFlying() || LLAgent::enableFlying(); + return gAgent.getFlying() || LLAgent::enableFlying(); } class LLCheckPanelPeopleTab : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string panel_name = userdata.asString(); - LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); - if(panel && panel->isInVisibleChain()) - { - return true; - } - return false; - } + LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); + if(panel && panel->isInVisibleChain()) + { + return true; + } + return false; + } }; // Toggle one of "People" panel tabs in side tray. class LLTogglePanelPeopleTab : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); - - LLSD param; - param["people_panel_tab_name"] = panel_name; - - if ( panel_name == "friends_panel" - || panel_name == "groups_panel" - || panel_name == "nearby_panel" - || panel_name == "blocked_panel") - { - return togglePeoplePanel(panel_name, param); - } - else - { - return false; - } - } - - static bool togglePeoplePanel(const std::string& panel_name, const LLSD& param) - { - LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); - if(!panel) - return false; - - if (panel->isInVisibleChain()) - { - LLFloaterReg::hideInstance("people"); - } - else - { - LLFloaterSidePanelContainer::showPanel("people", "panel_people", param) ; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string panel_name = userdata.asString(); + + LLSD param; + param["people_panel_tab_name"] = panel_name; + + if ( panel_name == "friends_panel" + || panel_name == "groups_panel" + || panel_name == "nearby_panel" + || panel_name == "blocked_panel") + { + return togglePeoplePanel(panel_name, param); + } + else + { + return false; + } + } + + static bool togglePeoplePanel(const std::string& panel_name, const LLSD& param) + { + LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); + if(!panel) + return false; + + if (panel->isInVisibleChain()) + { + LLFloaterReg::hideInstance("people"); + } + else + { + LLFloaterSidePanelContainer::showPanel("people", "panel_people", param) ; + } + + return true; + } }; BOOL check_admin_override(void*) { - return gAgent.getAdminOverride(); + return gAgent.getAdminOverride(); } void handle_admin_override_toggle(void*) { - gAgent.setAdminOverride(!gAgent.getAdminOverride()); + gAgent.setAdminOverride(!gAgent.getAdminOverride()); - // The above may have affected which debug menus are visible - show_debug_menus(); + // The above may have affected which debug menus are visible + show_debug_menus(); } void handle_visual_leak_detector_toggle(void*) { - static bool vld_enabled = false; + static bool vld_enabled = false; - if ( vld_enabled ) - { + if ( vld_enabled ) + { #ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) + // only works for debug builds (hard coded into vld.h) #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDDisable(); + // start with Visual Leak Detector turned off + VLDDisable(); #endif // _DEBUG #endif // INCLUDE_VLD - vld_enabled = false; - } - else - { + vld_enabled = false; + } + else + { #ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) - #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDEnable(); - #endif // _DEBUG + // only works for debug builds (hard coded into vld.h) + #ifdef _DEBUG + // start with Visual Leak Detector turned off + VLDEnable(); + #endif // _DEBUG #endif // INCLUDE_VLD - vld_enabled = true; - }; + vld_enabled = true; + }; } void handle_god_mode(void*) { - gAgent.requestEnterGodMode(); + gAgent.requestEnterGodMode(); } void handle_leave_god_mode(void*) { - gAgent.requestLeaveGodMode(); + gAgent.requestLeaveGodMode(); } void set_god_level(U8 god_level) { - U8 old_god_level = gAgent.getGodLevel(); - gAgent.setGodLevel( god_level ); - LLViewerParcelMgr::getInstance()->notifyObservers(); + U8 old_god_level = gAgent.getGodLevel(); + gAgent.setGodLevel( god_level ); + LLViewerParcelMgr::getInstance()->notifyObservers(); - // God mode changes region visibility - LLWorldMap::getInstance()->reloadItems(true); + // God mode changes region visibility + LLWorldMap::getInstance()->reloadItems(true); - // inventory in items may change in god mode - gObjectList.dirtyAllObjectInventory(); + // inventory in items may change in god mode + gObjectList.dirtyAllObjectInventory(); if(gViewerWindow) { gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, LLGridManager::getInstance()->isInProductionGrid()); } - + LLSD args; - if(god_level > GOD_NOT) - { - args["LEVEL"] = llformat("%d",(S32)god_level); - LLNotificationsUtil::add("EnteringGodMode", args); - } - else - { - args["LEVEL"] = llformat("%d",(S32)old_god_level); - LLNotificationsUtil::add("LeavingGodMode", args); - } - - // changing god-level can affect which menus we see - show_debug_menus(); - - // changing god-level can invalidate search results - LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search")); - if (search) - { - search->godLevelChanged(god_level); - } + if(god_level > GOD_NOT) + { + args["LEVEL"] = llformat("%d",(S32)god_level); + LLNotificationsUtil::add("EnteringGodMode", args); + } + else + { + args["LEVEL"] = llformat("%d",(S32)old_god_level); + LLNotificationsUtil::add("LeavingGodMode", args); + } + + // changing god-level can affect which menus we see + show_debug_menus(); + + // changing god-level can invalidate search results + LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search")); + if (search) + { + search->godLevelChanged(god_level); + } } #ifdef TOGGLE_HACKED_GODLIKE_VIEWER void handle_toggle_hacked_godmode(void*) { - gHackGodmode = !gHackGodmode; - set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); + gHackGodmode = !gHackGodmode; + set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); } BOOL check_toggle_hacked_godmode(void*) { - return gHackGodmode; + return gHackGodmode; } bool enable_toggle_hacked_godmode(void*) @@ -4230,174 +4230,174 @@ bool enable_toggle_hacked_godmode(void*) void process_grant_godlike_powers(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) - { - U8 god_level; - msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); - set_god_level(god_level); - } - else - { - LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; - } + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) + { + U8 god_level; + msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); + set_god_level(god_level); + } + else + { + LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; + } } /* class LLHaveCallingcard : public LLInventoryCollectFunctor { public: - LLHaveCallingcard(const LLUUID& agent_id); - virtual ~LLHaveCallingcard() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL isThere() const { return mIsThere;} + LLHaveCallingcard(const LLUUID& agent_id); + virtual ~LLHaveCallingcard() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + BOOL isThere() const { return mIsThere;} protected: - LLUUID mID; - BOOL mIsThere; + LLUUID mID; + BOOL mIsThere; }; LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) : - mID(agent_id), - mIsThere(FALSE) + mID(agent_id), + mIsThere(FALSE) { } bool LLHaveCallingcard::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item) - { - if((item->getType() == LLAssetType::AT_CALLINGCARD) - && (item->getCreatorUUID() == mID)) - { - mIsThere = TRUE; - } - } - return FALSE; + LLInventoryItem* item) +{ + if(item) + { + if((item->getType() == LLAssetType::AT_CALLINGCARD) + && (item->getCreatorUUID() == mID)) + { + mIsThere = TRUE; + } + } + return FALSE; } */ BOOL is_agent_mappable(const LLUUID& agent_id) { - const LLRelationship* buddy_info = NULL; - bool is_friend = LLAvatarActions::isFriend(agent_id); + const LLRelationship* buddy_info = NULL; + bool is_friend = LLAvatarActions::isFriend(agent_id); - if (is_friend) - buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); + if (is_friend) + buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); - return (buddy_info && - buddy_info->isOnline() && - buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) - ); + return (buddy_info && + buddy_info->isOnline() && + buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) + ); } // Enable a menu item when you don't have someone's card. class LLAvatarEnableAddFriend : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); + return new_value; + } }; void request_friendship(const LLUUID& dest_id) { - LLViewerObject* dest = gObjectList.findObject(dest_id); - if(dest && dest->isAvatar()) - { - std::string full_name; - LLNameValue* nvfirst = dest->getNVPair("FirstName"); - LLNameValue* nvlast = dest->getNVPair("LastName"); - if(nvfirst && nvlast) - { - full_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - if (!full_name.empty()) - { - LLAvatarActions::requestFriendshipDialog(dest_id, full_name); - } - else - { - LLNotificationsUtil::add("CantOfferFriendship"); - } - } + LLViewerObject* dest = gObjectList.findObject(dest_id); + if(dest && dest->isAvatar()) + { + std::string full_name; + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if(nvfirst && nvlast) + { + full_name = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + } + if (!full_name.empty()) + { + LLAvatarActions::requestFriendshipDialog(dest_id, full_name); + } + else + { + LLNotificationsUtil::add("CantOfferFriendship"); + } + } } class LLEditEnableCustomizeAvatar : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentWearables.areWearablesLoaded(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgentWearables.areWearablesLoaded(); + return new_value; + } }; class LLEnableEditShape : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - } + bool handleEvent(const LLSD& userdata) + { + return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + } }; class LLEnableHoverHeight : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.getRegion() && gAgent.getRegion()->avatarHoverHeightEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.getRegion() && gAgent.getRegion()->avatarHoverHeightEnabled(); + } }; class LLEnableEditPhysics : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - return TRUE; - } + bool handleEvent(const LLSD& userdata) + { + //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + return TRUE; + } }; bool is_object_sittable() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (object && object->getPCode() == LL_PCODE_VOLUME) - { - return true; - } - else - { - return false; - } + if (object && object->getPCode() == LL_PCODE_VOLUME) + { + return true; + } + else + { + return false; + } } // only works on pie menu void handle_object_sit(LLViewerObject *object, const LLVector3 &offset) { - // get object selection offset + // get object selection offset - if (object && object->getPCode() == LL_PCODE_VOLUME) - { + if (object && object->getPCode() == LL_PCODE_VOLUME) + { - gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_TargetObject); - gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_TargetObject); + gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); + gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); - object->getRegion()->sendReliableMessage(); - } + object->getRegion()->sendReliableMessage(); + } } void handle_object_sit_or_stand() @@ -4432,12 +4432,12 @@ void handle_object_sit(const LLUUID& object_id) void near_sit_down_point(BOOL success, void *) { - if (success) - { - gAgent.setFlying(FALSE); - gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP); // might have been set by autopilot - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - } + if (success) + { + gAgent.setFlying(FALSE); + gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP); // might have been set by autopilot + gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + } } class LLLandSit : public view_listener_t @@ -4484,120 +4484,120 @@ void reset_view_final( BOOL proceed ); void handle_reset_view() { - if (gAgentCamera.cameraCustomizeAvatar()) - { - // switching to outfit selector should automagically save any currently edited wearable - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); - } - gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); - reset_view_final( TRUE ); - LLFloaterCamera::resetCameraMode(); + if (gAgentCamera.cameraCustomizeAvatar()) + { + // switching to outfit selector should automagically save any currently edited wearable + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); + } + gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); + reset_view_final( TRUE ); + LLFloaterCamera::resetCameraMode(); } class LLViewResetView : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_reset_view(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_reset_view(); + return true; + } }; // Note: extra parameters allow this function to be called from dialog. -void reset_view_final( BOOL proceed ) +void reset_view_final( BOOL proceed ) { - if( !proceed ) - { - return; - } + if( !proceed ) + { + return; + } - gAgentCamera.resetView(TRUE, TRUE); - gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + gAgentCamera.resetView(TRUE, TRUE); + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); } class LLViewLookAtLastChatter : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgentCamera.lookAtLastChat(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgentCamera.lookAtLastChat(); + return true; + } }; class LLViewMouselook : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (!gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToMouselook(); - } - else - { - gAgentCamera.changeCameraToDefault(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (!gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToMouselook(); + } + else + { + gAgentCamera.changeCameraToDefault(); + } + return true; + } }; class LLViewDefaultUISize : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setF32("UIScaleFactor", 1.0f); - gSavedSettings.setBOOL("UIAutoScale", FALSE); - gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gSavedSettings.setF32("UIScaleFactor", 1.0f); + gSavedSettings.setBOOL("UIAutoScale", FALSE); + gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); + return true; + } }; class LLViewToggleUI : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - LLNotification::Params params("ConfirmHideUI"); - params.functor.function(boost::bind(&LLViewToggleUI::confirm, this, _1, _2)); - LLSD substitutions; + bool handleEvent(const LLSD& userdata) + { + if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) + { + LLNotification::Params params("ConfirmHideUI"); + params.functor.function(boost::bind(&LLViewToggleUI::confirm, this, _1, _2)); + LLSD substitutions; #if LL_DARWIN - substitutions["SHORTCUT"] = "Cmd+Shift+U"; + substitutions["SHORTCUT"] = "Cmd+Shift+U"; #else - substitutions["SHORTCUT"] = "Ctrl+Shift+U"; + substitutions["SHORTCUT"] = "Ctrl+Shift+U"; #endif - params.substitutions = substitutions; - if (!gSavedSettings.getBOOL("HideUIControls")) - { - // hiding, so show notification - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } - } - return true; - } - - void confirm(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (option == 0) // OK - { - gViewerWindow->setUIVisibility(gSavedSettings.getBOOL("HideUIControls")); - LLPanelStandStopFlying::getInstance()->setVisible(gSavedSettings.getBOOL("HideUIControls")); - gSavedSettings.setBOOL("HideUIControls",!gSavedSettings.getBOOL("HideUIControls")); - } - } -}; + params.substitutions = substitutions; + if (!gSavedSettings.getBOOL("HideUIControls")) + { + // hiding, so show notification + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } + } + return true; + } -void handle_duplicate_in_place(void*) + void confirm(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (option == 0) // OK + { + gViewerWindow->setUIVisibility(gSavedSettings.getBOOL("HideUIControls")); + LLPanelStandStopFlying::getInstance()->setVisible(gSavedSettings.getBOOL("HideUIControls")); + gSavedSettings.setBOOL("HideUIControls",!gSavedSettings.getBOOL("HideUIControls")); + } + } +}; + +void handle_duplicate_in_place(void*) { - LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; + LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; - LLVector3 offset(0.f, 0.f, 0.f); - LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); + LLVector3 offset(0.f, 0.f, 0.f); + LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); } @@ -4606,121 +4606,121 @@ void handle_duplicate_in_place(void*) * No longer able to support viewer side manipulations in this way * void god_force_inv_owner_permissive(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void*) -{ - typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t; - item_array_t items; - - LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); - LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); - for ( ; inv_it != inv_end; ++inv_it) - { - if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) - { - LLInventoryObject* obj = *inv_it; - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); - LLPermissions perm(new_item->getPermissions()); - perm.setMaskBase(PERM_ALL); - perm.setMaskOwner(PERM_ALL); - new_item->setPermissions(perm); - items.push_back(new_item); - } - } - item_array_t::iterator end = items.end(); - item_array_t::iterator it; - for(it = items.begin(); it != end; ++it) - { - // since we have the inventory item in the callback, it should not - // invalidate iteration through the selection manager. - object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); - } + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void*) +{ + typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t; + item_array_t items; + + LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); + LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); + for ( ; inv_it != inv_end; ++inv_it) + { + if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) + { + LLInventoryObject* obj = *inv_it; + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); + LLPermissions perm(new_item->getPermissions()); + perm.setMaskBase(PERM_ALL); + perm.setMaskOwner(PERM_ALL); + new_item->setPermissions(perm); + items.push_back(new_item); + } + } + item_array_t::iterator end = items.end(); + item_array_t::iterator it; + for(it = items.begin(); it != end; ++it) + { + // since we have the inventory item in the callback, it should not + // invalidate iteration through the selection manager. + object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); + } } */ void handle_object_owner_permissive(void*) { - // only send this if they're a god. - if(gAgent.isGodlike()) - { - // do the objects. - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); - } + // only send this if they're a god. + if(gAgent.isGodlike()) + { + // do the objects. + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); + } } void handle_object_owner_self(void*) { - // only send this if they're a god. - if(gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); - } + // only send this if they're a god. + if(gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); + } } // Shortcut to set owner permissions to not editable. void handle_object_lock(void*) { - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); } void handle_object_asset_ids(void*) { - // only send this if they're a god. - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); - } + // only send this if they're a god. + if (gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); + } } void handle_force_parcel_owner_to_me(void*) { - LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); + LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); } void handle_force_parcel_to_content(void*) { - LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); + LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); } void handle_claim_public_land(void*) { - if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) - { - LLNotificationsUtil::add("ClaimPublicLand"); - return; - } - - LLVector3d west_south_global; - LLVector3d east_north_global; - LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); - LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); - LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GodlikeMessage"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - msg->nextBlock("MethodData"); - msg->addString("Method", "claimpublicland"); - msg->addUUID("Invoice", LLUUID::null); - std::string buffer; - buffer = llformat( "%f", west_south.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", west_south.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - gAgent.sendReliableMessage(); + if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) + { + LLNotificationsUtil::add("ClaimPublicLand"); + return; + } + + LLVector3d west_south_global; + LLVector3d east_north_global; + LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); + LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); + LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("GodlikeMessage"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + msg->nextBlock("MethodData"); + msg->addString("Method", "claimpublicland"); + msg->addUUID("Invoice", LLUUID::null); + std::string buffer; + buffer = llformat( "%f", west_south.mV[VX]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", west_south.mV[VY]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", east_north.mV[VX]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", east_north.mV[VY]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + gAgent.sendReliableMessage(); } @@ -4728,286 +4728,286 @@ void handle_claim_public_land(void*) // HACK for easily testing new avatar geometry void handle_god_request_avatar_geometry(void *) { - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); - } + if (gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); + } } static bool get_derezzable_objects( - EDeRezDestination dest, - std::string& error, - LLViewerRegion*& first_region, - std::vector<LLViewerObjectPtr>* derez_objectsp, - bool only_check = false) -{ - bool found = false; - - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if (derez_objectsp) - derez_objectsp->reserve(selection->getRootObjectCount()); - - // Check conditions that we can't deal with, building a list of - // everything that we'll actually be derezzing. - for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); - iter != selection->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerRegion* region = object->getRegion(); - if (!first_region) - { - first_region = region; - } - else - { - if(region != first_region) - { - // Derez doesn't work at all if the some of the objects - // are in regions besides the first object selected. - - // ...crosses region boundaries - error = "AcquireErrorObjectSpan"; - break; - } - } - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } - - // If AssetContainers are being sent back, they will appear as - // boxes in the owner's inventory. - if (object->getNVPair("AssetContainer") - && dest != DRD_RETURN_TO_OWNER) - { - // this object is an asset container, derez its contents, not it - LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; - /* - object->requestInventory(container_inventory_arrived, - (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); - */ - continue; - } - BOOL can_derez_current = FALSE; - switch(dest) - { - case DRD_TAKE_INTO_AGENT_INVENTORY: - case DRD_TRASH: - if (!object->isPermanentEnforced() && - ((node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) - || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)))) - { - can_derez_current = TRUE; - } - break; - - case DRD_RETURN_TO_OWNER: - if(!object->isAttachment()) - { - can_derez_current = TRUE; - } - break; - - default: - if((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permCopy()) - || gAgent.isGodlike()) - { - can_derez_current = TRUE; - } - break; - } - if(can_derez_current) - { - found = true; - - if (only_check) - // one found, no need to traverse to the end - break; - - if (derez_objectsp) - derez_objectsp->push_back(object); - - } - } - - return found; + EDeRezDestination dest, + std::string& error, + LLViewerRegion*& first_region, + std::vector<LLViewerObjectPtr>* derez_objectsp, + bool only_check = false) +{ + bool found = false; + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + + if (derez_objectsp) + derez_objectsp->reserve(selection->getRootObjectCount()); + + // Check conditions that we can't deal with, building a list of + // everything that we'll actually be derezzing. + for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + iter != selection->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + LLViewerRegion* region = object->getRegion(); + if (!first_region) + { + first_region = region; + } + else + { + if(region != first_region) + { + // Derez doesn't work at all if the some of the objects + // are in regions besides the first object selected. + + // ...crosses region boundaries + error = "AcquireErrorObjectSpan"; + break; + } + } + if (object->isAvatar()) + { + // ...don't acquire avatars + continue; + } + + // If AssetContainers are being sent back, they will appear as + // boxes in the owner's inventory. + if (object->getNVPair("AssetContainer") + && dest != DRD_RETURN_TO_OWNER) + { + // this object is an asset container, derez its contents, not it + LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; + /* + object->requestInventory(container_inventory_arrived, + (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); + */ + continue; + } + BOOL can_derez_current = FALSE; + switch(dest) + { + case DRD_TAKE_INTO_AGENT_INVENTORY: + case DRD_TRASH: + if (!object->isPermanentEnforced() && + ((node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) + || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)))) + { + can_derez_current = TRUE; + } + break; + + case DRD_RETURN_TO_OWNER: + if(!object->isAttachment()) + { + can_derez_current = TRUE; + } + break; + + default: + if((node->mPermissions->allowTransferTo(gAgent.getID()) + && object->permCopy()) + || gAgent.isGodlike()) + { + can_derez_current = TRUE; + } + break; + } + if(can_derez_current) + { + found = true; + + if (only_check) + // one found, no need to traverse to the end + break; + + if (derez_objectsp) + derez_objectsp->push_back(object); + + } + } + + return found; } static bool can_derez(EDeRezDestination dest) { - LLViewerRegion* first_region = NULL; - std::string error; - return get_derezzable_objects(dest, error, first_region, NULL, true); + LLViewerRegion* first_region = NULL; + std::string error; + return get_derezzable_objects(dest, error, first_region, NULL, true); } static void derez_objects( - EDeRezDestination dest, - const LLUUID& dest_id, - LLViewerRegion*& first_region, - std::string& error, - std::vector<LLViewerObjectPtr>* objectsp) -{ - std::vector<LLViewerObjectPtr> derez_objects; - - if (!objectsp) // if objects to derez not specified - { - // get them from selection - if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) - { - LL_WARNS() << "No objects to derez" << LL_ENDL; - return; - } - - objectsp = &derez_objects; - } - - - if(gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - - // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per - // root. I lopped off a few (33) to provide a bit - // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. - // This gives us a maximum of 63500 root objects - which should - // satisfy anybody. - const S32 MAX_ROOTS_PER_PACKET = 250; - const S32 MAX_PACKET_COUNT = 254; - F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); - if(packets > (F32)MAX_PACKET_COUNT) - { - error = "AcquireErrorTooManyObjects"; - } - - if(error.empty() && objectsp->size() > 0) - { - U8 d = (U8)dest; - LLUUID tid; - tid.generate(); - U8 packet_count = (U8)packets; - S32 object_index = 0; - S32 objects_in_packet = 0; - LLMessageSystem* msg = gMessageSystem; - for(U8 packet_number = 0; - packet_number < packet_count; - ++packet_number) - { - msg->newMessageFast(_PREHASH_DeRezObject); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_AgentBlock); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->addU8Fast(_PREHASH_Destination, d); - msg->addUUIDFast(_PREHASH_DestinationID, dest_id); - msg->addUUIDFast(_PREHASH_TransactionID, tid); - msg->addU8Fast(_PREHASH_PacketCount, packet_count); - msg->addU8Fast(_PREHASH_PacketNumber, packet_number); - objects_in_packet = 0; - while((object_index < objectsp->size()) - && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) - - { - LLViewerObject* object = objectsp->at(object_index++); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - // VEFFECT: DerezObject - LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(object->getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - } - msg->sendReliable(first_region->getHost()); - } - make_ui_sound("UISndObjectRezOut"); - - // Busy count decremented by inventory update, so only increment - // if will be causing an update. - if (dest != DRD_RETURN_TO_OWNER) - { - gViewerWindow->getWindow()->incBusyCount(); - } - } - else if(!error.empty()) - { - LLNotificationsUtil::add(error); - } + EDeRezDestination dest, + const LLUUID& dest_id, + LLViewerRegion*& first_region, + std::string& error, + std::vector<LLViewerObjectPtr>* objectsp) +{ + std::vector<LLViewerObjectPtr> derez_objects; + + if (!objectsp) // if objects to derez not specified + { + // get them from selection + if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) + { + LL_WARNS() << "No objects to derez" << LL_ENDL; + return; + } + + objectsp = &derez_objects; + } + + + if(gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + + // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per + // root. I lopped off a few (33) to provide a bit + // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. + // This gives us a maximum of 63500 root objects - which should + // satisfy anybody. + const S32 MAX_ROOTS_PER_PACKET = 250; + const S32 MAX_PACKET_COUNT = 254; + F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); + if(packets > (F32)MAX_PACKET_COUNT) + { + error = "AcquireErrorTooManyObjects"; + } + + if(error.empty() && objectsp->size() > 0) + { + U8 d = (U8)dest; + LLUUID tid; + tid.generate(); + U8 packet_count = (U8)packets; + S32 object_index = 0; + S32 objects_in_packet = 0; + LLMessageSystem* msg = gMessageSystem; + for(U8 packet_number = 0; + packet_number < packet_count; + ++packet_number) + { + msg->newMessageFast(_PREHASH_DeRezObject); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_AgentBlock); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->addU8Fast(_PREHASH_Destination, d); + msg->addUUIDFast(_PREHASH_DestinationID, dest_id); + msg->addUUIDFast(_PREHASH_TransactionID, tid); + msg->addU8Fast(_PREHASH_PacketCount, packet_count); + msg->addU8Fast(_PREHASH_PacketNumber, packet_number); + objects_in_packet = 0; + while((object_index < objectsp->size()) + && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) + + { + LLViewerObject* object = objectsp->at(object_index++); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); + // VEFFECT: DerezObject + LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(object->getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + } + msg->sendReliable(first_region->getHost()); + } + make_ui_sound("UISndObjectRezOut"); + + // Busy count decremented by inventory update, so only increment + // if will be causing an update. + if (dest != DRD_RETURN_TO_OWNER) + { + gViewerWindow->getWindow()->incBusyCount(); + } + } + else if(!error.empty()) + { + LLNotificationsUtil::add(error); + } } static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) { - LLViewerRegion* first_region = NULL; - std::string error; - derez_objects(dest, dest_id, first_region, error, NULL); + LLViewerRegion* first_region = NULL; + std::string error; + derez_objects(dest, dest_id, first_region, error, NULL); } void handle_take_copy() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } void handle_link_objects() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - LLFloaterReg::toggleInstanceOrBringToFront("places"); - } - else - { - LLSelectMgr::getInstance()->linkObjects(); - } + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLFloaterReg::toggleInstanceOrBringToFront("places"); + } + else + { + LLSelectMgr::getInstance()->linkObjects(); + } } // You can return an object to its owner if it is on your land. class LLObjectReturn : public view_listener_t { public: - LLObjectReturn() : mFirstRegion(NULL) {} + LLObjectReturn() : mFirstRegion(NULL) {} private: - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; - - mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; + + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. - get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); - return true; - } + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); + return true; + } - bool onReturnToOwner(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects); - } + bool onReturnToOwner(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects); + } - mReturnableObjects.clear(); - mError.clear(); - mFirstRegion = NULL; + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; - // drop reference to current selection - mObjectSelection = NULL; - return false; - } + // drop reference to current selection + mObjectSelection = NULL; + return false; + } - LLObjectSelectionHandle mObjectSelection; + LLObjectSelectionHandle mObjectSelection; - std::vector<LLViewerObjectPtr> mReturnableObjects; - std::string mError; - LLViewerRegion* mFirstRegion; + std::vector<LLViewerObjectPtr> mReturnableObjects; + std::string mError; + LLViewerRegion* mFirstRegion; }; @@ -5015,187 +5015,187 @@ private: // over land you own. class LLObjectEnableReturn : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - // Do not enable if nothing selected - return false; - } + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + // Do not enable if nothing selected + return false; + } #ifdef HACKED_GODLIKE_VIEWER - bool new_value = true; + bool new_value = true; #else - bool new_value = false; - if (gAgent.isGodlike()) - { - new_value = true; - } - else - { - new_value = can_derez(DRD_RETURN_TO_OWNER); - } + bool new_value = false; + if (gAgent.isGodlike()) + { + new_value = true; + } + else + { + new_value = can_derez(DRD_RETURN_TO_OWNER); + } #endif - return new_value; - } + return new_value; + } }; void force_take_copy(void*) { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); } void handle_take() { - // we want to use the folder this was derezzed from if it's - // available. Otherwise, derez to the normal place. - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - BOOL you_own_everything = TRUE; - BOOL locked_but_takeable_object = FALSE; - LLUUID category_id; - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if(object) - { - if(!object->permYouOwner()) - { - you_own_everything = FALSE; - } - - if(!object->permMove()) - { - locked_but_takeable_object = TRUE; - } - } - if(node->mFolderID.notNull()) - { - if(category_id.isNull()) - { - category_id = node->mFolderID; - } - else if(category_id != node->mFolderID) - { - // we have found two potential destinations. break out - // now and send to the default location. - category_id.setNull(); - break; - } - } - } - if(category_id.notNull()) - { - // there is an unambiguous destination. See if this agent has - // such a location and it is not in the trash or library - if(!gInventory.getCategory(category_id)) - { - // nope, set to NULL. - category_id.setNull(); - } - if(category_id.notNull()) - { - // check trash - const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) - { - category_id.setNull(); - } - - // check library - if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) - { - category_id.setNull(); - } - - // check inbox - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); - if (category_id == inbox_id || gInventory.isObjectDescendentOf(category_id, inbox_id)) - { - category_id.setNull(); - } - } - } - if(category_id.isNull()) - { - category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - } - LLSD payload; - payload["folder_id"] = category_id; - - LLNotification::Params params("ConfirmObjectTakeLock"); - params.payload(payload); - // MAINT-290 - // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. - // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened - params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); - - if(locked_but_takeable_object || - !you_own_everything) - { - if(locked_but_takeable_object && you_own_everything) - { - params.name("ConfirmObjectTakeLock"); - } - else if(!locked_but_takeable_object && !you_own_everything) - { - params.name("ConfirmObjectTakeNoOwn"); - } - else - { - params.name("ConfirmObjectTakeLockNoOwn"); - } - - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } + // we want to use the folder this was derezzed from if it's + // available. Otherwise, derez to the normal place. + if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + return; + } + + BOOL you_own_everything = TRUE; + BOOL locked_but_takeable_object = FALSE; + LLUUID category_id; + + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if(object) + { + if(!object->permYouOwner()) + { + you_own_everything = FALSE; + } + + if(!object->permMove()) + { + locked_but_takeable_object = TRUE; + } + } + if(node->mFolderID.notNull()) + { + if(category_id.isNull()) + { + category_id = node->mFolderID; + } + else if(category_id != node->mFolderID) + { + // we have found two potential destinations. break out + // now and send to the default location. + category_id.setNull(); + break; + } + } + } + if(category_id.notNull()) + { + // there is an unambiguous destination. See if this agent has + // such a location and it is not in the trash or library + if(!gInventory.getCategory(category_id)) + { + // nope, set to NULL. + category_id.setNull(); + } + if(category_id.notNull()) + { + // check trash + const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) + { + category_id.setNull(); + } + + // check library + if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) + { + category_id.setNull(); + } + + // check inbox + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); + if (category_id == inbox_id || gInventory.isObjectDescendentOf(category_id, inbox_id)) + { + category_id.setNull(); + } + } + } + if(category_id.isNull()) + { + category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + } + LLSD payload; + payload["folder_id"] = category_id; + + LLNotification::Params params("ConfirmObjectTakeLock"); + params.payload(payload); + // MAINT-290 + // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. + // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened + params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); + + if(locked_but_takeable_object || + !you_own_everything) + { + if(locked_but_takeable_object && you_own_everything) + { + params.name("ConfirmObjectTakeLock"); + } + else if(!locked_but_takeable_object && !you_own_everything) + { + params.name("ConfirmObjectTakeNoOwn"); + } + else + { + params.name("ConfirmObjectTakeLockNoOwn"); + } + + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } } void handle_object_show_inspector() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* objectp = selection->getFirstRootObject(TRUE); - if (!objectp) - { - return; - } + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* objectp = selection->getFirstRootObject(TRUE); + if (!objectp) + { + return; + } - LLSD params; - params["object_id"] = objectp->getID(); - LLFloaterReg::showInstance("inspect_object", params); + LLSD params; + params["object_id"] = objectp->getID(); + LLFloaterReg::showInstance("inspect_object", params); } void handle_avatar_show_inspector() { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLSD params; - params["avatar_id"] = avatar->getID(); - LLFloaterReg::showInstance("inspect_avatar", params); - } + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLSD params; + params["avatar_id"] = avatar->getID(); + LLFloaterReg::showInstance("inspect_avatar", params); + } } bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection_handle) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(enable_take() && (option == 0)) - { - derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(enable_take() && (option == 0)) + { + derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); + } + return false; } // You can take an item when it is public and transferrable, or when @@ -5203,101 +5203,101 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect // one item selected can be copied to inventory. BOOL enable_take() { - if (sitting_on_selection()) - { - return FALSE; - } - - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } + if (sitting_on_selection()) + { + return FALSE; + } + + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (object->isAvatar()) + { + // ...don't acquire avatars + continue; + } #ifdef HACKED_GODLIKE_VIEWER - return TRUE; + return TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() + if (!LLGridManager::getInstance()->isInProductionGrid() && gAgent.isGodlike()) - { - return TRUE; - } + { + return TRUE; + } # endif - if(!object->isPermanentEnforced() && - ((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permModify()) - || (node->mPermissions->getOwner() == gAgent.getID()))) - { - return !object->isAttachment(); - } + if(!object->isPermanentEnforced() && + ((node->mPermissions->allowTransferTo(gAgent.getID()) + && object->permModify()) + || (node->mPermissions->getOwner() == gAgent.getID()))) + { + return !object->isAttachment(); + } #endif - } - return FALSE; + } + return FALSE; } void handle_buy_or_take() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - if (is_selection_buy_not_take()) - { - S32 total_price = selection_price(); - - if (total_price <= gStatusBar->getBalance() || total_price == 0) - { - handle_buy(); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", total_price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); - } - } - else - { - handle_take(); - } + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + return; + } + + if (is_selection_buy_not_take()) + { + S32 total_price = selection_price(); + + if (total_price <= gStatusBar->getBalance() || total_price == 0) + { + handle_buy(); + } + else + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", total_price); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); + } + } + else + { + handle_take(); + } } bool visible_buy_object() { - return is_selection_buy_not_take() && enable_buy_object(); + return is_selection_buy_not_take() && enable_buy_object(); } bool visible_take_object() { - return !is_selection_buy_not_take() && enable_take(); + return !is_selection_buy_not_take() && enable_take(); } bool tools_visible_buy_object() { - return is_selection_buy_not_take(); + return is_selection_buy_not_take(); } bool tools_visible_take_object() { - return !is_selection_buy_not_take(); + return !is_selection_buy_not_take(); } class LLToolsEnableBuyOrTake : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool is_buy = is_selection_buy_not_take(); - bool new_value = is_buy ? enable_buy_object() : enable_take(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool is_buy = is_selection_buy_not_take(); + bool new_value = is_buy ? enable_buy_object() : enable_take(); + return new_value; + } }; // This is a small helper function to determine if we have a buy or a @@ -5318,255 +5318,255 @@ class LLToolsEnableBuyOrTake : public view_listener_t // FALSE if selection is a 'take' BOOL is_selection_buy_not_take() { - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale, thus, - // it's a buy - return TRUE; - } - } - return FALSE; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) + { + // you do not own the object and it is for sale, thus, + // it's a buy + return TRUE; + } + } + return FALSE; } S32 selection_price() { - S32 total_price = 0; - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale. - // Add its price. - total_price += node->mSaleInfo.getSalePrice(); - } - } - - return total_price; + S32 total_price = 0; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) + { + // you do not own the object and it is for sale. + // Add its price. + total_price += node->mSaleInfo.getSalePrice(); + } + } + + return total_price; } /* bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LL_INFOS() << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << LL_ENDL; - LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_INFOS() << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << LL_ENDL; + LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); + } + return false; } */ void show_buy_currency(const char* extra) { - // Don't show currency web page for branded clients. + // Don't show currency web page for branded clients. /* - std::ostringstream mesg; - if (extra != NULL) - { - mesg << extra << "\n \n"; - } - mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; + std::ostringstream mesg; + if (extra != NULL) + { + mesg << extra << "\n \n"; + } + mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; */ - LLSD args; - if (extra != NULL) - { - args["EXTRA"] = extra; - } - LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); + LLSD args; + if (extra != NULL) + { + args["EXTRA"] = extra; + } + LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); } void handle_buy() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - LLSaleInfo sale_info; - BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); - if (!valid) return; + LLSaleInfo sale_info; + BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); + if (!valid) return; - S32 price = sale_info.getSalePrice(); - - if (price > 0 && price > gStatusBar->getBalance()) - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); - return; - } + S32 price = sale_info.getSalePrice(); - if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) - { - handle_buy_contents(sale_info); - } - else - { - handle_buy_object(sale_info); - } + if (price > 0 && price > gStatusBar->getBalance()) + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", price); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); + return; + } + + if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) + { + handle_buy_contents(sale_info); + } + else + { + handle_buy_object(sale_info); + } } bool anyone_copy_selection(LLSelectNode* nodep) { - bool perm_copy = (bool)(nodep->getObject()->permCopy()); - bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); - return perm_copy && all_copy; + bool perm_copy = (bool)(nodep->getObject()->permCopy()); + bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); + return perm_copy && all_copy; } bool for_sale_selection(LLSelectNode* nodep) { - return nodep->mSaleInfo.isForSale() - && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER - && (nodep->mPermissions->getMaskOwner() & PERM_COPY - || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); + return nodep->mSaleInfo.isForSale() + && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER + && (nodep->mPermissions->getMaskOwner() & PERM_COPY + || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); } BOOL sitting_on_selection() { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (!node) - { - return FALSE; - } + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (!node) + { + return FALSE; + } - if (!node->mValid) - { - return FALSE; - } + if (!node->mValid) + { + return FALSE; + } - LLViewerObject* root_object = node->getObject(); - if (!root_object) - { - return FALSE; - } + LLViewerObject* root_object = node->getObject(); + if (!root_object) + { + return FALSE; + } - // Need to determine if avatar is sitting on this object - if (!isAgentAvatarValid()) return FALSE; + // Need to determine if avatar is sitting on this object + if (!isAgentAvatarValid()) return FALSE; - return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); + return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); } class LLToolsSaveToObjectInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if(node && (node->mValid) && (!node->mFromTaskID.isNull())) + { + // *TODO: check to see if the fromtaskid object exists. + derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); + } + return true; + } }; class LLToolsEnablePathfinding : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); - } + bool handleEvent(const LLSD& userdata) + { + return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + } }; class LLToolsEnablePathfindingView : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); + } }; class LLToolsDoPathfindingRebakeRegion : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); - - if (hasPathfinding) - { - LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); - } + bool handleEvent(const LLSD& userdata) + { + bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); + + if (hasPathfinding) + { + LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); + } - return hasPathfinding; - } + return hasPathfinding; + } }; class LLToolsEnablePathfindingRebakeRegion : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool returnValue = false; + bool handleEvent(const LLSD& userdata) + { + bool returnValue = false; if (LLNavigationBar::instanceExists()) { returnValue = LLNavigationBar::getInstance()->isRebakeNavMeshAvailable(); } - return returnValue; - } + return returnValue; + } }; // Round the position of all root objects to the grid class LLToolsSnapObjectXY : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if (obj->permModify()) - { - LLVector3d pos_global = obj->getPositionGlobal(); - F64 round_x = fmod(pos_global.mdV[VX], snap_size); - if (round_x < snap_size * 0.5) - { - // closer to round down - pos_global.mdV[VX] -= round_x; - } - else - { - // closer to round up - pos_global.mdV[VX] -= round_x; - pos_global.mdV[VX] += snap_size; - } - - F64 round_y = fmod(pos_global.mdV[VY], snap_size); - if (round_y < snap_size * 0.5) - { - pos_global.mdV[VY] -= round_y; - } - else - { - pos_global.mdV[VY] -= round_y; - pos_global.mdV[VY] += snap_size; - } - - obj->setPositionGlobal(pos_global, FALSE); - } - } - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); - return true; - } + bool handleEvent(const LLSD& userdata) + { + F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); + + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (obj->permModify()) + { + LLVector3d pos_global = obj->getPositionGlobal(); + F64 round_x = fmod(pos_global.mdV[VX], snap_size); + if (round_x < snap_size * 0.5) + { + // closer to round down + pos_global.mdV[VX] -= round_x; + } + else + { + // closer to round up + pos_global.mdV[VX] -= round_x; + pos_global.mdV[VX] += snap_size; + } + + F64 round_y = fmod(pos_global.mdV[VY], snap_size); + if (round_y < snap_size * 0.5) + { + pos_global.mdV[VY] -= round_y; + } + else + { + pos_global.mdV[VY] -= round_y; + pos_global.mdV[VY] += snap_size; + } + + obj->setPositionGlobal(pos_global, FALSE); + } + } + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + return true; + } }; // Determine if the option to cycle between linked prims is shown class LLToolsEnableSelectNextPart : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { bool new_value = (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && (gSavedSettings.getBOOL("EditLinkedParts") || LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool())); - return new_value; - } + return new_value; + } }; // Cycle selection through linked children or/and faces in selected object. @@ -5641,61 +5641,61 @@ class LLToolsSelectNextPartFace : public view_listener_t } } - S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - if (cycle_linked && object_count && restart_face_on_part) - { - LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if (selected && selected->getRootEdit()) - { - LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); - children.push_front(selected->getRootEdit()); // need root in the list too - - for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) - { - if ((*iter)->isSelected()) - { - if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include - { - to_select = *iter; - if (fwd) - { - // stop searching if going forward; repeat to get last hit if backward - break; - } - } - else if ((object_count == 1) || (ifwd || iprev)) // single selection or include - { - if (fwd || ifwd) - { - ++iter; - while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) - { - ++iter; // skip sitting avatars and selected if include - } - } - else // backward - { - iter = (iter == children.begin() ? children.end() : iter); - --iter; - while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) - { - --iter; // skip sitting avatars and selected if include - } - } - iter = (iter == children.end() ? children.begin() : iter); - to_select = *iter; - break; - } - } - } - } - } + S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (cycle_linked && object_count && restart_face_on_part) + { + LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (selected && selected->getRootEdit()) + { + LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); + children.push_front(selected->getRootEdit()); // need root in the list too + + for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) + { + if ((*iter)->isSelected()) + { + if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include + { + to_select = *iter; + if (fwd) + { + // stop searching if going forward; repeat to get last hit if backward + break; + } + } + else if ((object_count == 1) || (ifwd || iprev)) // single selection or include + { + if (fwd || ifwd) + { + ++iter; + while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) + { + ++iter; // skip sitting avatars and selected if include + } + } + else // backward + { + iter = (iter == children.begin() ? children.end() : iter); + --iter; + while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) + { + --iter; // skip sitting avatars and selected if include + } + } + iter = (iter == children.end() ? children.begin() : iter); + to_select = *iter; + break; + } + } + } + } + } if (to_select) { if (gFocusMgr.childHasKeyboardFocus(gFloaterTools)) { - gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes + gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes } if (fwd || prev) { @@ -5723,455 +5723,455 @@ class LLToolsSelectNextPartFace : public view_listener_t } return true; } - return true; - } + return true; + } }; class LLToolsStopAllAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.stopCurrentAnimations(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.stopCurrentAnimations(); + return true; + } }; class LLToolsReleaseKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.forceReleaseControls(); + bool handleEvent(const LLSD& userdata) + { + gAgent.forceReleaseControls(); - return true; - } + return true; + } }; class LLToolsEnableReleaseKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.anyControlGrabbed(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.anyControlGrabbed(); + } }; class LLEditEnableCut : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); + return new_value; + } }; class LLEditCut : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->cut(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->cut(); + } + return true; + } }; class LLEditEnableCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); + return new_value; + } }; class LLEditCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->copy(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->copy(); + } + return true; + } }; class LLEditEnablePaste : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); + return new_value; + } }; class LLEditPaste : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->paste(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->paste(); + } + return true; + } }; class LLEditEnableDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); + return new_value; + } }; class LLEditDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // If a text field can do a deletion, it gets precedence over deleting - // an object in the world. - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) - { - LLEditMenuHandler::gEditMenuHandler->doDelete(); - } + bool handleEvent(const LLSD& userdata) + { + // If a text field can do a deletion, it gets precedence over deleting + // an object in the world. + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) + { + LLEditMenuHandler::gEditMenuHandler->doDelete(); + } - // and close any pie/context menus when done - gMenuHolder->hideMenus(); + // and close any pie/context menus when done + gMenuHolder->hideMenus(); - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return true; - } + // When deleting an object we may not actually be done + // Keep selection so we know what to delete when confirmation is needed about the delete + gMenuObject->hide(); + return true; + } }; void handle_spellcheck_replace_with_suggestion(const LLUICtrl* ctrl, const LLSD& param) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) - { - return; - } + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return; + } - U32 index = 0; - if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) - { - return; - } + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return; + } - spellcheck_handler->replaceWithSuggestion(index); + spellcheck_handler->replaceWithSuggestion(index); } bool visible_spellcheck_suggestion(LLUICtrl* ctrl, const LLSD& param) { - LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(ctrl); - const LLContextMenu* menu = (item) ? dynamic_cast<const LLContextMenu*>(item->getParent()) : NULL; - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) - { - return false; - } + LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(ctrl); + const LLContextMenu* menu = (item) ? dynamic_cast<const LLContextMenu*>(item->getParent()) : NULL; + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return false; + } - U32 index = 0; - if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) - { - return false; - } + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return false; + } - item->setLabel(spellcheck_handler->getSuggestion(index)); - return true; + item->setLabel(spellcheck_handler->getSuggestion(index)); + return true; } void handle_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) - { - spellcheck_handler->addToDictionary(); - } + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) + { + spellcheck_handler->addToDictionary(); + } } bool enable_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); } void handle_spellcheck_add_to_ignore(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) - { - spellcheck_handler->addToIgnore(); - } + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) + { + spellcheck_handler->addToIgnore(); + } } bool enable_spellcheck_add_to_ignore(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); } bool enable_object_return() { - return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && - (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); + return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && + (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); } bool enable_object_delete() { - bool new_value = + bool new_value = #ifdef HACKED_GODLIKE_VIEWER - TRUE; + TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - (!LLGridManager::getInstance()->isInProductionGrid() + (!LLGridManager::getInstance()->isInProductionGrid() && gAgent.isGodlike()) || # endif - LLSelectMgr::getInstance()->canDoDelete(); + LLSelectMgr::getInstance()->canDoDelete(); #endif - return new_value; + return new_value; } class LLObjectsReturnPackage { public: - LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; - ~LLObjectsReturnPackage() - { - mObjectSelection.clear(); - mReturnableObjects.clear(); - mError.clear(); - mFirstRegion = NULL; - }; + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + ~LLObjectsReturnPackage() + { + mObjectSelection.clear(); + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; + }; - LLObjectSelectionHandle mObjectSelection; - std::vector<LLViewerObjectPtr> mReturnableObjects; - std::string mError; - LLViewerRegion *mFirstRegion; + LLObjectSelectionHandle mObjectSelection; + std::vector<LLViewerObjectPtr> mReturnableObjects; + std::string mError; + LLViewerRegion *mFirstRegion; }; static void return_objects(LLObjectsReturnPackage *objectsReturnPackage, const LLSD& notification, const LLSD& response) { - if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); - } + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); + } - delete objectsReturnPackage; + delete objectsReturnPackage; } void handle_object_return() { - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); - objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); + objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. - get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); - } + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); + } } void handle_object_delete() { - if (LLSelectMgr::getInstance()) - { - LLSelectMgr::getInstance()->doDelete(); - } + if (LLSelectMgr::getInstance()) + { + LLSelectMgr::getInstance()->doDelete(); + } - // and close any pie/context menus when done - gMenuHolder->hideMenus(); + // and close any pie/context menus when done + gMenuHolder->hideMenus(); - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return; + // When deleting an object we may not actually be done + // Keep selection so we know what to delete when confirmation is needed about the delete + gMenuObject->hide(); + return; } void handle_force_delete(void*) { - LLSelectMgr::getInstance()->selectForceDelete(); + LLSelectMgr::getInstance()->selectForceDelete(); } class LLViewEnableJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); + return new_value; + } }; class LLViewEnableLastChatter : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // *TODO: add check that last chatter is in range - bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // *TODO: add check that last chatter is in range + bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); + return new_value; + } }; class LLEditEnableDeselect : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); + return new_value; + } }; class LLEditDeselect : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->deselect(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->deselect(); + } + return true; + } }; class LLEditEnableSelectAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); + return new_value; + } }; class LLEditSelectAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->selectAll(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->selectAll(); + } + return true; + } }; class LLEditEnableUndo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); + return new_value; + } }; class LLEditUndo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) - { - LLEditMenuHandler::gEditMenuHandler->undo(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) + { + LLEditMenuHandler::gEditMenuHandler->undo(); + } + return true; + } }; class LLEditEnableRedo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); + return new_value; + } }; class LLEditRedo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) - { - LLEditMenuHandler::gEditMenuHandler->redo(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) + { + LLEditMenuHandler::gEditMenuHandler->redo(); + } + return true; + } }; void print_object_info(void*) { - LLSelectMgr::getInstance()->selectionDump(); + LLSelectMgr::getInstance()->selectionDump(); } void print_agent_nvpairs(void*) { - LLViewerObject *objectp; + LLViewerObject *objectp; - LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; + LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; - objectp = gObjectList.findObject(gAgentID); - if (objectp) - { - objectp->printNameValuePairs(); - } - else - { - LL_INFOS() << "Can't find agent object" << LL_ENDL; - } + objectp = gObjectList.findObject(gAgentID); + if (objectp) + { + objectp->printNameValuePairs(); + } + else + { + LL_INFOS() << "Can't find agent object" << LL_ENDL; + } - LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; + LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; } void show_debug_menus() { - // this might get called at login screen where there is no menu so only toggle it if one exists - if ( gMenuBarView ) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - BOOL qamode = gSavedSettings.getBOOL("QAMode"); - - gMenuBarView->setItemVisible("Advanced", debug); -// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden - - gMenuBarView->setItemVisible("Debug", qamode); - gMenuBarView->setItemEnabled("Debug", qamode); - - gMenuBarView->setItemVisible("Develop", qamode); - gMenuBarView->setItemEnabled("Develop", qamode); - - // Server ('Admin') menu hidden when not in godmode. - const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); - gMenuBarView->setItemVisible("Admin", show_server_menu); - gMenuBarView->setItemEnabled("Admin", show_server_menu); - } - if (gLoginMenuBarView) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - gLoginMenuBarView->setItemVisible("Debug", debug); - gLoginMenuBarView->setItemEnabled("Debug", debug); - } + // this might get called at login screen where there is no menu so only toggle it if one exists + if ( gMenuBarView ) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + BOOL qamode = gSavedSettings.getBOOL("QAMode"); + + gMenuBarView->setItemVisible("Advanced", debug); +// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + + gMenuBarView->setItemVisible("Debug", qamode); + gMenuBarView->setItemEnabled("Debug", qamode); + + gMenuBarView->setItemVisible("Develop", qamode); + gMenuBarView->setItemEnabled("Develop", qamode); + + // Server ('Admin') menu hidden when not in godmode. + const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); + gMenuBarView->setItemVisible("Admin", show_server_menu); + gMenuBarView->setItemEnabled("Admin", show_server_menu); + } + if (gLoginMenuBarView) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + gLoginMenuBarView->setItemVisible("Debug", debug); + gLoginMenuBarView->setItemEnabled("Debug", debug); + } } void toggle_debug_menus(void*) { - BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); - gSavedSettings.setBOOL("UseDebugMenus", visible); - show_debug_menus(); + BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); + gSavedSettings.setBOOL("UseDebugMenus", visible); + show_debug_menus(); } @@ -6182,292 +6182,292 @@ void toggle_debug_menus(void*) // void handle_export_selected( void * ) // { -// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); -// if (selection->isEmpty()) -// { -// return; -// } -// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; - -// gExporterRequestID.generate(); -// gExportDirectory = ""; - -// LLMessageSystem* msg = gMessageSystem; -// msg->newMessageFast(_PREHASH_ObjectExportSelected); -// msg->nextBlockFast(_PREHASH_AgentData); -// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); -// msg->addS16Fast(_PREHASH_VolumeDetail, 4); - -// for (LLObjectSelection::root_iterator iter = selection->root_begin(); -// iter != selection->root_end(); iter++) -// { -// LLSelectNode* node = *iter; -// LLViewerObject* object = node->getObject(); -// msg->nextBlockFast(_PREHASH_ObjectData); -// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); -// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; -// } -// msg->sendReliable(gAgent.getRegion()->getHost()); - -// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); +// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); +// if (selection->isEmpty()) +// { +// return; +// } +// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; + +// gExporterRequestID.generate(); +// gExportDirectory = ""; + +// LLMessageSystem* msg = gMessageSystem; +// msg->newMessageFast(_PREHASH_ObjectExportSelected); +// msg->nextBlockFast(_PREHASH_AgentData); +// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); +// msg->addS16Fast(_PREHASH_VolumeDetail, 4); + +// for (LLObjectSelection::root_iterator iter = selection->root_begin(); +// iter != selection->root_end(); iter++) +// { +// LLSelectNode* node = *iter; +// LLViewerObject* object = node->getObject(); +// msg->nextBlockFast(_PREHASH_ObjectData); +// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); +// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; +// } +// msg->sendReliable(gAgent.getRegion()->getHost()); + +// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); // } // class LLCommunicateNearbyChat : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); + bool handleEvent(const LLSD& userdata) + { + LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); LLFloaterIMNearbyChat* floater_nearby = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); - if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() + if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() && im_box->getSelectedSession() == LLUUID() && im_box->getConversationListItemSize() > 1) - { - im_box->selectNextorPreviousConversation(false); - } - else - { - LLFloaterReg::toggleInstanceOrBringToFront("nearby_chat"); - } - return true; - } + { + im_box->selectNextorPreviousConversation(false); + } + else + { + LLFloaterReg::toggleInstanceOrBringToFront("nearby_chat"); + } + return true; + } }; class LLWorldSetHomeLocation : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // we just send the message and let the server check for failure cases - // server will echo back a "Home position set." alert if it succeeds - // and the home location screencapture happens when that alert is recieved - gAgent.setStartPosition(START_LOCATION_ID_HOME); - return true; - } + bool handleEvent(const LLSD& userdata) + { + // we just send the message and let the server check for failure cases + // server will echo back a "Home position set." alert if it succeeds + // and the home location screencapture happens when that alert is recieved + gAgent.setStartPosition(START_LOCATION_ID_HOME); + return true; + } }; class LLWorldLindenHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); - LLWeb::loadURL(url); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); + LLWeb::loadURL(url); + return true; + } }; class LLWorldTeleportHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.teleportHome(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.teleportHome(); + return true; + } }; class LLWorldAlwaysRun : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // as well as altering the default walk-vs-run state, - // we also change the *current* walk-vs-run state. - if (gAgent.getAlwaysRun()) - { - gAgent.clearAlwaysRun(); - gAgent.clearRunning(); - } - else - { - gAgent.setAlwaysRun(); - gAgent.setRunning(); - } + bool handleEvent(const LLSD& userdata) + { + // as well as altering the default walk-vs-run state, + // we also change the *current* walk-vs-run state. + if (gAgent.getAlwaysRun()) + { + gAgent.clearAlwaysRun(); + gAgent.clearRunning(); + } + else + { + gAgent.setAlwaysRun(); + gAgent.setRunning(); + } - // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); + // tell the simulator. + gAgent.sendWalkRun(gAgent.getAlwaysRun()); - // Update Movement Controls according to AlwaysRun mode - LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); + // Update Movement Controls according to AlwaysRun mode + LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); - return true; - } + return true; + } }; class LLWorldCheckAlwaysRun : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.getAlwaysRun(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgent.getAlwaysRun(); + return new_value; + } }; class LLWorldSetAway : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.getAFK()) - { - gAgent.clearAFK(); - } - else - { - gAgent.setAFK(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.getAFK()) + { + gAgent.clearAFK(); + } + else + { + gAgent.setAFK(); + } + return true; + } }; class LLWorldSetDoNotDisturb : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isDoNotDisturb()) - { - gAgent.setDoNotDisturb(false); - } - else - { - gAgent.setDoNotDisturb(true); - LLNotificationsUtil::add("DoNotDisturbModeSet"); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.isDoNotDisturb()) + { + gAgent.setDoNotDisturb(false); + } + else + { + gAgent.setDoNotDisturb(true); + LLNotificationsUtil::add("DoNotDisturbModeSet"); + } + return true; + } }; class LLWorldCreateLandmark : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("add_landmark"); + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("add_landmark"); - return true; - } + return true; + } }; class LLWorldPlaceProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); + bool handleEvent(const LLSD& userdata) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); - return true; - } + return true; + } }; void handle_look_at_selection(const LLSD& param) { - const F32 PADDING_FACTOR = 1.75f; - BOOL zoom = (param.asString() == "zoom"); - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - - LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); - obj_to_cam.normVec(); - - LLUUID object_id; - if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; - } - if (zoom) - { - // Make sure we are not increasing the distance between the camera and object - LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); - distance = llmin(distance, (F32) orig_distance.length()); - - gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), - LLSelectMgr::getInstance()->getSelectionCenterGlobal(), - object_id ); - - } - else - { - gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); - } - } + const F32 PADDING_FACTOR = 1.75f; + BOOL zoom = (param.asString() == "zoom"); + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + + LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); + F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); + + LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); + obj_to_cam.normVec(); + + LLUUID object_id; + if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) + { + object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; + } + if (zoom) + { + // Make sure we are not increasing the distance between the camera and object + LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); + distance = llmin(distance, (F32) orig_distance.length()); + + gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), + LLSelectMgr::getInstance()->getSelectionCenterGlobal(), + object_id ); + + } + else + { + gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); + } + } } void handle_zoom_to_object(LLUUID object_id) { - const F32 PADDING_FACTOR = 2.f; + const F32 PADDING_FACTOR = 2.f; - LLViewerObject* object = gObjectList.findObject(object_id); + LLViewerObject* object = gObjectList.findObject(object_id); - if (object) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + if (object) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - LLBBox bbox = object->getBoundingBoxAgent() ; - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); + LLBBox bbox = object->getBoundingBoxAgent() ; + F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); + F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); - obj_to_cam.normVec(); + LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); + obj_to_cam.normVec(); - LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); + LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); - gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), - object_center_global, - object_id ); - } + gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), + object_center_global, + object_id ); + } } class LLAvatarInviteToGroup : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::inviteToGroup(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::inviteToGroup(avatar->getID()); + } + return true; + } }; class LLAvatarAddFriend : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !LLAvatarActions::isFriend(avatar->getID())) - { - request_friendship(avatar->getID()); - } - return true; - } -}; - - + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar && !LLAvatarActions::isFriend(avatar->getID())) + { + request_friendship(avatar->getID()); + } + return true; + } +}; + + class LLAvatarToggleMyProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID()); - if (LLFloater::isMinimized(instance)) - { - instance->setMinimized(FALSE); - instance->setFocus(TRUE); - } - else if (!LLFloater::isShown(instance)) - { - LLAvatarActions::showProfile(gAgent.getID()); - } - else if (!instance->hasFocus() && !instance->getIsChrome()) - { - instance->setFocus(TRUE); - } - else - { - instance->closeFloater(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID()); + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + } + else if (!LLFloater::isShown(instance)) + { + LLAvatarActions::showProfile(gAgent.getID()); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } + return true; + } }; class LLAvatarTogglePicks : public view_listener_t @@ -6495,41 +6495,41 @@ class LLAvatarTogglePicks : public view_listener_t class LLAvatarToggleSearch : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* instance = LLFloaterReg::findInstance("search"); - if (LLFloater::isMinimized(instance)) - { - instance->setMinimized(FALSE); - instance->setFocus(TRUE); - } - else if (!LLFloater::isShown(instance)) - { - LLFloaterReg::showInstance("search"); - } - else if (!instance->hasFocus() && !instance->getIsChrome()) - { - instance->setFocus(TRUE); - } - else - { - instance->closeFloater(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* instance = LLFloaterReg::findInstance("search"); + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + } + else if (!LLFloater::isShown(instance)) + { + LLFloaterReg::showInstance("search"); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } + return true; + } }; class LLAvatarResetSkeleton: public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = NULL; LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (obj) { avatar = obj->getAvatar(); } - if(avatar) + if(avatar) { avatar->resetSkeleton(false); } @@ -6553,184 +6553,184 @@ class LLAvatarEnableResetSkeleton: public view_listener_t class LLAvatarResetSkeletonAndAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) - { - avatar->resetSkeleton(true); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + return true; + } }; class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) - { - avatar->resetSkeleton(true); - } - else - { - gAgentAvatarp->resetSkeleton(true); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + else + { + gAgentAvatarp->resetSkeleton(true); + } + return true; + } }; class LLAvatarAddContact : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - create_inventory_callingcard(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + create_inventory_callingcard(avatar->getID()); + } + return true; + } }; bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - gAgent.setDoNotDisturb(false); - } - - LLViewerObject* objectp = selection->getPrimaryObject(); - - // Show avatar's name if paying attachment - if (objectp && objectp->isAttachment()) - { - while (objectp && !objectp->isAvatar()) - { - objectp = (LLViewerObject*)objectp->getParent(); - } - } - - if (objectp) - { - if (objectp->isAvatar()) - { - const bool is_group = false; - LLFloaterPayUtil::payDirectly(&give_money, - objectp->getID(), - is_group); - } - else - { - LLFloaterPayUtil::payViaObject(&give_money, selection); - } - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + gAgent.setDoNotDisturb(false); + } + + LLViewerObject* objectp = selection->getPrimaryObject(); + + // Show avatar's name if paying attachment + if (objectp && objectp->isAttachment()) + { + while (objectp && !objectp->isAvatar()) + { + objectp = (LLViewerObject*)objectp->getParent(); + } + } + + if (objectp) + { + if (objectp->isAvatar()) + { + const bool is_group = false; + LLFloaterPayUtil::payDirectly(&give_money, + objectp->getID(), + is_group); + } + else + { + LLFloaterPayUtil::payViaObject(&give_money, selection); + } + } + return false; } void handle_give_money_dialog() { - LLNotification::Params params("DoNotDisturbModePay"); - params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + LLNotification::Params params("DoNotDisturbModePay"); + params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); - if (gAgent.isDoNotDisturb()) - { - // warn users of being in do not disturb mode during a transaction - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 1); - } + if (gAgent.isDoNotDisturb()) + { + // warn users of being in do not disturb mode during a transaction + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 1); + } } bool enable_pay_avatar() { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLVOAvatar* avatar = find_avatar_from_object(obj); - return (avatar != NULL); + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLVOAvatar* avatar = find_avatar_from_object(obj); + return (avatar != NULL); } bool enable_pay_object() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if( object ) - { - LLViewerObject *parent = (LLViewerObject *)object->getParent(); - if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) - { - return true; - } - } - return false; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if( object ) + { + LLViewerObject *parent = (LLViewerObject *)object->getParent(); + if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) + { + return true; + } + } + return false; } bool enable_object_stand_up() { - // 'Object Stand Up' menu item is enabled when agent is sitting on selection - return sitting_on_selection(); + // 'Object Stand Up' menu item is enabled when agent is sitting on selection + return sitting_on_selection(); } bool enable_object_sit(LLUICtrl* ctrl) { - // 'Object Sit' menu item is enabled when agent is not sitting on selection - bool sitting_on_sel = sitting_on_selection(); - if (!sitting_on_sel) - { - // init default labels - init_default_item_label(ctrl); - - // Update label - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mSitName.empty()) - { - ctrl->setValue(node->mSitName); - } - else - { - ctrl->setValue(get_default_item_label(ctrl->getName())); - } - } - return !sitting_on_sel && is_object_sittable(); + // 'Object Sit' menu item is enabled when agent is not sitting on selection + bool sitting_on_sel = sitting_on_selection(); + if (!sitting_on_sel) + { + // init default labels + init_default_item_label(ctrl); + + // Update label + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mSitName.empty()) + { + ctrl->setValue(node->mSitName); + } + else + { + ctrl->setValue(get_default_item_label(ctrl->getName())); + } + } + return !sitting_on_sel && is_object_sittable(); } void dump_select_mgr(void*) { - LLSelectMgr::getInstance()->dump(); + LLSelectMgr::getInstance()->dump(); } void dump_inventory(void*) { - gInventory.dumpInventory(); + gInventory.dumpInventory(); } void handle_dump_followcam(void*) { - LLFollowCamMgr::getInstance()->dump(); + LLFollowCamMgr::getInstance()->dump(); } void handle_viewer_enable_message_log(void*) { - gMessageSystem->startLogging(); + gMessageSystem->startLogging(); } void handle_viewer_disable_message_log(void*) { - gMessageSystem->stopLogging(); + gMessageSystem->stopLogging(); } void handle_customize_avatar() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); } void handle_edit_outfit() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); } void handle_now_wearing() @@ -6747,225 +6747,225 @@ void handle_now_wearing() void handle_edit_shape() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); } void handle_hover_height() { - LLFloaterReg::showInstance("edit_hover_height"); + LLFloaterReg::showInstance("edit_hover_height"); } void handle_edit_physics() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_physics")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_physics")); } void handle_report_abuse() { - // Prevent menu from appearing in screen shot. - gMenuHolder->hideMenus(); - LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); + // Prevent menu from appearing in screen shot. + gMenuHolder->hideMenus(); + LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); } void handle_buy_currency() { - LLBuyCurrencyHTML::openCurrencyFloater(); + LLBuyCurrencyHTML::openCurrencyFloater(); } class LLFloaterVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - bool new_value = false; - { - new_value = LLFloaterReg::instanceVisible(floater_name); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + bool new_value = false; + { + new_value = LLFloaterReg::instanceVisible(floater_name); + } + return new_value; + } }; class LLShowHelp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string help_topic = userdata.asString(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(help_topic); + return true; + } }; class LLToggleHelp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); - if (help_browser && help_browser->isInVisibleChain()) - { - help_browser->closeFloater(); - } - else - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); + if (help_browser && help_browser->isInVisibleChain()) + { + help_browser->closeFloater(); + } + else + { + std::string help_topic = userdata.asString(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(help_topic); + } + return true; + } }; class LLToggleSpeak : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVoiceClient::getInstance()->toggleUserPTTState(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVoiceClient::getInstance()->toggleUserPTTState(); + return true; + } }; class LLShowSidetrayPanel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - - LLPanel* panel = LLFloaterSidePanelContainer::getPanel(floater_name); - if (panel) - { - if (panel->isInVisibleChain()) - { - LLFloaterReg::getInstance(floater_name)->closeFloater(); - } - else - { - LLFloaterReg::getInstance(floater_name)->openFloater(); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + + LLPanel* panel = LLFloaterSidePanelContainer::getPanel(floater_name); + if (panel) + { + if (panel->isInVisibleChain()) + { + LLFloaterReg::getInstance(floater_name)->closeFloater(); + } + else + { + LLFloaterReg::getInstance(floater_name)->openFloater(); + } + } + return true; + } }; class LLSidetrayPanelVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - // Toggle the panel - if (LLFloaterReg::getInstance(floater_name)->isInVisibleChain()) - { - return true; - } - else - { - return false; - } - - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + // Toggle the panel + if (LLFloaterReg::getInstance(floater_name)->isInVisibleChain()) + { + return true; + } + else + { + return false; + } + + } }; bool callback_show_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"].asString()); + } + return false; } class LLPromptShowURL : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string url = param.substr(offset+1); - - if (LLWeb::useExternalBrowser(url)) - { - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); - } - else - { - LLWeb::loadURL(url); - } - } - else - { - LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string url = param.substr(offset+1); + + if (LLWeb::useExternalBrowser(url)) + { + LLSD payload; + payload["url"] = url; + LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); + } + else + { + LLWeb::loadURL(url); + } + } + else + { + LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; + } + return true; + } }; bool callback_show_file(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"]); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"]); + } + return false; } class LLPromptShowFile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string file = param.substr(offset+1); - - LLSD payload; - payload["url"] = file; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); - } - else - { - LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string file = param.substr(offset+1); + + LLSD payload; + payload["url"] = file; + LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); + } + else + { + LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; + } + return true; + } }; class LLShowAgentProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - LLAvatarActions::showProfile(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID agent_id; + if (userdata.asString() == "agent") + { + agent_id = gAgent.getID(); + } + else if (userdata.asString() == "hit object") + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + agent_id = objectp->getID(); + } + } + else + { + agent_id = userdata.asUUID(); + } + + LLVOAvatar* avatar = find_avatar_from_object(agent_id); + if (avatar) + { + LLAvatarActions::showProfile(avatar->getID()); + } + return true; + } }; class LLShowAgentProfilePicks : public view_listener_t @@ -6979,164 +6979,164 @@ class LLShowAgentProfilePicks : public view_listener_t class LLToggleAgentProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - if (!LLAvatarActions::profileVisible(avatar->getID())) - { - LLAvatarActions::showProfile(avatar->getID()); - } - else - { - LLAvatarActions::hideProfile(avatar->getID()); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID agent_id; + if (userdata.asString() == "agent") + { + agent_id = gAgent.getID(); + } + else if (userdata.asString() == "hit object") + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + agent_id = objectp->getID(); + } + } + else + { + agent_id = userdata.asUUID(); + } + + LLVOAvatar* avatar = find_avatar_from_object(agent_id); + if (avatar) + { + if (!LLAvatarActions::profileVisible(avatar->getID())) + { + LLAvatarActions::showProfile(avatar->getID()); + } + else + { + LLAvatarActions::hideProfile(avatar->getID()); + } + } + return true; + } }; class LLLandEdit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } + gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } - LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); + LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); - LLFloaterReg::showInstance("build"); + LLFloaterReg::showInstance("build"); - // Switch to land edit toolset - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); - return true; - } + // Switch to land edit toolset + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); + return true; + } }; class LLMuteParticle : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID; - - if (id.notNull()) - { - LLAvatarName av_name; - LLAvatarNameCache::get(id, &av_name); - - LLMute mute(id, av_name.getUserName(), LLMute::AGENT); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID; + + if (id.notNull()) + { + LLAvatarName av_name; + LLAvatarNameCache::get(id, &av_name); + + LLMute mute(id, av_name.getUserName(), LLMute::AGENT); + if (LLMuteList::getInstance()->isMuted(mute.mID)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + } + + return true; + } }; class LLWorldEnableBuyLand : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->selectionEmpty() - ? LLViewerParcelMgr::getInstance()->getAgentParcel() - : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), - false); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( + LLViewerParcelMgr::getInstance()->selectionEmpty() + ? LLViewerParcelMgr::getInstance()->getAgentParcel() + : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), + false); + return new_value; + } }; BOOL enable_buy_land(void*) { - return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); + return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( + LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); } void handle_buy_land() { - LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); - if (vpm->selectionEmpty()) - { - vpm->selectParcelAt(gAgent.getPositionGlobal()); - } - vpm->startBuyLand(); + LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); + if (vpm->selectionEmpty()) + { + vpm->selectParcelAt(gAgent.getPositionGlobal()); + } + vpm->startBuyLand(); } class LLObjectAttachToAvatar : public view_listener_t { public: - LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} - static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } + LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} + static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } private: - bool handleEvent(const LLSD& userdata) - { - setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); - if (selectedObject) - { - S32 index = userdata.asInteger(); - LLViewerJointAttachment* attachment_point = NULL; - if (index > 0) - attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); - confirmReplaceAttachment(0, attachment_point); - } - return true; - } - - static void onNearAttachObject(BOOL success, void *user_data); - void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); - class CallbackData : public LLSelectionCallbackData - { - public: - CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} - - LLViewerJointAttachment* mAttachmentPoint; - bool mReplace; - }; + bool handleEvent(const LLSD& userdata) + { + setObjectSelection(LLSelectMgr::getInstance()->getSelection()); + LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); + if (selectedObject) + { + S32 index = userdata.asInteger(); + LLViewerJointAttachment* attachment_point = NULL; + if (index > 0) + attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + confirmReplaceAttachment(0, attachment_point); + } + return true; + } + + static void onNearAttachObject(BOOL success, void *user_data); + void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); + class CallbackData : public LLSelectionCallbackData + { + public: + CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} + + LLViewerJointAttachment* mAttachmentPoint; + bool mReplace; + }; protected: - static LLObjectSelectionHandle sObjectSelection; - bool mReplace; + static LLObjectSelectionHandle sObjectSelection; + bool mReplace; }; LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; @@ -7144,238 +7144,238 @@ LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; // static void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) { - if (!user_data) return; - CallbackData* cb_data = static_cast<CallbackData*>(user_data); - - if (success) - { - const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; - - U8 attachment_id = 0; - if (attachment) - { - for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) - { - if (iter->second == attachment) - { - attachment_id = iter->first; - break; - } - } - } - else - { - // interpret 0 as "default location" - attachment_id = 0; - } - LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); - } - LLObjectAttachToAvatar::setObjectSelection(NULL); - - delete cb_data; + if (!user_data) return; + CallbackData* cb_data = static_cast<CallbackData*>(user_data); + + if (success) + { + const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; + + U8 attachment_id = 0; + if (attachment) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) + { + if (iter->second == attachment) + { + attachment_id = iter->first; + break; + } + } + } + else + { + // interpret 0 as "default location" + attachment_id = 0; + } + LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); + } + LLObjectAttachToAvatar::setObjectSelection(NULL); + + delete cb_data; } // static void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point) { - if (option == 0/*YES*/) - { - LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); - if (selectedObject) - { - const F32 MIN_STOP_DISTANCE = 1.f; // meters - const F32 ARM_LENGTH = 0.5f; // meters - const F32 SCALE_FUDGE = 1.5f; - - F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; - if (stop_distance < MIN_STOP_DISTANCE) - { - stop_distance = MIN_STOP_DISTANCE; - } - - LLVector3 walkToSpot = selectedObject->getPositionAgent(); - - // make sure we stop in front of the object - LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); - delta.normVec(); - delta = delta * 0.5f; - walkToSpot -= delta; - - // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. - CallbackData* user_data = new CallbackData(attachment_point, mReplace); - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); - gAgentCamera.clearFocusObject(); - } - } + if (option == 0/*YES*/) + { + LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); + if (selectedObject) + { + const F32 MIN_STOP_DISTANCE = 1.f; // meters + const F32 ARM_LENGTH = 0.5f; // meters + const F32 SCALE_FUDGE = 1.5f; + + F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; + if (stop_distance < MIN_STOP_DISTANCE) + { + stop_distance = MIN_STOP_DISTANCE; + } + + LLVector3 walkToSpot = selectedObject->getPositionAgent(); + + // make sure we stop in front of the object + LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); + delta.normVec(); + delta = delta * 0.5f; + walkToSpot -= delta; + + // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. + CallbackData* user_data = new CallbackData(attachment_point, mReplace); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); + gAgentCamera.clearFocusObject(); + } + } } void callback_attachment_drop(const LLSD& notification, const LLSD& response) { - // Ensure user confirmed the drop - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; - - // Called when the user clicked on an object attached to them - // and selected "Drop". - LLUUID object_id = notification["payload"]["object_id"].asUUID(); - LLViewerObject *object = gObjectList.findObject(object_id); - - if (!object) - { - LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; - return; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return; - } - - if (object->isAvatar()) - { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; - return; - } - - // reselect the object - LLSelectMgr::getInstance()->selectObjectAndFamily(object); - - LLSelectMgr::getInstance()->sendDropAttachment(); - - return; + // Ensure user confirmed the drop + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; + + // Called when the user clicked on an object attached to them + // and selected "Drop". + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLViewerObject *object = gObjectList.findObject(object_id); + + if (!object) + { + LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; + return; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return; + } + + if (object->isAvatar()) + { + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + return; + } + + // reselect the object + LLSelectMgr::getInstance()->selectObjectAndFamily(object); + + LLSelectMgr::getInstance()->sendDropAttachment(); + + return; } class LLAttachmentDrop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSD payload; - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + bool handleEvent(const LLSD& userdata) + { + LLSD payload; + LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (object) - { - payload["object_id"] = object->getID(); - } - else - { - LL_WARNS() << "Drop object not found" << LL_ENDL; - return true; - } + if (object) + { + payload["object_id"] = object->getID(); + } + else + { + LL_WARNS() << "Drop object not found" << LL_ENDL; + return true; + } - LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); - return true; - } + LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); + return true; + } }; // called from avatar pie menu class LLAttachmentDetachFromPoint : public view_listener_t { - bool handleEvent(const LLSD& user_data) - { - uuid_vec_t ids_to_remove; - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment->getNumObjects() > 0) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); - iter != attachment->mAttachedObjects.end(); - iter++) - { - LLViewerObject *attached_object = iter->get(); - ids_to_remove.push_back(attached_object->getAttachmentItemID()); - } - } - if (!ids_to_remove.empty()) - { - LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove); - } - return true; - } + bool handleEvent(const LLSD& user_data) + { + uuid_vec_t ids_to_remove; + const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); + if (attachment->getNumObjects() > 0) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); + iter != attachment->mAttachedObjects.end(); + iter++) + { + LLViewerObject *attached_object = iter->get(); + ids_to_remove.push_back(attached_object->getAttachmentItemID()); + } + } + if (!ids_to_remove.empty()) + { + LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove); + } + return true; + } }; static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { - std::string label; - LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); - if (menu) - { - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment) - { - label = data["label"].asString(); - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = attachment_iter->get(); - if (attached_object) - { - LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); - if (itemp) - { - label += std::string(" (") + itemp->getName() + std::string(")"); - break; - } - } - } - } - menu->setLabel(label); - } - return true; + std::string label; + LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); + if (menu) + { + const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); + if (attachment) + { + label = data["label"].asString(); + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object) + { + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); + if (itemp) + { + label += std::string(" (") + itemp->getName() + std::string(")"); + break; + } + } + } + } + menu->setLabel(label); + } + return true; } class LLAttachmentDetach : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // Called when the user clicked on an object attached to them - // and selected "Detach". - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return true; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return true; - } - - if (object->isAvatar()) - { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; - return true; - } - - LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); - - return true; - } + bool handleEvent(const LLSD& userdata) + { + // Called when the user clicked on an object attached to them + // and selected "Detach". + LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return true; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return true; + } + + if (object->isAvatar()) + { + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + return true; + } + + LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); + + return true; + } }; //Adding an observer for a Jira 2422 and needs to be a fetch observer @@ -7383,468 +7383,468 @@ class LLAttachmentDetach : public view_listener_t class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver { public: - LLWornItemFetchedObserver(const LLUUID& worn_item_id) : - LLInventoryFetchItemsObserver(worn_item_id) - {} - virtual ~LLWornItemFetchedObserver() {} + LLWornItemFetchedObserver(const LLUUID& worn_item_id) : + LLInventoryFetchItemsObserver(worn_item_id) + {} + virtual ~LLWornItemFetchedObserver() {} protected: - virtual void done() - { - gMenuAttachmentSelf->buildDrawLabels(); - gInventory.removeObserver(this); - delete this; - } + virtual void done() + { + gMenuAttachmentSelf->buildDrawLabels(); + gInventory.removeObserver(this); + delete this; + } }; // You can only drop items on parcels where you can build. class LLAttachmentEnableDrop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); - - //Add an inventory observer to only allow dropping the newly attached item - //once it exists in your inventory. Look at Jira 2422. - //-jwolk - - // A bug occurs when you wear/drop an item before it actively is added to your inventory - // if this is the case (you're on a slow sim, etc.) a copy of the object, - // well, a newly created object with the same properties, is placed - // in your inventory. Therefore, we disable the drop option until the - // item is in your inventory - - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLViewerJointAttachment* attachment = NULL; - LLInventoryItem* item = NULL; - - // Do not enable drop if all faces of object are not enabled - if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); - attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); - - if (attachment) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) - // so check to see if the item is in the inventory already - item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); - if (!item) - { - // Item does not exist, make an observer to enable the pie menu - // when the item finishes fetching worst case scenario - // if a fetch is already out there (being sent from a slow sim) - // we refetch and there are 2 fetches - LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); - worn_item_fetched->startFetch(); - gInventory.addObserver(worn_item_fetched); - } - } - } - } - - //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach() && can_build && item; - - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); + + //Add an inventory observer to only allow dropping the newly attached item + //once it exists in your inventory. Look at Jira 2422. + //-jwolk + + // A bug occurs when you wear/drop an item before it actively is added to your inventory + // if this is the case (you're on a slow sim, etc.) a copy of the object, + // well, a newly created object with the same properties, is placed + // in your inventory. Therefore, we disable the drop option until the + // item is in your inventory + + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLViewerJointAttachment* attachment = NULL; + LLInventoryItem* item = NULL; + + // Do not enable drop if all faces of object are not enabled + if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); + attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); + + if (attachment) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) + // so check to see if the item is in the inventory already + item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); + if (!item) + { + // Item does not exist, make an observer to enable the pie menu + // when the item finishes fetching worst case scenario + // if a fetch is already out there (being sent from a slow sim) + // we refetch and there are 2 fetches + LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); + worn_item_fetched->startFetch(); + gInventory.addObserver(worn_item_fetched); + } + } + } + } + + //now check to make sure that the item is actually in the inventory before we enable dropping it + bool new_value = enable_detach() && can_build && item; + + return new_value; + } }; BOOL enable_detach(const LLSD&) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - // Only enable detach if all faces of object are selected - if (!object || - !object->isAttachment() || - !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - return FALSE; - } + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - // Find the avatar who owns this attachment - LLViewerObject* avatar = object; - while (avatar) - { - // ...if it's you, good to detach - if (avatar->getID() == gAgent.getID()) - { - return TRUE; - } + // Only enable detach if all faces of object are selected + if (!object || + !object->isAttachment() || + !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + return FALSE; + } - avatar = (LLViewerObject*)avatar->getParent(); - } + // Find the avatar who owns this attachment + LLViewerObject* avatar = object; + while (avatar) + { + // ...if it's you, good to detach + if (avatar->getID() == gAgent.getID()) + { + return TRUE; + } + + avatar = (LLViewerObject*)avatar->getParent(); + } - return FALSE; + return FALSE; } class LLAttachmentEnableDetach : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_detach(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_detach(); + return new_value; + } }; // Used to tell if the selected object can be attached to your avatar. BOOL object_selected_and_point_valid() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::root_iterator iter = selection->root_begin(); - iter != selection->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerObject::const_child_list_t& child_list = object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - if (child->isAvatar()) - { - return FALSE; - } - } - } - - return (selection->getRootObjectCount() == 1) && - (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && - selection->getFirstRootObject()->permYouOwner() && - selection->getFirstRootObject()->flagObjectMove() && - !selection->getFirstRootObject()->flagObjectPermanent() && - !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && - (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::root_iterator iter = selection->root_begin(); + iter != selection->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + LLViewerObject::const_child_list_t& child_list = object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + if (child->isAvatar()) + { + return FALSE; + } + } + } + + return (selection->getRootObjectCount() == 1) && + (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && + selection->getFirstRootObject()->permYouOwner() && + selection->getFirstRootObject()->flagObjectMove() && + !selection->getFirstRootObject()->flagObjectPermanent() && + !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && + (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); } BOOL object_is_wearable() { - if (!isAgentAvatarValid()) - { - return FALSE; - } - if (!object_selected_and_point_valid()) - { - return FALSE; - } - if (sitting_on_selection()) - { - return FALSE; - } + if (!isAgentAvatarValid()) + { + return FALSE; + } + if (!object_selected_and_point_valid()) + { + return FALSE; + } + if (sitting_on_selection()) + { + return FALSE; + } if (!gAgentAvatarp->canAttachMoreObjects()) { return FALSE; } - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - if (node->mPermissions->getOwner() == gAgent.getID()) - { - return TRUE; - } - } - return FALSE; + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + if (node->mPermissions->getOwner() == gAgent.getID()) + { + return TRUE; + } + } + return FALSE; } class LLAttachmentPointFilled : public view_listener_t { - bool handleEvent(const LLSD& user_data) - { - bool enable = false; - LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); - if (found_it != gAgentAvatarp->mAttachmentPoints.end()) - { - enable = found_it->second->getNumObjects() > 0; - } - return enable; - } + bool handleEvent(const LLSD& user_data) + { + bool enable = false; + LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); + if (found_it != gAgentAvatarp->mAttachmentPoints.end()) + { + enable = found_it->second->getNumObjects() > 0; + } + return enable; + } }; class LLAvatarSendIM : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startIM(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::startIM(avatar->getID()); + } + return true; + } }; class LLAvatarCall : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startCall(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::startCall(avatar->getID()); + } + return true; + } }; namespace { - struct QueueObjects : public LLSelectedNodeFunctor - { - BOOL scripted; - BOOL modifiable; - LLFloaterScriptQueue* mQueue; - QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLSelectNode* node) - { - LLViewerObject* obj = node->getObject(); - if (!obj) - { - return true; - } - scripted = obj->flagScripted(); - modifiable = obj->permModify(); - - if( scripted && modifiable ) - { - mQueue->addObject(obj->getID(), node->mName); - return false; - } - else - { - return true; // fail: stop applying - } - } - }; + struct QueueObjects : public LLSelectedNodeFunctor + { + BOOL scripted; + BOOL modifiable; + LLFloaterScriptQueue* mQueue; + QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} + virtual bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + if (!obj) + { + return true; + } + scripted = obj->flagScripted(); + modifiable = obj->permModify(); + + if( scripted && modifiable ) + { + mQueue->addObject(obj->getID(), node->mName); + return false; + } + else + { + return true; // fail: stop applying + } + } + }; } bool queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { - QueueObjects func(q); - LLSelectMgr *mgr = LLSelectMgr::getInstance(); - LLObjectSelectionHandle selectHandle = mgr->getSelection(); - bool fail = selectHandle->applyToNodes(&func); - if(fail) - { - if ( !func.scripted ) - { - std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; - LLNotificationsUtil::add(noscriptmsg); - } - else if ( !func.modifiable ) - { - std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; - LLNotificationsUtil::add(nomodmsg); - } - else - { - LL_ERRS() << "Bad logic." << LL_ENDL; - } - q->closeFloater(); - } - else - { - if (!q->start()) - { - LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; - } - } - return !fail; + QueueObjects func(q); + LLSelectMgr *mgr = LLSelectMgr::getInstance(); + LLObjectSelectionHandle selectHandle = mgr->getSelection(); + bool fail = selectHandle->applyToNodes(&func); + if(fail) + { + if ( !func.scripted ) + { + std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; + LLNotificationsUtil::add(noscriptmsg); + } + else if ( !func.modifiable ) + { + std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; + LLNotificationsUtil::add(nomodmsg); + } + else + { + LL_ERRS() << "Bad logic." << LL_ENDL; + } + q->closeFloater(); + } + else + { + if (!q->start()) + { + LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; + } + } + return !fail; } class LLToolsSelectedScriptAction : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string action = userdata.asString(); - bool mono = false; - std::string msg, name; - std::string title; - if (action == "compile mono") - { - name = "compile_queue"; - mono = true; - msg = "Recompile"; - title = LLTrans::getString("CompileQueueTitle"); - } - if (action == "compile lsl") - { - name = "compile_queue"; - msg = "Recompile"; - title = LLTrans::getString("CompileQueueTitle"); - } - else if (action == "reset") - { - name = "reset_queue"; - msg = "Reset"; - title = LLTrans::getString("ResetQueueTitle"); - } - else if (action == "start") - { - name = "start_queue"; - msg = "SetRunning"; - title = LLTrans::getString("RunQueueTitle"); - } - else if (action == "stop") - { - name = "stop_queue"; - msg = "SetRunningNot"; - title = LLTrans::getString("NotRunQueueTitle"); - } - LLUUID id; id.generate(); - - LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id)); - if (queue) - { - queue->setMono(mono); - if (queue_actions(queue, msg)) - { - queue->setTitle(title); - } - } - else - { - LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string action = userdata.asString(); + bool mono = false; + std::string msg, name; + std::string title; + if (action == "compile mono") + { + name = "compile_queue"; + mono = true; + msg = "Recompile"; + title = LLTrans::getString("CompileQueueTitle"); + } + if (action == "compile lsl") + { + name = "compile_queue"; + msg = "Recompile"; + title = LLTrans::getString("CompileQueueTitle"); + } + else if (action == "reset") + { + name = "reset_queue"; + msg = "Reset"; + title = LLTrans::getString("ResetQueueTitle"); + } + else if (action == "start") + { + name = "start_queue"; + msg = "SetRunning"; + title = LLTrans::getString("RunQueueTitle"); + } + else if (action == "stop") + { + name = "stop_queue"; + msg = "SetRunningNot"; + title = LLTrans::getString("NotRunQueueTitle"); + } + LLUUID id; id.generate(); + + LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id)); + if (queue) + { + queue->setMono(mono); + if (queue_actions(queue, msg)) + { + queue->setTitle(title); + } + } + else + { + LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; + } + return true; + } }; void handle_selected_texture_info(void*) { - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Texture info for: "); - msg.append(node->mName); - - U8 te_count = node->getObject()->getNumTEs(); - // map from texture ID to list of faces using it - typedef std::map< LLUUID, std::vector<U8> > map_t; - map_t faces_per_texture; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - LLViewerTexture* img = node->getObject()->getTEImage(i); - LLUUID image_id = img->getID(); - faces_per_texture[image_id].push_back(i); - } - // Per-texture, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) - { - U8 te = it->second[0]; - LLViewerTexture* img = node->getObject()->getTEImage(te); - S32 height = img->getHeight(); - S32 width = img->getWidth(); - S32 components = img->getComponents(); - msg.append(llformat("\n%dx%d %s on face ", - width, - height, - (components == 4 ? "alpha" : "opaque"))); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - } - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } + for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + LLSelectNode* node = *iter; + + std::string msg; + msg.assign("Texture info for: "); + msg.append(node->mName); + + U8 te_count = node->getObject()->getNumTEs(); + // map from texture ID to list of faces using it + typedef std::map< LLUUID, std::vector<U8> > map_t; + map_t faces_per_texture; + for (U8 i = 0; i < te_count; i++) + { + if (!node->isTESelected(i)) continue; + + LLViewerTexture* img = node->getObject()->getTEImage(i); + LLUUID image_id = img->getID(); + faces_per_texture[image_id].push_back(i); + } + // Per-texture, dump which faces are using it. + map_t::iterator it; + for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) + { + U8 te = it->second[0]; + LLViewerTexture* img = node->getObject()->getTEImage(te); + S32 height = img->getHeight(); + S32 width = img->getWidth(); + S32 components = img->getComponents(); + msg.append(llformat("\n%dx%d %s on face ", + width, + height, + (components == 4 ? "alpha" : "opaque"))); + for (U8 i = 0; i < it->second.size(); ++i) + { + msg.append( llformat("%d ", (S32)(it->second[i]))); + } + } + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); + } } void handle_selected_material_info() { - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Material info for: \n"); - msg.append(node->mName); - - U8 te_count = node->getObject()->getNumTEs(); - // map from material ID to list of faces using it - typedef std::map<LLMaterialID, std::vector<U8> > map_t; - map_t faces_per_material; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID(); - faces_per_material[material_id].push_back(i); - } - // Per-material, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it) - { - const LLMaterialID& material_id = it->first; - msg += llformat("%s on face ", material_id.asString().c_str()); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - msg.append("\n"); - } - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } + for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + LLSelectNode* node = *iter; + + std::string msg; + msg.assign("Material info for: \n"); + msg.append(node->mName); + + U8 te_count = node->getObject()->getNumTEs(); + // map from material ID to list of faces using it + typedef std::map<LLMaterialID, std::vector<U8> > map_t; + map_t faces_per_material; + for (U8 i = 0; i < te_count; i++) + { + if (!node->isTESelected(i)) continue; + + const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID(); + faces_per_material[material_id].push_back(i); + } + // Per-material, dump which faces are using it. + map_t::iterator it; + for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it) + { + const LLMaterialID& material_id = it->first; + msg += llformat("%s on face ", material_id.asString().c_str()); + for (U8 i = 0; i < it->second.size(); ++i) + { + msg.append( llformat("%d ", (S32)(it->second[i]))); + } + msg.append("\n"); + } + + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); + } } void handle_test_male(void*) { - LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); - //gGestureList.requestResetFromServer( TRUE ); + LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); + //gGestureList.requestResetFromServer( TRUE ); } void handle_test_female(void*) { - LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); - //gGestureList.requestResetFromServer( FALSE ); + LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); + //gGestureList.requestResetFromServer( FALSE ); } void handle_dump_attachments(void*) { - if(!isAgentAvatarValid()) return; - - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - S32 key = curiter->first; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = attachment_iter->get(); - BOOL visible = (attached_object != NULL && - attached_object->mDrawable.notNull() && - !attached_object->mDrawable->isRenderType(0)); - LLVector3 pos; - if (visible) pos = attached_object->mDrawable->getPosition(); - LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() - << (attached_object ? " present " : " absent ") - << (visible ? "visible " : "invisible ") - << " at " << pos - << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) - << LL_ENDL; - } - } + if(!isAgentAvatarValid()) return; + + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + S32 key = curiter->first; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = attachment_iter->get(); + BOOL visible = (attached_object != NULL && + attached_object->mDrawable.notNull() && + !attached_object->mDrawable->isRenderType(0)); + LLVector3 pos; + if (visible) pos = attached_object->mDrawable->getPosition(); + LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() + << (attached_object ? " present " : " absent ") + << (visible ? "visible " : "invisible ") + << " at " << pos + << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) + << LL_ENDL; + } + } } @@ -7853,369 +7853,369 @@ class LLToggleControl : public view_listener_t { protected: - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); + return true; + } }; class LLCheckControl : public view_listener_t { - bool handleEvent( const LLSD& userdata) - { - std::string callback_data = userdata.asString(); - bool new_value = gSavedSettings.getBOOL(callback_data); - return new_value; - } + bool handleEvent( const LLSD& userdata) + { + std::string callback_data = userdata.asString(); + bool new_value = gSavedSettings.getBOOL(callback_data); + return new_value; + } }; // not so generic class LLAdvancedCheckRenderShadowOption: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // is off - { - return false; - } - else // is on - { - return true; - } - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + S32 current_shadow_level = gSavedSettings.getS32(control_name); + if (current_shadow_level == 0) // is off + { + return false; + } + else // is on + { + return true; + } + } }; class LLAdvancedClickRenderShadowOption: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // upgrade to level 2 - { - gSavedSettings.setS32(control_name, 2); - } - else // downgrade to level 0 - { - gSavedSettings.setS32(control_name, 0); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + S32 current_shadow_level = gSavedSettings.getS32(control_name); + if (current_shadow_level == 0) // upgrade to level 2 + { + gSavedSettings.setS32(control_name, 2); + } + else // downgrade to level 0 + { + gSavedSettings.setS32(control_name, 0); + } + return true; + } }; class LLAdvancedClickRenderProfile: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gShaderProfileFrame = TRUE; - return true; - } + bool handleEvent(const LLSD& userdata) + { + gShaderProfileFrame = TRUE; + return true; + } }; F32 gpu_benchmark(); class LLAdvancedClickRenderBenchmark: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gpu_benchmark(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gpu_benchmark(); + return true; + } }; // these are used in the gl menus to set control values that require shader recompilation class LLToggleShaderControl : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); LLPipeline::refreshCachedSettings(); LLViewerShaderMgr::instance()->setShaders(); - return !checked; - } + return !checked; + } }; void menu_toggle_attached_lights(void* user_data) { - LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); + LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); } void menu_toggle_attached_particles(void* user_data) { - LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } class LLAdvancedHandleAttachedLightParticles: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); - // toggle the control - gSavedSettings.setBOOL(control_name, - !gSavedSettings.getBOOL(control_name)); + // toggle the control + gSavedSettings.setBOOL(control_name, + !gSavedSettings.getBOOL(control_name)); - // update internal flags - if (control_name == "RenderAttachedLights") - { - menu_toggle_attached_lights(NULL); - } - else if (control_name == "RenderAttachedParticles") - { - menu_toggle_attached_particles(NULL); - } - return true; - } + // update internal flags + if (control_name == "RenderAttachedLights") + { + menu_toggle_attached_lights(NULL); + } + else if (control_name == "RenderAttachedParticles") + { + menu_toggle_attached_particles(NULL); + } + return true; + } }; class LLSomethingSelected : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); + return new_value; + } }; class LLSomethingSelectedNoHUD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); + return new_value; + } }; static bool is_editable_selected() { - return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); } class LLEditableSelected : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return is_editable_selected(); - } + bool handleEvent(const LLSD& userdata) + { + return is_editable_selected(); + } }; class LLEditableSelectedMono : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - LLViewerRegion* region = gAgent.getRegion(); - if(region && gMenuHolder) - { - bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); - new_value = is_editable_selected() && have_cap; - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = false; + LLViewerRegion* region = gAgent.getRegion(); + if(region && gMenuHolder) + { + bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); + new_value = is_editable_selected() && have_cap; + } + return new_value; + } }; bool enable_object_take_copy() { - bool all_valid = false; - if (LLSelectMgr::getInstance()) - { - if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 0) - { - all_valid = true; + bool all_valid = false; + if (LLSelectMgr::getInstance()) + { + if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 0) + { + all_valid = true; #ifndef HACKED_GODLIKE_VIEWER # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (LLGridManager::getInstance()->isInProductionGrid() + if (LLGridManager::getInstance()->isInProductionGrid() || !gAgent.isGodlike()) # endif - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return (!obj->permCopy() || obj->isAttachment()); - } - } func; - const bool firstonly = true; - bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - all_valid = !any_invalid; - } + { + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* obj) + { + return (!obj->permCopy() || obj->isAttachment()); + } + } func; + const bool firstonly = true; + bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); + all_valid = !any_invalid; + } #endif // HACKED_GODLIKE_VIEWER - } - } + } + } - return all_valid; + return all_valid; } class LLHasAsset : public LLInventoryCollectFunctor { public: - LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} - virtual ~LLHasAsset() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL hasAsset() const { return mHasAsset; } + LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} + virtual ~LLHasAsset() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + BOOL hasAsset() const { return mHasAsset; } protected: - LLUUID mAssetID; - BOOL mHasAsset; + LLUUID mAssetID; + BOOL mHasAsset; }; bool LLHasAsset::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item && item->getAssetUUID() == mAssetID) - { - mHasAsset = TRUE; - } - return FALSE; + if(item && item->getAssetUUID() == mAssetID) + { + mHasAsset = TRUE; + } + return FALSE; } BOOL enable_save_into_task_inventory(void*) { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - LLViewerObject* obj = node->getObject(); - if( obj && !obj->isAttachment() ) - { - return TRUE; - } - } - return FALSE; + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if(node && (node->mValid) && (!node->mFromTaskID.isNull())) + { + // *TODO: check to see if the fromtaskid object exists. + LLViewerObject* obj = node->getObject(); + if( obj && !obj->isAttachment() ) + { + return TRUE; + } + } + return FALSE; } class LLToolsEnableSaveToObjectInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_save_into_task_inventory(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_save_into_task_inventory(NULL); + return new_value; + } }; class LLToggleHowTo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); + return true; + } }; class LLViewEnableMouselook : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // You can't go directly from customize avatar to mouselook. - // TODO: write code with appropriate dialogs to handle this transition. - bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // You can't go directly from customize avatar to mouselook. + // TODO: write code with appropriate dialogs to handle this transition. + bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); + return new_value; + } }; class LLToolsEnableToolNotPie : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); + return new_value; + } }; class LLWorldEnableCreateLandmark : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return !LLLandmarkActions::landmarkAlreadyExists(); - } + bool handleEvent(const LLSD& userdata) + { + return !LLLandmarkActions::landmarkAlreadyExists(); + } }; class LLWorldEnableSetHomeLocation : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.isGodlike() || - (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgent.isGodlike() || + (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); + return new_value; + } }; class LLWorldEnableTeleportHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerRegion* regionp = gAgent.getRegion(); - bool agent_on_prelude = (regionp && regionp->isPrelude()); - bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; - return enable_teleport_home; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerRegion* regionp = gAgent.getRegion(); + bool agent_on_prelude = (regionp && regionp->isPrelude()); + bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; + return enable_teleport_home; + } }; BOOL enable_god_full(void*) { - return gAgent.getGodLevel() >= GOD_FULL; + return gAgent.getGodLevel() >= GOD_FULL; } BOOL enable_god_liaison(void*) { - return gAgent.getGodLevel() >= GOD_LIAISON; + return gAgent.getGodLevel() >= GOD_LIAISON; } bool is_god_customer_service() { - return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; + return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; } BOOL enable_god_basic(void*) { - return gAgent.getGodLevel() > GOD_NOT; + return gAgent.getGodLevel() > GOD_NOT; } void toggle_show_xui_names(void *) { - gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); + gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); } BOOL check_show_xui_names(void *) { - return gSavedSettings.getBOOL("DebugShowXUINames"); + return gSavedSettings.getBOOL("DebugShowXUINames"); } class LLToolsSelectOnlyMyObjects : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); - gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); + gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); - return true; - } + return true; + } }; class LLToolsSelectOnlyMovableObjects : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); - gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); + gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); - return true; - } + return true; + } }; class LLToolsSelectInvisibleObjects : public view_listener_t @@ -8244,178 +8244,178 @@ class LLToolsSelectReflectionProbes: public view_listener_t class LLToolsSelectBySurrounding : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; + bool handleEvent(const LLSD& userdata) + { + LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; - gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); - return true; - } + gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); + return true; + } }; class LLToolsShowHiddenSelection : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // TomY TODO Merge these - LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; + bool handleEvent(const LLSD& userdata) + { + // TomY TODO Merge these + LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; - gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); - return true; - } + gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); + return true; + } }; class LLToolsShowSelectionLightRadius : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // TomY TODO merge these - LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; + bool handleEvent(const LLSD& userdata) + { + // TomY TODO merge these + LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; - gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); - return true; - } + gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); + return true; + } }; class LLToolsEditLinkedParts : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); - gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); - if (select_individuals) - { - LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); - } - else - { - LLSelectMgr::getInstance()->promoteSelectionToRoot(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); + gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); + if (select_individuals) + { + LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); + } + else + { + LLSelectMgr::getInstance()->promoteSelectionToRoot(); + } + return true; + } }; void reload_vertex_shader(void *) { - //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP + //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP } void handle_dump_avatar_local_textures(void*) { - gAgentAvatarp->dumpLocalTextures(); + gAgentAvatarp->dumpLocalTextures(); } void handle_dump_timers() { - LLTrace::BlockTimer::dumpCurTimes(); + LLTrace::BlockTimer::dumpCurTimes(); } void handle_debug_avatar_textures(void*) { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); - } + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); + } } void handle_grab_baked_texture(void* data) { - EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); - if (!isAgentAvatarValid()) return; - - const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); - LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << LL_ENDL; - LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; - LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - if(folder_id.notNull()) - { - std::string name; - name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; - - LLUUID item_id; - item_id.generate(); - LLPermissions perm; - perm.init(gAgentID, - gAgentID, - LLUUID::null, - LLUUID::null); - U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; - perm.initMasks(PERM_ALL, - PERM_ALL, - PERM_NONE, - PERM_NONE, - next_owner_perm); - time_t creation_date_now = time_corrected(); - LLPointer<LLViewerInventoryItem> item - = new LLViewerInventoryItem(item_id, - folder_id, - perm, - asset_id, - asset_type, - inv_type, - name, - LLStringUtil::null, - LLSaleInfo::DEFAULT, - LLInventoryItemFlags::II_FLAGS_NONE, - creation_date_now); - - item->updateServer(TRUE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - // Show the preview panel for textures to let - // user know that the image is now in inventory. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if(active_panel) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - active_panel->openSelected(); - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); - } - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } + EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); + if (!isAgentAvatarValid()) return; + + const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); + LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << LL_ENDL; + LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; + LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); + if(folder_id.notNull()) + { + std::string name; + name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; + + LLUUID item_id; + item_id.generate(); + LLPermissions perm; + perm.init(gAgentID, + gAgentID, + LLUUID::null, + LLUUID::null); + U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; + perm.initMasks(PERM_ALL, + PERM_ALL, + PERM_NONE, + PERM_NONE, + next_owner_perm); + time_t creation_date_now = time_corrected(); + LLPointer<LLViewerInventoryItem> item + = new LLViewerInventoryItem(item_id, + folder_id, + perm, + asset_id, + asset_type, + inv_type, + name, + LLStringUtil::null, + LLSaleInfo::DEFAULT, + LLInventoryItemFlags::II_FLAGS_NONE, + creation_date_now); + + item->updateServer(TRUE); + gInventory.updateItem(item); + gInventory.notifyObservers(); + + // Show the preview panel for textures to let + // user know that the image is now in inventory. + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if(active_panel) + { + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); + + active_panel->setSelection(item_id, TAKE_FOCUS_NO); + active_panel->openSelected(); + //LLFloaterInventory::dumpSelectionInformation((void*)view); + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus_ctrl); + } + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } } BOOL enable_grab_baked_texture(void* data) { - EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); - if (isAgentAvatarValid()) - { - return gAgentAvatarp->canGrabBakedTexture(index); - } - return FALSE; + EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); + if (isAgentAvatarValid()) + { + return gAgentAvatarp->canGrabBakedTexture(index); + } + return FALSE; } // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) { - if (object) - { - if( object->isAttachment() ) - { - do - { - object = (LLViewerObject*) object->getParent(); - } - while( object && !object->isAvatar() ); - } - else if( !object->isAvatar() ) - { - object = NULL; - } - } + if (object) + { + if( object->isAttachment() ) + { + do + { + object = (LLViewerObject*) object->getParent(); + } + while( object && !object->isAvatar() ); + } + else if( !object->isAvatar() ) + { + object = NULL; + } + } - return (LLVOAvatar*) object; + return (LLVOAvatar*) object; } @@ -8423,13 +8423,13 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ) { - return find_avatar_from_object( gObjectList.findObject(object_id) ); + return find_avatar_from_object( gObjectList.findObject(object_id) ); } void handle_disconnect_viewer(void *) { - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); } void force_error_breakpoint(void *) @@ -8484,30 +8484,30 @@ void force_error_thread_crash(void *) class LLToolsUseSelectionForGrid : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::getInstance()->clearGridObjects(); - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* objectp) - { - LLSelectMgr::getInstance()->addGridObject(objectp); - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); - LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); - LLFloaterTools::setGridMode((S32)GRID_MODE_REF_OBJECT); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLSelectMgr::getInstance()->clearGridObjects(); + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* objectp) + { + LLSelectMgr::getInstance()->addGridObject(objectp); + return true; + } + } func; + LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); + LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); + LLFloaterTools::setGridMode((S32)GRID_MODE_REF_OBJECT); + return true; + } }; void handle_test_load_url(void*) { - LLWeb::loadURL(""); - LLWeb::loadURL("hacker://www.google.com/"); - LLWeb::loadURL("http"); - LLWeb::loadURL("http://www.google.com/"); + LLWeb::loadURL(""); + LLWeb::loadURL("hacker://www.google.com/"); + LLWeb::loadURL("http"); + LLWeb::loadURL("http://www.google.com/"); } // @@ -8521,86 +8521,86 @@ LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p BOOL LLViewerMenuHolderGL::hideMenus() { - BOOL handled = FALSE; - - if (LLMenuHolderGL::hideMenus()) - { - handled = TRUE; - } + BOOL handled = FALSE; + + if (LLMenuHolderGL::hideMenus()) + { + handled = TRUE; + } - // drop pie menu selection - mParcelSelection = NULL; - mObjectSelection = NULL; + // drop pie menu selection + mParcelSelection = NULL; + mObjectSelection = NULL; - if (gMenuBarView) - { - gMenuBarView->clearHoverItem(); - gMenuBarView->resetMenuTrigger(); - } + if (gMenuBarView) + { + gMenuBarView->clearHoverItem(); + gMenuBarView->resetMenuTrigger(); + } - return handled; + return handled; } -void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection) -{ - mParcelSelection = selection; +void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection) +{ + mParcelSelection = selection; } -void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection) -{ - mObjectSelection = selection; +void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection) +{ + mObjectSelection = selection; } const LLRect LLViewerMenuHolderGL::getMenuRect() const { - return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); + return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); } void handle_web_browser_test(const LLSD& param) { - std::string url = param.asString(); - if (url.empty()) - { - url = "about:blank"; - } - LLWeb::loadURLInternal(url); + std::string url = param.asString(); + if (url.empty()) + { + url = "about:blank"; + } + LLWeb::loadURLInternal(url); } bool callback_clear_cache_immediately(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - //clear cache - LLAppViewer::instance()->purgeCacheImmediate(); - } + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + //clear cache + LLAppViewer::instance()->purgeCacheImmediate(); + } - return false; + return false; } void handle_cache_clear_immediately() { - LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); + LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); } void handle_web_content_test(const LLSD& param) { - std::string url = param.asString(); - LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); + std::string url = param.asString(); + LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); } void handle_show_url(const LLSD& param) { - std::string url = param.asString(); - if (LLWeb::useExternalBrowser(url)) - { - LLWeb::loadURLExternal(url); - } - else - { - LLWeb::loadURLInternal(url); - } + std::string url = param.asString(); + if (LLWeb::useExternalBrowser(url)) + { + LLWeb::loadURLExternal(url); + } + else + { + LLWeb::loadURLInternal(url); + } } @@ -8612,378 +8612,378 @@ void handle_report_bug(const LLSD& param) void handle_buy_currency_test(void*) { - std::string url = - "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; + std::string url = + "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; - LLStringUtil::format_map_t replace; - replace["[AGENT_ID]"] = gAgent.getID().asString(); - replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); - replace["[LANGUAGE]"] = LLUI::getLanguage(); - LLStringUtil::format(url, replace); + LLStringUtil::format_map_t replace; + replace["[AGENT_ID]"] = gAgent.getID().asString(); + replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); + replace["[LANGUAGE]"] = LLUI::getLanguage(); + LLStringUtil::format(url, replace); - LL_INFOS() << "buy currency url " << url << LL_ENDL; + LL_INFOS() << "buy currency url " << url << LL_ENDL; - LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); + LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); } // SUNSHINE CLEANUP - is only the request update at the end needed now? void handle_rebake_textures(void*) { - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) return; - // Slam pending upload count to "unstick" things - bool slam_for_debug = true; - gAgentAvatarp->forceBakeAllTextures(slam_for_debug); - if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) - { - LLAppearanceMgr::instance().requestServerAppearanceUpdate(); - } + // Slam pending upload count to "unstick" things + bool slam_for_debug = true; + gAgentAvatarp->forceBakeAllTextures(slam_for_debug); + if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) + { + LLAppearanceMgr::instance().requestServerAppearanceUpdate(); + } } void toggle_visibility(void* user_data) { - LLView* viewp = (LLView*)user_data; - viewp->setVisible(!viewp->getVisible()); + LLView* viewp = (LLView*)user_data; + viewp->setVisible(!viewp->getVisible()); } BOOL get_visibility(void* user_data) { - LLView* viewp = (LLView*)user_data; - return viewp->getVisible(); + LLView* viewp = (LLView*)user_data; + return viewp->getVisible(); } class LLViewShowHoverTips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); + return true; + } }; class LLViewCheckShowHoverTips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); + return new_value; + } }; class LLViewHighlightTransparent : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; + bool handleEvent(const LLSD& userdata) + { + LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; // invisible objects skip building their render batches unless sShowDebugAlpha is true, so rebuild batches whenever toggling this flag - gPipeline.rebuildDrawInfo(); - return true; - } + gPipeline.rebuildDrawInfo(); + return true; + } }; class LLViewCheckHighlightTransparent : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; + return new_value; + } }; class LLViewBeaconWidth : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string width = userdata.asString(); - if(width == "1") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 1); - } - else if(width == "4") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 4); - } - else if(width == "16") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 16); - } - else if(width == "32") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 32); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string width = userdata.asString(); + if(width == "1") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 1); + } + else if(width == "4") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 4); + } + else if(width == "16") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 16); + } + else if(width == "32") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 32); + } + + return true; + } }; class LLViewToggleBeacon : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - if (beacon == "scriptsbeacon") - { - LLPipeline::toggleRenderScriptedBeacons(); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) - { - LLPipeline::toggleRenderScriptedTouchBeacons(); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); - } - } - else if (beacon == "physicalbeacon") - { - LLPipeline::toggleRenderPhysicalBeacons(); - gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons() ); - } - else if (beacon == "moapbeacon") - { - LLPipeline::toggleRenderMOAPBeacons(); - gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons() ); - } - else if (beacon == "soundsbeacon") - { - LLPipeline::toggleRenderSoundBeacons(); - gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons() ); - } - else if (beacon == "particlesbeacon") - { - LLPipeline::toggleRenderParticleBeacons(); - gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons() ); - } - else if (beacon == "scripttouchbeacon") - { - LLPipeline::toggleRenderScriptedTouchBeacons(); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) - { - LLPipeline::toggleRenderScriptedBeacons(); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); - } - } - else if (beacon == "sunbeacon") - { - gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); - } - else if (beacon == "moonbeacon") - { - gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); - } - else if (beacon == "renderbeacons") - { - LLPipeline::toggleRenderBeacons(); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) - { - LLPipeline::toggleRenderHighlights(); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); - } - } - else if (beacon == "renderhighlights") - { - LLPipeline::toggleRenderHighlights(); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) - { - LLPipeline::toggleRenderBeacons(); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); - } - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + if (beacon == "scriptsbeacon") + { + LLPipeline::toggleRenderScriptedBeacons(); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) + { + LLPipeline::toggleRenderScriptedTouchBeacons(); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); + } + } + else if (beacon == "physicalbeacon") + { + LLPipeline::toggleRenderPhysicalBeacons(); + gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons() ); + } + else if (beacon == "moapbeacon") + { + LLPipeline::toggleRenderMOAPBeacons(); + gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons() ); + } + else if (beacon == "soundsbeacon") + { + LLPipeline::toggleRenderSoundBeacons(); + gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons() ); + } + else if (beacon == "particlesbeacon") + { + LLPipeline::toggleRenderParticleBeacons(); + gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons() ); + } + else if (beacon == "scripttouchbeacon") + { + LLPipeline::toggleRenderScriptedTouchBeacons(); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) + { + LLPipeline::toggleRenderScriptedBeacons(); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); + } + } + else if (beacon == "sunbeacon") + { + gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); + } + else if (beacon == "moonbeacon") + { + gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); + } + else if (beacon == "renderbeacons") + { + LLPipeline::toggleRenderBeacons(); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) + { + LLPipeline::toggleRenderHighlights(); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); + } + } + else if (beacon == "renderhighlights") + { + LLPipeline::toggleRenderHighlights(); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) + { + LLPipeline::toggleRenderBeacons(); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); + } + } + + return true; + } }; class LLViewCheckBeaconEnabled : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - bool new_value = false; - if (beacon == "scriptsbeacon") - { - new_value = gSavedSettings.getBOOL( "scriptsbeacon"); - LLPipeline::setRenderScriptedBeacons(new_value); - } - else if (beacon == "moapbeacon") - { - new_value = gSavedSettings.getBOOL( "moapbeacon"); - LLPipeline::setRenderMOAPBeacons(new_value); - } - else if (beacon == "physicalbeacon") - { - new_value = gSavedSettings.getBOOL( "physicalbeacon"); - LLPipeline::setRenderPhysicalBeacons(new_value); - } - else if (beacon == "soundsbeacon") - { - new_value = gSavedSettings.getBOOL( "soundsbeacon"); - LLPipeline::setRenderSoundBeacons(new_value); - } - else if (beacon == "particlesbeacon") - { - new_value = gSavedSettings.getBOOL( "particlesbeacon"); - LLPipeline::setRenderParticleBeacons(new_value); - } - else if (beacon == "scripttouchbeacon") - { - new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); - LLPipeline::setRenderScriptedTouchBeacons(new_value); - } - else if (beacon == "renderbeacons") - { - new_value = gSavedSettings.getBOOL( "renderbeacons"); - LLPipeline::setRenderBeacons(new_value); - } - else if (beacon == "renderhighlights") - { - new_value = gSavedSettings.getBOOL( "renderhighlights"); - LLPipeline::setRenderHighlights(new_value); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + bool new_value = false; + if (beacon == "scriptsbeacon") + { + new_value = gSavedSettings.getBOOL( "scriptsbeacon"); + LLPipeline::setRenderScriptedBeacons(new_value); + } + else if (beacon == "moapbeacon") + { + new_value = gSavedSettings.getBOOL( "moapbeacon"); + LLPipeline::setRenderMOAPBeacons(new_value); + } + else if (beacon == "physicalbeacon") + { + new_value = gSavedSettings.getBOOL( "physicalbeacon"); + LLPipeline::setRenderPhysicalBeacons(new_value); + } + else if (beacon == "soundsbeacon") + { + new_value = gSavedSettings.getBOOL( "soundsbeacon"); + LLPipeline::setRenderSoundBeacons(new_value); + } + else if (beacon == "particlesbeacon") + { + new_value = gSavedSettings.getBOOL( "particlesbeacon"); + LLPipeline::setRenderParticleBeacons(new_value); + } + else if (beacon == "scripttouchbeacon") + { + new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); + LLPipeline::setRenderScriptedTouchBeacons(new_value); + } + else if (beacon == "renderbeacons") + { + new_value = gSavedSettings.getBOOL( "renderbeacons"); + LLPipeline::setRenderBeacons(new_value); + } + else if (beacon == "renderhighlights") + { + new_value = gSavedSettings.getBOOL( "renderhighlights"); + LLPipeline::setRenderHighlights(new_value); + } + return new_value; + } }; class LLViewToggleRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - if (type == "hideparticles") - { - LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string type = userdata.asString(); + if (type == "hideparticles") + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); + } + return true; + } }; class LLViewCheckRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - bool new_value = false; - if (type == "hideparticles") - { - new_value = LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string type = userdata.asString(); + bool new_value = false; + if (type == "hideparticles") + { + new_value = LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES); + } + return new_value; + } }; class LLViewStatusAway : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.isInitialized() && gAgent.getAFK()); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.isInitialized() && gAgent.getAFK()); + } }; class LLViewStatusDoNotDisturb : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.isInitialized() && gAgent.isDoNotDisturb()); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.isInitialized() && gAgent.isDoNotDisturb()); + } }; class LLViewShowHUDAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; + return true; + } }; class LLViewCheckHUDAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPipeline::sShowHUDAttachments; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPipeline::sShowHUDAttachments; + return new_value; + } }; class LLEditEnableTakeOff : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - return LLAgentWearables::selfHasWearable(type); - return false; - } + bool handleEvent(const LLSD& userdata) + { + std::string clothing = userdata.asString(); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); + if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) + return LLAgentWearables::selfHasWearable(type); + return false; + } }; class LLEditTakeOff : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - if (clothing == "all") - LLAppearanceMgr::instance().removeAllClothesFromAvatar(); - else - { - LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE - && type < LLWearableType::WT_COUNT - && (gAgentWearables.getWearableCount(type) > 0)) - { - // MULTI-WEARABLES: assuming user wanted to remove top shirt. - U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; - LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); - LLAppearanceMgr::instance().removeItemFromAvatar(item_id); - } - - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string clothing = userdata.asString(); + if (clothing == "all") + LLAppearanceMgr::instance().removeAllClothesFromAvatar(); + else + { + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); + if (type >= LLWearableType::WT_SHAPE + && type < LLWearableType::WT_COUNT + && (gAgentWearables.getWearableCount(type) > 0)) + { + // MULTI-WEARABLES: assuming user wanted to remove top shirt. + U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; + LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); + LLAppearanceMgr::instance().removeItemFromAvatar(item_id); + } + + } + return true; + } }; class LLToolsSelectTool : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string tool_name = userdata.asString(); - if (tool_name == "focus") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); - } - else if (tool_name == "move") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); - } - else if (tool_name == "edit") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); - } - else if (tool_name == "create") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); - } - else if (tool_name == "land") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); - } - - // Note: if floater is not visible LLViewerWindow::updateLayout() will - // attempt to open it, but it won't bring it to front or de-minimize. - if (gFloaterTools && (gFloaterTools->isMinimized() || !gFloaterTools->isShown() || !gFloaterTools->isFrontmost())) - { - gFloaterTools->setMinimized(FALSE); - gFloaterTools->openFloater(); - gFloaterTools->setVisibleAndFrontmost(TRUE); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string tool_name = userdata.asString(); + if (tool_name == "focus") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); + } + else if (tool_name == "move") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); + } + else if (tool_name == "edit") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); + } + else if (tool_name == "create") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); + } + else if (tool_name == "land") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); + } + + // Note: if floater is not visible LLViewerWindow::updateLayout() will + // attempt to open it, but it won't bring it to front or de-minimize. + if (gFloaterTools && (gFloaterTools->isMinimized() || !gFloaterTools->isShown() || !gFloaterTools->isFrontmost())) + { + gFloaterTools->setMinimized(FALSE); + gFloaterTools->openFloater(); + gFloaterTools->setVisibleAndFrontmost(TRUE); + } + return true; + } }; /// WINDLIGHT callbacks @@ -9002,7 +9002,7 @@ void defocusEnvFloaters() } } -bool handle_env_setting_event(std::string event_name) +bool handle_env_setting_event(std::string event_name) { if (event_name == "sunrise") { @@ -9066,126 +9066,126 @@ bool handle_env_setting_event(std::string event_name) } class LLWorldEnvSettings : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { +{ + bool handleEvent(const LLSD& userdata) + { handle_env_setting_event(userdata.asString()); - return true; - } + return true; + } }; class LLWorldEnableEnvSettings : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool result = false; - std::string event_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + bool result = false; + std::string event_name = userdata.asString(); if (event_name == "pause_clouds") - { + { return LLEnvironment::instance().isCloudScrollPaused(); - } + } LLSettingsSky::ptr_t sky = LLEnvironment::instance().getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL); - if (!sky) - { - return (event_name == "region"); - } + if (!sky) + { + return (event_name == "region"); + } std::string skyname = (sky) ? sky->getName() : ""; LLUUID skyid = (sky) ? sky->getAssetId() : LLUUID::null; - if (event_name == "sunrise") - { + if (event_name == "sunrise") + { result = (skyid == LLEnvironment::KNOWN_SKY_SUNRISE); - } - else if (event_name == "noon") - { + } + else if (event_name == "noon") + { result = (skyid == LLEnvironment::KNOWN_SKY_MIDDAY); - } + } else if (event_name == "legacy noon") { result = (skyid == LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY); } - else if (event_name == "sunset") - { + else if (event_name == "sunset") + { result = (skyid == LLEnvironment::KNOWN_SKY_SUNSET); - } - else if (event_name == "midnight") - { + } + else if (event_name == "midnight") + { result = (skyid == LLEnvironment::KNOWN_SKY_MIDNIGHT); - } - else if (event_name == "region") - { - return false; - } - else - { - LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; - } - return result; - } + } + else if (event_name == "region") + { + return false; + } + else + { + LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; + } + return result; + } }; class LLWorldEnvPreset : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string item = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string item = userdata.asString(); - if (item == "new_water") - { + if (item == "new_water") + { LLFloaterReg::showInstance("env_fixed_environmentent_water", "new"); - } - else if (item == "edit_water") - { + } + else if (item == "edit_water") + { LLFloaterReg::showInstance("env_fixed_environmentent_water", "edit"); - } - else if (item == "new_sky") - { + } + else if (item == "new_sky") + { LLFloaterReg::showInstance("env_fixed_environmentent_sky", "new"); - } - else if (item == "edit_sky") - { + } + else if (item == "edit_sky") + { LLFloaterReg::showInstance("env_fixed_environmentent_sky", "edit"); - } - else if (item == "new_day_cycle") - { + } + else if (item == "new_day_cycle") + { LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); - } - else if (item == "edit_day_cycle") - { - LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); - } - else - { - LL_WARNS() << "Unknown item selected" << LL_ENDL; - } + } + else if (item == "edit_day_cycle") + { + LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); + } + else + { + LL_WARNS() << "Unknown item selected" << LL_ENDL; + } - return true; - } + return true; + } }; class LLWorldEnableEnvPreset : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { - return false; - } + return false; + } }; /// Post-Process callbacks class LLWorldPostProcess : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_post_process"); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("env_post_process"); + return true; + } }; class LLWorldCheckBanLines : public view_listener_t @@ -9209,684 +9209,684 @@ class LLWorldShowBanLines : public view_listener_t void handle_flush_name_caches() { - if (gCacheName) gCacheName->clear(); + if (gCacheName) gCacheName->clear(); } class LLUploadCostCalculator : public view_listener_t { - std::string mCostStr; - - bool handleEvent(const LLSD& userdata) - { - std::vector<std::string> fields; - std::string str = userdata.asString(); - boost::split(fields, str, boost::is_any_of(",")); - if (fields.size()<1) - { - return false; - } - std::string menu_name = fields[0]; - std::string asset_type_str = "texture"; - if (fields.size()>1) - { - asset_type_str = fields[1]; - } - LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; - calculateCost(asset_type_str); - gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); - - return true; - } - - void calculateCost(const std::string& asset_type_str); + std::string mCostStr; + + bool handleEvent(const LLSD& userdata) + { + std::vector<std::string> fields; + std::string str = userdata.asString(); + boost::split(fields, str, boost::is_any_of(",")); + if (fields.size()<1) + { + return false; + } + std::string menu_name = fields[0]; + std::string asset_type_str = "texture"; + if (fields.size()>1) + { + asset_type_str = fields[1]; + } + LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; + calculateCost(asset_type_str); + gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); + + return true; + } + + void calculateCost(const std::string& asset_type_str); public: - LLUploadCostCalculator() - { - } + LLUploadCostCalculator() + { + } }; class LLUpdateMembershipLabel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); - gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); + bool handleEvent(const LLSD& userdata) + { + const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); + gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); - return true; - } + return true; + } }; void handle_voice_morphing_subscribe() { - LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); + LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); } void handle_premium_voice_morphing_subscribe() { - LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); + LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); } class LLToggleUIHints : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); - // toggle - ui_hints_enabled = !ui_hints_enabled; - gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); - return true; - } + bool handleEvent(const LLSD& userdata) + { + bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); + // toggle + ui_hints_enabled = !ui_hints_enabled; + gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); + return true; + } }; void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str) { - S32 upload_cost = -1; - - if (asset_type_str == "texture") - { - upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - } - else if (asset_type_str == "animation") - { - upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); - } - else if (asset_type_str == "sound") - { - upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); - } - if (upload_cost < 0) - { - LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; - } - mCostStr = std::to_string(upload_cost); + S32 upload_cost = -1; + + if (asset_type_str == "texture") + { + upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); + } + else if (asset_type_str == "animation") + { + upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); + } + else if (asset_type_str == "sound") + { + upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); + } + if (upload_cost < 0) + { + LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; + } + mCostStr = std::to_string(upload_cost); } void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) { - static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } - show_navbar_context_menu->buildDrawLabels(); - show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); + static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } + show_navbar_context_menu->buildDrawLabels(); + show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); } void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y) { - static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark"); - if (!LLLandmarkActions::landmarkAlreadyExists()) - { - landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); - } - else - { - landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); - } + LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark"); + if (!LLLandmarkActions::landmarkAlreadyExists()) + { + landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); + } + else + { + landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); + } - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } - show_topbarinfo_context_menu->buildDrawLabels(); - show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); + show_topbarinfo_context_menu->buildDrawLabels(); + show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); } void initialize_edit_menu() { - view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); - view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); - view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); - view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); - view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); - view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); - view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); - view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); - view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); - view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); - view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); - view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); - view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); - view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); - view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); - view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); - view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); + view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); + view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); + view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); + view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); + view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); + view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); + view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); + view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); + view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); + view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); + view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); + view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); + view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); + view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); + view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); + view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); + view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); } void initialize_spellcheck_menu() { - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); - enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); - commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); - enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); - commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); - enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); + commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); + commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); + commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); } void initialize_menus() { - // A parameterized event handler used as ctrl-8/9/0 zoom controls below. - class LLZoomer : public view_listener_t - { - public: - // The "mult" parameter says whether "val" is a multiplier or used to set the value. - LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(const LLSD& userdata) - { - F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; - LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); - gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. - return true; - } - private: - F32 mVal; - bool mMult; - }; - - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - - // Generic enable and visible - // Don't prepend MenuName.Foo because these can be used in any menu. - enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service)); - - enable.add("displayViewerEventRecorderMenuItems",boost::bind(&LLViewerEventRecorder::displayViewerEventRecorderMenuItems,&LLViewerEventRecorder::instance())); - - view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts"); - - view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); - - enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); - - // Agent - commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); - enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); - commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); - commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); - commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); - enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); - enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); - - // File menu - init_menu_file(); - - view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); - view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); - view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); - view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); - view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); - commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); + // A parameterized event handler used as ctrl-8/9/0 zoom controls below. + class LLZoomer : public view_listener_t + { + public: + // The "mult" parameter says whether "val" is a multiplier or used to set the value. + LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} + bool handleEvent(const LLSD& userdata) + { + F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; + LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); + gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. + return true; + } + private: + F32 mVal; + bool mMult; + }; + + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // Generic enable and visible + // Don't prepend MenuName.Foo because these can be used in any menu. + enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service)); + + enable.add("displayViewerEventRecorderMenuItems",boost::bind(&LLViewerEventRecorder::displayViewerEventRecorderMenuItems,&LLViewerEventRecorder::instance())); + + view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts"); + + view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); + + enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); + + // Agent + commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); + enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); + commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); + commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); + commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); + enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); + enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); + + // File menu + init_menu_file(); + + view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); + view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); + view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); + view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); + view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); + commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); commit.add("NowWearing", boost::bind(&handle_now_wearing)); - commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); - commit.add("EditShape", boost::bind(&handle_edit_shape)); - commit.add("HoverHeight", boost::bind(&handle_hover_height)); - commit.add("EditPhysics", boost::bind(&handle_edit_physics)); - - // View menu - view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); - view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); - view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); - view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); - view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); - view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); - view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); - view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); - view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); - view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); - view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); - view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); - view_listener_t::addMenu(new LLViewToggleUI(), "View.ToggleUI"); - - view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); - view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); - view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); - - view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); - view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); - view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); - view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); - view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway"); - view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); - view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); - - //Communicate Nearby chat - view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); - - // Communicate > Voice morphing > Subscribe... - commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); - // Communicate > Voice morphing > Premium perk... - commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); - LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); - enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" - , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); - commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" - , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); - - // World menu - view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); - view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); - view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); - view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); - view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); - view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); - view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); - view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); - - view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); - view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); - view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); - view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); - - view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); - - view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); - view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); - view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); - view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); - view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); + commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); + commit.add("EditShape", boost::bind(&handle_edit_shape)); + commit.add("HoverHeight", boost::bind(&handle_hover_height)); + commit.add("EditPhysics", boost::bind(&handle_edit_physics)); + + // View menu + view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); + view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); + view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); + view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); + view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); + view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); + view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); + view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); + view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); + view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); + view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); + view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); + view_listener_t::addMenu(new LLViewToggleUI(), "View.ToggleUI"); + + view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); + view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); + view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); + + view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); + view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); + view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); + view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); + view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway"); + view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); + view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); + + //Communicate Nearby chat + view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); + + // Communicate > Voice morphing > Subscribe... + commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); + // Communicate > Voice morphing > Premium perk... + commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); + LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); + enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" + , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); + commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" + , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); + + // World menu + view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); + view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); + view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); + view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); + view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); + view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); + view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); + view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); + + view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); + view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); + view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); + view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); + + view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); + + view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); + view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); + view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); + view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); + view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines"); view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines"); - // Tools menu - view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); - view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); - view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); + // Tools menu + view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); + view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); + view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); view_listener_t::addMenu(new LLToolsSelectInvisibleObjects(), "Tools.SelectInvisibleObjects"); view_listener_t::addMenu(new LLToolsSelectReflectionProbes(), "Tools.SelectReflectionProbes"); - view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); - view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); - view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); - view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); - view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); - view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); - view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); - commit.add("Tools.Link", boost::bind(&handle_link_objects)); - commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); - view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); - view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); - view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); - view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); - - view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); - view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); - enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); - enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); - enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); - enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); - enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); - view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); - - view_listener_t::addMenu(new LLToolsEnablePathfinding(), "Tools.EnablePathfinding"); - view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView"); - view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion"); - view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion"); - - // Help menu - // most items use the ShowFloater method - view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); - - // Advanced menu - view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); - view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); - view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); - - // Advanced > HUD Info - view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); - view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); - - // Advanced Other Settings - view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); - - // Advanced > Render > Types - view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); - view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); - - //// Advanced > Render > Features - view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); - view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); - - view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity"); - view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity"); - - // Advanced > Render > Info Displays - view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); - commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); - view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); - view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); - // Develop > Render - view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); - view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); - view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); - view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); - - #ifdef TOGGLE_HACKED_GODLIKE_VIEWER - view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); - #endif - - // Advanced > World - view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); - view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); + view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); + view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); + view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); + view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); + view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); + view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); + view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); + commit.add("Tools.Link", boost::bind(&handle_link_objects)); + commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); + view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); + view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); + commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); + commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); + commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); + view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); + view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); + + view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); + view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); + enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); + enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); + enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); + enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); + enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); + view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); + + view_listener_t::addMenu(new LLToolsEnablePathfinding(), "Tools.EnablePathfinding"); + view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView"); + view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion"); + view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion"); + + // Help menu + // most items use the ShowFloater method + view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); + + // Advanced menu + view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); + view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); + view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); + + // Advanced > HUD Info + view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); + view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); + + // Advanced Other Settings + view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); + + // Advanced > Render > Types + view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); + view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); + + //// Advanced > Render > Features + view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); + view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); + + view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity"); + view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity"); + + // Advanced > Render > Info Displays + view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); + commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); + view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); + view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); + // Develop > Render + view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); + view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); + view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); + view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); + view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); + view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); + + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER + view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); + #endif + + // Advanced > World + view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); + view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); view_listener_t::addMenu(new LLAdvancedToggleStatsRecorder(), "Advanced.ToggleStatsRecorder"); view_listener_t::addMenu(new LLAdvancedCheckStatsRecorder(), "Advanced.CheckStatsRecorder"); view_listener_t::addMenu(new LLAdvancedToggleInterestList360Mode(), "Advanced.ToggleInterestList360Mode"); view_listener_t::addMenu(new LLAdvancedCheckInterestList360Mode(), "Advanced.CheckInterestList360Mode"); view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); - // Advanced > UI - commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser - commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater - commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); - commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); - view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); - view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); - view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); - commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); - view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); - view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); - view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); - view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); - view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); - view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); - view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); - view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); - view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); - view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); - - // Advanced > XUI - commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); - view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); - view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); - view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); - - // Advanced > Character > Grab Baked Texture - view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); - view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); - - // Advanced > Character > Character Tests - view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); - - view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); - view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); - - // Advanced > Character > Animation Speed - view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); - view_listener_t::addMenu(new LLAdvancedAnimTenSlower(), "Advanced.AnimTenSlower"); - view_listener_t::addMenu(new LLAdvancedAnimResetAll(), "Advanced.AnimResetAll"); - - // Advanced > Character (toplevel) - view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); - view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); - view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); - view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); - view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); - view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); - view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); - view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); - view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); - // Advanced > Network - view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); + // Advanced > UI + commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser + commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater + commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); + commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); + view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); + view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); + view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); + commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); + commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); + view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); + view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); + view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); + view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); + view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); + view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); + view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); + view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); + + // Advanced > XUI + commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); + view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); + view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); + view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); + commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); + + // Advanced > Character > Grab Baked Texture + view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); + view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); + + // Advanced > Character > Character Tests + view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); + + view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); + view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); + + // Advanced > Character > Animation Speed + view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); + view_listener_t::addMenu(new LLAdvancedAnimTenSlower(), "Advanced.AnimTenSlower"); + view_listener_t::addMenu(new LLAdvancedAnimResetAll(), "Advanced.AnimResetAll"); + + // Advanced > Character (toplevel) + view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); + view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); + view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); + view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); + view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); + view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); + view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); + view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); + view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); + // Advanced > Network + view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); // Advanced > Cache view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache"); - // Advanced > Recorder - view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); - view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop"); - view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop"); - view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); + // Advanced > Recorder + view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); + view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop"); + view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop"); + view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); - // Advanced > Debugging - view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); + // Advanced > Debugging + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); + view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); - // Advanced (toplevel) - view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); + // Advanced (toplevel) + view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest"); - view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); - view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); - - view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); - view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); - - // Develop >Set logging level - view_listener_t::addMenu(new LLDevelopCheckLoggingLevel(), "Develop.CheckLoggingLevel"); - view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); - - //Develop (clear cache immediately) - commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); - - // Develop (Fonts debugging) - commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); - commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); - - // Admin >Object - view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); - view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); - view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); - view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); - - // Admin >Parcel - view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); - view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); - view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); - - // Admin >Region - view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); - // Admin top level - view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); - - // Self context menu - view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); - enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); - view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); - - view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); - - // we don't use boost::bind directly to delay side tray construction - view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); - view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab"); - - // Avatar pie menu - view_listener_t::addMenu(new LLAvatarCheckImpostorMode(), "Avatar.CheckImpostorMode"); - view_listener_t::addMenu(new LLAvatarSetImpostorMode(), "Avatar.SetImpostorMode"); - view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); - view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); - view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); - commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); - view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); - view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); - view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); - commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); - view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); - view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); - enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); - view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); - view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); - view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); - view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); - view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); - view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); - view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); - view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); - enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); + view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); + view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); + + view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); + view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); + + // Develop >Set logging level + view_listener_t::addMenu(new LLDevelopCheckLoggingLevel(), "Develop.CheckLoggingLevel"); + view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); + + //Develop (clear cache immediately) + commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + + // Develop (Fonts debugging) + commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); + commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); + + // Admin >Object + view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); + view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); + view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); + view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); + + // Admin >Parcel + view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); + view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); + view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); + + // Admin >Region + view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); + // Admin top level + view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); + + // Self context menu + view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); + enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); + view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); + + view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); + + // we don't use boost::bind directly to delay side tray construction + view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); + view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab"); + + // Avatar pie menu + view_listener_t::addMenu(new LLAvatarCheckImpostorMode(), "Avatar.CheckImpostorMode"); + view_listener_t::addMenu(new LLAvatarSetImpostorMode(), "Avatar.SetImpostorMode"); + view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); + view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); + view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); + commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); + view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); + view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); + view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); + commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); + commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); + view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); + view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); + enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); + view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); + view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); + view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); + view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); + view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); + view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); + view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); + enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible)); - commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); - - view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); - enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); - - // Object pie menu - view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); - commit.add("Object.Touch", boost::bind(&handle_object_touch)); - commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); - commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - commit.add("Object.Delete", boost::bind(&handle_object_delete)); - view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); - view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); - view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); - commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); - view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); - - enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); - enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - - commit.add("Object.Buy", boost::bind(&handle_buy)); - commit.add("Object.Edit", boost::bind(&handle_object_edit)); + commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); + + view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); + enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); + + // Object pie menu + view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); + commit.add("Object.Touch", boost::bind(&handle_object_touch)); + commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); + commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); + commit.add("Object.Delete", boost::bind(&handle_object_delete)); + view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); + view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); + view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); + commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); + view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); + + enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); + enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); + + commit.add("Object.Buy", boost::bind(&handle_buy)); + commit.add("Object.Edit", boost::bind(&handle_object_edit)); commit.add("Object.Edit", boost::bind(&handle_object_edit)); commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); - commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); - commit.add("Object.Open", boost::bind(&handle_object_open)); - commit.add("Object.Take", boost::bind(&handle_take)); - commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); + commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); + commit.add("Object.Open", boost::bind(&handle_object_open)); + commit.add("Object.Take", boost::bind(&handle_take)); + commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect)); enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); - enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); - enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); - enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); - enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); - - enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); - enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); - - view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); - enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); - - enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); - enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); - commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); - - // Attachment pie menu - enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); - view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); - view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); - view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); - view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); - view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); - view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); - - // Land pie menu - view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); - view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); + enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); + enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); + enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); + enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); + + enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); + enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); + + view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); + enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); + + enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); + enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); + enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); + enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); + commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); + + // Attachment pie menu + enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); + view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); + view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); + view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); + view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); + view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); + view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); + + // Land pie menu + view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); + view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); view_listener_t::addMenu(new LLLandCanSit(), "Land.CanSit"); - view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); - view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); - - // Particle muting - view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); - - view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - commit.add("Land.Buy", boost::bind(&handle_buy_land)); - - // Generic actions - commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); - commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); - view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); - view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); - view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); - view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); - view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); + view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); + view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); + + // Particle muting + view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); + + view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); + commit.add("Land.Buy", boost::bind(&handle_buy_land)); + + // Generic actions + commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); + commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); + view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); + view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); + view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); + view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); + view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks"); - view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); - view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); + view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); + view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); - view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); - view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); - commit.add("PayObject", boost::bind(&handle_give_money_dialog)); - - commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); - - enable.add("EnablePayObject", boost::bind(&enable_pay_object)); - enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); - enable.add("EnableEdit", boost::bind(&enable_object_edit)); - enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); - enable.add("VisibleBuild", boost::bind(&enable_object_build)); - commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); - enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); - enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); - commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); - enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); + view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); + view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); + commit.add("PayObject", boost::bind(&handle_give_money_dialog)); + + commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); + + enable.add("EnablePayObject", boost::bind(&enable_pay_object)); + enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); + enable.add("EnableEdit", boost::bind(&enable_object_edit)); + enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); + enable.add("VisibleBuild", boost::bind(&enable_object_build)); + commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); + enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); + enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); + commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); + enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); - view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); - view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); - view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); - view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); - view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); - view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); - view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); - view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); + view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); + view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); + view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); + view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); + view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); + view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); + view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); + view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b43de3fe3f..6ac783fec5 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenu.h * @brief Builds menus out of objects * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -156,38 +156,38 @@ U64 info_display_from_string(std::string info_display); class LLViewerMenuHolderGL : public LLMenuHolderGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuHolderGL::Params> - {}; + struct Params : public LLInitParam::Block<Params, LLMenuHolderGL::Params> + {}; + + LLViewerMenuHolderGL(const Params& p); - LLViewerMenuHolderGL(const Params& p); + virtual BOOL hideMenus(); - virtual BOOL hideMenus(); - - void setParcelSelection(LLSafeHandle<LLParcelSelection> selection); - void setObjectSelection(LLSafeHandle<LLObjectSelection> selection); + void setParcelSelection(LLSafeHandle<LLParcelSelection> selection); + void setObjectSelection(LLSafeHandle<LLObjectSelection> selection); - virtual const LLRect getMenuRect() const; + virtual const LLRect getMenuRect() const; protected: - LLSafeHandle<LLParcelSelection> mParcelSelection; - LLSafeHandle<LLObjectSelection> mObjectSelection; + LLSafeHandle<LLParcelSelection> mParcelSelection; + LLSafeHandle<LLObjectSelection> mObjectSelection; }; -extern LLMenuBarGL* gMenuBarView; -//extern LLView* gMenuBarHolder; -extern LLMenuGL* gEditMenu; -extern LLMenuGL* gPopupMenuView; -extern LLViewerMenuHolderGL* gMenuHolder; -extern LLMenuBarGL* gLoginMenuBarView; +extern LLMenuBarGL* gMenuBarView; +//extern LLView* gMenuBarHolder; +extern LLMenuGL* gEditMenu; +extern LLMenuGL* gPopupMenuView; +extern LLViewerMenuHolderGL* gMenuHolder; +extern LLMenuBarGL* gLoginMenuBarView; // Context menus in 3D scene -extern LLContextMenu *gMenuAvatarSelf; -extern LLContextMenu *gMenuAvatarOther; -extern LLContextMenu *gMenuObject; -extern LLContextMenu *gMenuAttachmentSelf; -extern LLContextMenu *gMenuAttachmentOther; -extern LLContextMenu *gMenuLand; -extern LLContextMenu *gMenuMuteParticle; +extern LLContextMenu *gMenuAvatarSelf; +extern LLContextMenu *gMenuAvatarOther; +extern LLContextMenu *gMenuObject; +extern LLContextMenu *gMenuAttachmentSelf; +extern LLContextMenu *gMenuAttachmentOther; +extern LLContextMenu *gMenuLand; +extern LLContextMenu *gMenuMuteParticle; // Needed to build menus when attachment site list available extern LLMenuGL* gAttachSubMenu; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a1dc7119ce..243c3aeff8 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenufile.cpp * @brief "File" menu in the main menu bar. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,17 +47,17 @@ #include "llimagej2c.h" #include "llimagejpeg.h" #include "llimagetga.h" -#include "llinventorymodel.h" // gInventory +#include "llinventorymodel.h" // gInventory #include "llpluginclassmedia.h" #include "llresourcedata.h" #include "llstatusbar.h" #include "lltinygltfhelper.h" #include "lltoast.h" -#include "llviewercontrol.h" // gSavedSettings +#include "llviewercontrol.h" // gSavedSettings #include "llviewertexturelist.h" #include "lluictrlfactory.h" #include "llviewerinventory.h" -#include "llviewermenu.h" // gMenuHolder +#include "llviewermenu.h" // gMenuHolder #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" @@ -83,24 +83,24 @@ class LLFileEnableUpload : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { return true; - } + } }; class LLFileEnableUploadModel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model"); - if (fmp && fmp->isModelLoading()) - { - return false; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model"); + if (fmp && fmp->isModelLoading()) + { + return false; + } + + return true; + } }; class LLFileEnableUploadMaterial : public view_listener_t @@ -118,18 +118,18 @@ class LLFileEnableUploadMaterial : public view_listener_t class LLMeshEnabled : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gSavedSettings.getBOOL("MeshEnabled"); - } + bool handleEvent(const LLSD& userdata) + { + return gSavedSettings.getBOOL("MeshEnabled"); + } }; class LLMeshUploadVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gMeshRepo.meshUploadEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return gMeshRepo.meshUploadEnabled(); + } }; LLMutex* LLFilePickerThread::sMutex = NULL; @@ -139,51 +139,51 @@ void LLFilePickerThread::getFile() { #if LL_WINDOWS // Todo: get rid of LLFilePickerThread and make this modeless - start(); + start(); #elif LL_DARWIN runModeless(); #else - run(); + run(); #endif } -//virtual +//virtual void LLFilePickerThread::run() { #if LL_WINDOWS - bool blocking = false; + bool blocking = false; #else - bool blocking = true; // modal + bool blocking = true; // modal #endif - LLFilePicker picker; - - if (mIsSaveDialog) - { - if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) - { - mResponses.push_back(picker.getFirstFile()); - } - } - else - { - bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking); - if (result) - { - std::string filename = picker.getFirstFile(); // consider copying mFiles directly - do - { - mResponses.push_back(filename); - filename = picker.getNextFile(); - } - while (mIsGetMultiple && !filename.empty()); - } - } - - { - LLMutexLock lock(sMutex); - sDeadQ.push(this); - } + LLFilePicker picker; + + if (mIsSaveDialog) + { + if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) + { + mResponses.push_back(picker.getFirstFile()); + } + } + else + { + bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking); + if (result) + { + std::string filename = picker.getFirstFile(); // consider copying mFiles directly + do + { + mResponses.push_back(filename); + filename = picker.getNextFile(); + } + while (mIsGetMultiple && !filename.empty()); + } + } + + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } } void LLFilePickerThread::runModeless() @@ -206,7 +206,7 @@ void LLFilePickerThread::runModeless() { result = picker.getOpenFileModeless(mLoadFilter, modelessVectorCallback, this); } - + if (!result) { LLMutexLock lock(sMutex); @@ -223,7 +223,7 @@ void LLFilePickerThread::modelessStringCallback(bool success, { picker->mResponses.push_back(response); } - + { LLMutexLock lock(sMutex); sDeadQ.push(picker); @@ -255,7 +255,7 @@ void LLFilePickerThread::modelessVectorCallback(bool success, } } } - + { LLMutexLock lock(sMutex); sDeadQ.push(picker); @@ -265,66 +265,66 @@ void LLFilePickerThread::modelessVectorCallback(bool success, //static void LLFilePickerThread::initClass() { - sMutex = new LLMutex(); + sMutex = new LLMutex(); } //static void LLFilePickerThread::cleanupClass() { - clearDead(); - - delete sMutex; - sMutex = NULL; + clearDead(); + + delete sMutex; + sMutex = NULL; } //static void LLFilePickerThread::clearDead() { - if (!sDeadQ.empty()) - { - LLMutexLock lock(sMutex); - while (!sDeadQ.empty()) - { - LLFilePickerThread* thread = sDeadQ.front(); - thread->notify(thread->mResponses); - delete thread; - sDeadQ.pop(); - } - } + if (!sDeadQ.empty()) + { + LLMutexLock lock(sMutex); + while (!sDeadQ.empty()) + { + LLFilePickerThread* thread = sDeadQ.front(); + thread->notify(thread->mResponses); + delete thread; + sDeadQ.pop(); + } + } } 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), - mFailureSignal(NULL) + : LLFilePickerThread(filter, get_multiple), + mLoadFilter(filter), + mSaveFilter(LLFilePicker::FFSAVE_ALL), + mFilePickedSignal(NULL), + mFailureSignal(NULL) { - mFilePickedSignal = new file_picked_signal_t(); - mFilePickedSignal->connect(cb); + mFilePickedSignal = new file_picked_signal_t(); + mFilePickedSignal->connect(cb); - mFailureSignal = new file_picked_signal_t(); - mFailureSignal->connect(failure_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, const file_picked_signal_t::slot_type& failure_cb) - : LLFilePickerThread(filter, proposed_name), - mLoadFilter(LLFilePicker::FFLOAD_ALL), - mSaveFilter(filter), - mFilePickedSignal(NULL), - mFailureSignal(NULL) + : LLFilePickerThread(filter, proposed_name), + mLoadFilter(LLFilePicker::FFLOAD_ALL), + mSaveFilter(filter), + mFilePickedSignal(NULL), + mFailureSignal(NULL) { - mFilePickedSignal = new file_picked_signal_t(); - mFilePickedSignal->connect(cb); + mFilePickedSignal = new file_picked_signal_t(); + mFilePickedSignal->connect(cb); - mFailureSignal = new file_picked_signal_t(); - mFailureSignal->connect(failure_cb); + mFailureSignal = new file_picked_signal_t(); + mFailureSignal->connect(failure_cb); } LLFilePickerReplyThread::~LLFilePickerReplyThread() { - delete mFilePickedSignal; - delete mFailureSignal; + delete mFilePickedSignal; + delete mFailureSignal; } void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb) @@ -339,20 +339,20 @@ void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames) { - if (filenames.empty()) - { - if (mFailureSignal) - { - (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); - } - } - else - { - if (mFilePickedSignal) - { - (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); - } - } + if (filenames.empty()) + { + if (mFailureSignal) + { + (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); + } + } + else + { + if (mFilePickedSignal) + { + (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); + } + } } @@ -389,167 +389,167 @@ static std::string MATERIAL_EXTENSIONS = "gltf glb"; std::string build_extensions_string(LLFilePicker::ELoadFilter filter) { - switch(filter) - { + switch(filter) + { #if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: - return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: - return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: - return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: - return SLOBJECT_EXTENSIONS; - case LLFilePicker::FFLOAD_MODEL: - return MODEL_EXTENSIONS; + case LLFilePicker::FFLOAD_IMAGE: + return IMAGE_EXTENSIONS; + case LLFilePicker::FFLOAD_WAV: + return SOUND_EXTENSIONS; + case LLFilePicker::FFLOAD_ANIM: + return ANIM_EXTENSIONS; + case LLFilePicker::FFLOAD_SLOBJECT: + return SLOBJECT_EXTENSIONS; + case LLFilePicker::FFLOAD_MODEL: + return MODEL_EXTENSIONS; case LLFilePicker::FFLOAD_MATERIAL: return MATERIAL_EXTENSIONS; - case LLFilePicker::FFLOAD_XML: - return XML_EXTENSIONS; + case LLFilePicker::FFLOAD_XML: + return XML_EXTENSIONS; case LLFilePicker::FFLOAD_ALL: case LLFilePicker::FFLOAD_EXE: - return ALL_FILE_EXTENSIONS; + return ALL_FILE_EXTENSIONS; #endif default: - return ALL_FILE_EXTENSIONS; - } + return ALL_FILE_EXTENSIONS; + } } const bool check_file_extension(const std::string& filename, LLFilePicker::ELoadFilter type) { - std::string ext = gDirUtilp->getExtension(filename); - - //strincmp doesn't like NULL pointers - if (ext.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - LLSD args; - args["FILE"] = short_name; - LLNotificationsUtil::add("NoFileExtension", args); - return false; - } - else - { - //so there is an extension - //loop over the valid extensions and compare to see - //if the extension is valid - - //now grab the set of valid file extensions - std::string valid_extensions = build_extensions_string(type); - - BOOL ext_valid = FALSE; - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep(" "); - tokenizer tokens(valid_extensions, sep); - tokenizer::iterator token_iter; - - //now loop over all valid file extensions - //and compare them to the extension of the file - //to be uploaded - for (token_iter = tokens.begin(); - token_iter != tokens.end() && ext_valid != TRUE; - ++token_iter) - { - const std::string& cur_token = *token_iter; - - if (cur_token == ext || cur_token == "*.*") - { - //valid extension - //or the acceptable extension is any - ext_valid = TRUE; - } - }//end for (loop over all tokens) - - if (ext_valid == FALSE) - { - //should only get here if the extension exists - //but is invalid - LLSD args; - args["EXTENSION"] = ext; - args["VALIDS"] = valid_extensions; - LLNotificationsUtil::add("InvalidFileExtension", args); - return false; - } - }//end else (non-null extension) - return true; + std::string ext = gDirUtilp->getExtension(filename); + + //strincmp doesn't like NULL pointers + if (ext.empty()) + { + std::string short_name = gDirUtilp->getBaseFileName(filename); + + // No extension + LLSD args; + args["FILE"] = short_name; + LLNotificationsUtil::add("NoFileExtension", args); + return false; + } + else + { + //so there is an extension + //loop over the valid extensions and compare to see + //if the extension is valid + + //now grab the set of valid file extensions + std::string valid_extensions = build_extensions_string(type); + + BOOL ext_valid = FALSE; + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + tokenizer tokens(valid_extensions, sep); + tokenizer::iterator token_iter; + + //now loop over all valid file extensions + //and compare them to the extension of the file + //to be uploaded + for (token_iter = tokens.begin(); + token_iter != tokens.end() && ext_valid != TRUE; + ++token_iter) + { + const std::string& cur_token = *token_iter; + + if (cur_token == ext || cur_token == "*.*") + { + //valid extension + //or the acceptable extension is any + ext_valid = TRUE; + } + }//end for (loop over all tokens) + + if (ext_valid == FALSE) + { + //should only get here if the extension exists + //but is invalid + LLSD args; + args["EXTENSION"] = ext; + args["VALIDS"] = valid_extensions; + LLNotificationsUtil::add("InvalidFileExtension", args); + return false; + } + }//end else (non-null extension) + return true; } const void upload_single_file(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type) { - std::string filename = filenames[0]; - if (!check_file_extension(filename, type)) return; - - if (!filename.empty()) - { - if (type == LLFilePicker::FFLOAD_WAV) - { - // pre-qualify wavs to make sure the format is acceptable - std::string error_msg; - if (check_for_invalid_wav_formats(filename, error_msg)) - { - LL_INFOS() << error_msg << ": " << filename << LL_ENDL; - LLSD args; - args["FILE"] = filename; - LLNotificationsUtil::add(error_msg, args); - return; - } - else - { - LLFloaterReg::showInstance("upload_sound", LLSD(filename)); - } - } - if (type == LLFilePicker::FFLOAD_IMAGE) - { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); - } - if (type == LLFilePicker::FFLOAD_ANIM) - { - std::string filename_lc(filename); - LLStringUtil::toLower(filename_lc); - if (filename_lc.rfind(".anim") != std::string::npos) - { - LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); - } - else - { - LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); - } - } - } - return; + std::string filename = filenames[0]; + if (!check_file_extension(filename, type)) return; + + if (!filename.empty()) + { + if (type == LLFilePicker::FFLOAD_WAV) + { + // pre-qualify wavs to make sure the format is acceptable + std::string error_msg; + if (check_for_invalid_wav_formats(filename, error_msg)) + { + LL_INFOS() << error_msg << ": " << filename << LL_ENDL; + LLSD args; + args["FILE"] = filename; + LLNotificationsUtil::add(error_msg, args); + return; + } + else + { + LLFloaterReg::showInstance("upload_sound", LLSD(filename)); + } + } + if (type == LLFilePicker::FFLOAD_IMAGE) + { + LLFloaterReg::showInstance("upload_image", LLSD(filename)); + } + if (type == LLFilePicker::FFLOAD_ANIM) + { + std::string filename_lc(filename); + LLStringUtil::toLower(filename_lc); + if (filename_lc.rfind(".anim") != std::string::npos) + { + LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); + } + else + { + LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); + } + } + } + return; } void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) - { - // Cancel upload - return; - } - - for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - std::string filename = (*in_iter); - - std::string name = gDirUtilp->getBaseFileName(filename, true); - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII(asset_name, '?'); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string ext = gDirUtilp->getExtension(filename); - LLAssetType::EType asset_type; - U32 codec; - S32 expected_upload_cost; - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) - { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + // Cancel upload + return; + } + + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + + std::string name = gDirUtilp->getBaseFileName(filename, true); + std::string asset_name = name; + LLStringUtil::replaceNonstandardASCII(asset_name, '?'); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string ext = gDirUtilp->getExtension(filename); + LLAssetType::EType asset_type; + U32 codec; + S32 expected_upload_cost; + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) + { LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( filename, asset_name, @@ -585,34 +585,34 @@ void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost, S32& file_count, S32& bvh_count) { - total_cost = 0; - file_count = 0; - bvh_count = 0; - for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - std::string filename = (*in_iter); - std::string ext = gDirUtilp->getExtension(filename); - - if (ext == "bvh") - { - bvh_count++; - } - - LLAssetType::EType asset_type; - U32 codec; - S32 cost; - - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) - { - total_cost += cost; - file_count++; - } + total_cost = 0; + file_count = 0; + bvh_count = 0; + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + std::string ext = gDirUtilp->getExtension(filename); + + if (ext == "bvh") + { + bvh_count++; + } + + LLAssetType::EType asset_type; + U32 codec; + S32 cost; + + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) + { + total_cost += cost; + file_count++; + } if (ext == "gltf" || ext == "glb") { S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - + tinygltf::Model model; if (LLTinyGLTFHelper::loadModel(filename, model)) @@ -652,87 +652,87 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3 } } } - } - + } + return file_count > 0; } const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type) { - // TODO: - // Check user balance for entire cost - // Charge user entire cost - // Loop, uploading - // If an upload fails, refund the user for that one - // - // Also fix single upload to charge first, then refund - - // FIXME PREMIUM what about known types that can't be bulk uploaded - // (bvh)? These will fail in the item by item upload but won't be - // mentioned in the notification. - std::vector<std::string> filtered_filenames; - for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - const std::string& filename = *in_iter; - if (check_file_extension(filename, type)) - { - filtered_filenames.push_back(filename); - } - } - - S32 expected_upload_cost; - S32 expected_upload_count; - S32 bvh_count; - if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) - { - LLSD args; - args["COST"] = expected_upload_cost; - args["COUNT"] = expected_upload_count; - LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); - - if (filtered_filenames.size() > expected_upload_count) - { - if (bvh_count == filtered_filenames.size() - expected_upload_count) - { - LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); - } - else - { - LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); - } - } - } - else if (bvh_count == filtered_filenames.size()) - { - LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); - } - else - { - LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); - } + // TODO: + // Check user balance for entire cost + // Charge user entire cost + // Loop, uploading + // If an upload fails, refund the user for that one + // + // Also fix single upload to charge first, then refund + + // FIXME PREMIUM what about known types that can't be bulk uploaded + // (bvh)? These will fail in the item by item upload but won't be + // mentioned in the notification. + std::vector<std::string> filtered_filenames; + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + const std::string& filename = *in_iter; + if (check_file_extension(filename, type)) + { + filtered_filenames.push_back(filename); + } + } + + S32 expected_upload_cost; + S32 expected_upload_count; + S32 bvh_count; + if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) + { + LLSD args; + args["COST"] = expected_upload_cost; + args["COUNT"] = expected_upload_count; + LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); + + if (filtered_filenames.size() > expected_upload_count) + { + if (bvh_count == filtered_filenames.size() - expected_upload_count) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); + } + } + } + else if (bvh_count == filtered_filenames.size()) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); + } } class LLFileUploadImage : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); + return true; + } }; class LLFileUploadModel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LLFloaterModelPreview::showModelPreview(); return TRUE; - } + } }; class LLFileUploadMaterial : public view_listener_t @@ -746,101 +746,101 @@ class LLFileUploadMaterial : public view_listener_t class LLFileUploadSound : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); + return true; + } }; class LLFileUploadAnim : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); + return true; + } }; class LLFileUploadBulk : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); + return true; + } }; -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) +void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) { - LL_WARNS() << error_message << LL_ENDL; - LLNotificationsUtil::add(label, args); - if(LLFile::remove(filename) == -1) - { - LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; - } - LLFilePicker::instance().reset(); + LL_WARNS() << error_message << LL_ENDL; + LLNotificationsUtil::add(label, args); + if(LLFile::remove(filename) == -1) + { + LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; + } + LLFilePicker::instance().reset(); } class LLFileEnableCloseWindow : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); - bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); - return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); - } + return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); + } }; class LLFileCloseWindow : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); - LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); - - if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) - { - snapshot_floater->closeFloater(); - if (gFocusMgr.getKeyboardFocus() == NULL) - { - gFloaterView->focusFrontFloater(); - } - } - else - { - LLFloater::closeFrontmostFloater(); - } - if (gMenuHolder) gMenuHolder->hideMenus(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); + + if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) + { + snapshot_floater->closeFloater(); + if (gFocusMgr.getKeyboardFocus() == NULL) + { + gFloaterView->focusFrontFloater(); + } + } + else + { + LLFloater::closeFrontmostFloater(); + } + if (gMenuHolder) gMenuHolder->hideMenus(); + return true; + } }; class LLFileEnableCloseAllWindows : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); - bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()); - bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; - return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown(); - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); + bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()); + bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; + return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown(); + } }; -void close_all_windows() +void close_all_windows() { bool app_quitting = false; gFloaterView->closeAllChildren(app_quitting); @@ -853,112 +853,112 @@ void close_all_windows() class LLFileCloseAllWindows : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - close_all_windows(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + close_all_windows(); + return true; + } }; class LLFileTakeSnapshotToDisk : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPointer<LLImageRaw> raw = new LLImageRaw; - - S32 width = gViewerWindow->getWindowWidthRaw(); - S32 height = gViewerWindow->getWindowHeightRaw(); - - BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); - BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); - BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); - - BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); - if (high_res) - { - width *= 2; - height *= 2; - // not compatible with UI/HUD - render_ui = false; - render_hud = false; - } - - if (gViewerWindow->rawSnapshot(raw, - width, - height, - TRUE, - FALSE, - render_ui, - render_hud, - FALSE, - render_no_post, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side - { - LLPointer<LLImageFormatted> formatted; + bool handleEvent(const LLSD& userdata) + { + LLPointer<LLImageRaw> raw = new LLImageRaw; + + S32 width = gViewerWindow->getWindowWidthRaw(); + S32 height = gViewerWindow->getWindowHeightRaw(); + + BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); + BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); + + BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); + if (high_res) + { + width *= 2; + height *= 2; + // not compatible with UI/HUD + render_ui = false; + render_hud = false; + } + + if (gViewerWindow->rawSnapshot(raw, + width, + height, + TRUE, + FALSE, + render_ui, + render_hud, + FALSE, + render_no_post, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side + { + LLPointer<LLImageFormatted> formatted; LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); - switch (fmt) - { - case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG: - formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); - break; - default: - LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL; - case LLSnapshotModel::SNAPSHOT_FORMAT_PNG: - formatted = new LLImagePNG; - break; - case LLSnapshotModel::SNAPSHOT_FORMAT_BMP: - formatted = new LLImageBMP; - break; - } - formatted->enableOverSize() ; - formatted->encode(raw, 0); - formatted->disableOverSize() ; - LLSnapshotLivePreview::saveLocal(formatted); - } - return true; - } + switch (fmt) + { + case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG: + formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); + break; + default: + LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL; + case LLSnapshotModel::SNAPSHOT_FORMAT_PNG: + formatted = new LLImagePNG; + break; + case LLSnapshotModel::SNAPSHOT_FORMAT_BMP: + formatted = new LLImageBMP; + break; + } + formatted->enableOverSize() ; + formatted->encode(raw, 0); + formatted->disableOverSize() ; + LLSnapshotLivePreview::saveLocal(formatted); + } + return true; + } }; class LLFileQuit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAppViewer::instance()->userQuit(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAppViewer::instance()->userQuit(); + return true; + } }; void handle_compress_image(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) - { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) - { - std::string outfile = infile + ".j2c"; - - LL_INFOS() << "Input: " << infile << LL_ENDL; - LL_INFOS() << "Output: " << outfile << LL_ENDL; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - LL_INFOS() << "Compression complete" << LL_ENDL; - } - else - { - LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; - } - - infile = picker.getNextFile(); - } - } + LLFilePicker& picker = LLFilePicker::instance(); + if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) + { + std::string infile = picker.getFirstFile(); + while (!infile.empty()) + { + std::string outfile = infile + ".j2c"; + + LL_INFOS() << "Input: " << infile << LL_ENDL; + LL_INFOS() << "Output: " << outfile << LL_ENDL; + + BOOL success; + + success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + + if (success) + { + LL_INFOS() << "Compression complete" << LL_ENDL; + } + else + { + LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; + } + + infile = picker.getNextFile(); + } + } } // No convinient check in LLFile, and correct way would be something @@ -966,7 +966,7 @@ void handle_compress_image(void*) // so doing dirty, but OS independent fopen and fseek size_t get_file_size(std::string &filename) { - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -1051,21 +1051,21 @@ void handle_compress_file_test(void*) LLUUID upload_new_resource( - const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata, - bool show_inventory) -{ + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata, + bool show_inventory) +{ LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>( src_filename, @@ -1079,127 +1079,127 @@ LLUUID upload_new_resource( } void upload_done_callback( - const LLUUID& uuid, - void* user_data, - S32 result, - LLExtStat ext_status) // StoreAssetData callback (fixed) + const LLUUID& uuid, + void* user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) { - LLResourceData* data = (LLResourceData*)user_data; - S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; - //LLAssetType::EType pref_loc = data->mPreferredLocation; - BOOL is_balance_sufficient = TRUE; - - if(data) - { - if (result >= 0) - { - LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; - - if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || - LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || - LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) - { - // Charge the user for the upload. - LLViewerRegion* region = gAgent.getRegion(); - - if(!(can_afford_transaction(expected_upload_cost))) - { - LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); - is_balance_sufficient = FALSE; - } - else if(region) - { - // Charge user for upload - gStatusBar->debitBalance(expected_upload_cost); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); - msg->addU8("Flags", 0); - // we tell the sim how much we were expecting to pay so it - // can respond to any discrepancy - msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); - msg->addStringFast(_PREHASH_Description, NULL); - msg->sendReliable(region->getHost()); - } - } - - if(is_balance_sufficient) - { - // Actually add the upload to inventory - LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); - if(folder_id.notNull()) - { - U32 next_owner_perms = data->mNextOwnerPerm; - if(PERM_NONE == next_owner_perms) - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), - data->mAssetInfo.getDescription(), data->mAssetInfo.mType, + LLResourceData* data = (LLResourceData*)user_data; + S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; + //LLAssetType::EType pref_loc = data->mPreferredLocation; + BOOL is_balance_sufficient = TRUE; + + if(data) + { + if (result >= 0) + { + LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; + + if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || + LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || + LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) + { + // Charge the user for the upload. + LLViewerRegion* region = gAgent.getRegion(); + + if(!(can_afford_transaction(expected_upload_cost))) + { + LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); + is_balance_sufficient = FALSE; + } + else if(region) + { + // Charge user for upload + gStatusBar->debitBalance(expected_upload_cost); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoneyTransferRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_MoneyData); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); + msg->addU8("Flags", 0); + // we tell the sim how much we were expecting to pay so it + // can respond to any discrepancy + msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); + msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); + msg->addStringFast(_PREHASH_Description, NULL); + msg->sendReliable(region->getHost()); + } + } + + if(is_balance_sufficient) + { + // Actually add the upload to inventory + LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; + const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); + if(folder_id.notNull()) + { + U32 next_owner_perms = data->mNextOwnerPerm; + if(PERM_NONE == next_owner_perms) + { + next_owner_perms = PERM_MOVE | PERM_TRANSFER; + } + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), + data->mAssetInfo.getDescription(), data->mAssetInfo.mType, data->mInventoryType, NO_INV_SUBTYPE, next_owner_perms, - LLPointer<LLInventoryCallback>(NULL)); - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } - } - } - else // if(result >= 0) - { - LLSD args; - args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); - args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); - LLNotificationsUtil::add("CannotUploadReason", args); - } - - delete data; - data = NULL; - } - - LLUploadDialog::modalUploadFinished(); - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback; - void *userdata = NULL; - upload_new_resource( - next_file, - asset_name, - asset_name, // file - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } + LLPointer<LLInventoryCallback>(NULL)); + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } + } + } + else // if(result >= 0) + { + LLSD args; + args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); + args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); + LLNotificationsUtil::add("CannotUploadReason", args); + } + + delete data; + data = NULL; + } + + LLUploadDialog::modalUploadFinished(); + + // *NOTE: This is a pretty big hack. What this does is check the + // file picker if there are any more pending uploads. If so, + // upload that file. + const std::string& next_file = LLFilePicker::instance().getNextFile(); + if(is_balance_sufficient && !next_file.empty()) + { + std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); + LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string display_name = LLStringUtil::null; + LLAssetStorage::LLStoreAssetCallback callback; + void *userdata = NULL; + upload_new_resource( + next_file, + asset_name, + asset_name, // file + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + display_name, + callback, + expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost + userdata); + } } void upload_new_resource( @@ -1207,90 +1207,90 @@ void upload_new_resource( LLAssetStorage::LLStoreAssetCallback callback, void *userdata) { - if(gDisconnected) - { - return ; - } + if(gDisconnected) + { + return ; + } // uploadInfo->setAssetType(assetType); // uploadInfo->setTransactionId(tid); - std::string url = gAgent.getRegionCapability("NewFileAgentInventory"); + std::string url = gAgent.getRegionCapability("NewFileAgentInventory"); - if ( !url.empty() ) - { + if ( !url.empty() ) + { LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); - } - else - { + } + else + { uploadInfo->prepareUpload(); uploadInfo->logPreparedUpload(); - LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; - // check for adequate funds - // TODO: do this check on the sim - if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || + LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; + // check for adequate funds + // TODO: do this check on the sim + if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() || LLAssetType::AT_ANIMATION == uploadInfo->getAssetType()) - { - S32 balance = gStatusBar->getBalance(); - if (balance < uploadInfo->getExpectedUploadCost()) - { - // insufficient funds, bail on this upload + { + S32 balance = gStatusBar->getBalance(); + if (balance < uploadInfo->getExpectedUploadCost()) + { + // insufficient funds, bail on this upload LLBuyCurrencyHTML::openCurrencyFloater("", uploadInfo->getExpectedUploadCost()); - return; - } - } + return; + } + } - LLResourceData* data = new LLResourceData; - data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); - data->mAssetInfo.mUuid = uploadInfo->getAssetId(); + LLResourceData* data = new LLResourceData; + data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); + data->mAssetInfo.mUuid = uploadInfo->getAssetId(); data->mAssetInfo.mType = uploadInfo->getAssetType(); - data->mAssetInfo.mCreatorID = gAgentID; - data->mInventoryType = uploadInfo->getInventoryType(); - data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); - data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); - data->mUserData = userdata; - data->mAssetInfo.setName(uploadInfo->getName()); - data->mAssetInfo.setDescription(uploadInfo->getDescription()); - data->mPreferredLocation = uploadInfo->getDestinationFolderType(); - - LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; - if (callback) - { - asset_callback = callback; - } - gAssetStorage->storeAssetData( - data->mAssetInfo.mTransactionID, - data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); - } + data->mAssetInfo.mCreatorID = gAgentID; + data->mInventoryType = uploadInfo->getInventoryType(); + data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); + data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); + data->mUserData = userdata; + data->mAssetInfo.setName(uploadInfo->getName()); + data->mAssetInfo.setDescription(uploadInfo->getDescription()); + data->mPreferredLocation = uploadInfo->getDestinationFolderType(); + + LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; + if (callback) + { + asset_callback = callback; + } + gAssetStorage->storeAssetData( + data->mAssetInfo.mTransactionID, + data->mAssetInfo.mType, + asset_callback, + (void*)data, + FALSE); + } } void init_menu_file() { - view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); - view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); - view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); - view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); + view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); + view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); + view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); + view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); view_listener_t::addCommit(new LLFileUploadMaterial(), "File.UploadMaterial"); - view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); - view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); - view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); - view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); - view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); - view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); - view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); - - view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); - view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); + view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); + view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); + view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); + view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); + view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); + view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); + view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); + + view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); + view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); view_listener_t::addEnable(new LLFileEnableUploadMaterial(), "File.EnableUploadMaterial"); - view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); - view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); + view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); + view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); - // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. + // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index d41aa23829..5bf78a2c7f 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenufile.h * @brief "File" menu in the main menu bar. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -66,11 +66,11 @@ void upload_new_resource( void assign_defaults_and_show_upload_message( - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description); + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description); void close_all_windows(); @@ -79,39 +79,39 @@ class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) public: - static std::queue<LLFilePickerThread*> sDeadQ; - static LLMutex* sMutex; + static std::queue<LLFilePickerThread*> sDeadQ; + static LLMutex* sMutex; - static void initClass(); - static void cleanupClass(); - static void clearDead(); + static void initClass(); + static void cleanupClass(); + static void clearDead(); - std::vector<std::string> mResponses; - std::string mProposedName; + std::vector<std::string> mResponses; + std::string mProposedName; - LLFilePicker::ELoadFilter mLoadFilter; - LLFilePicker::ESaveFilter mSaveFilter; - bool mIsSaveDialog; - bool mIsGetMultiple; + LLFilePicker::ELoadFilter mLoadFilter; + LLFilePicker::ESaveFilter mSaveFilter; + bool mIsSaveDialog; + bool mIsGetMultiple; - LLFilePickerThread(LLFilePicker::ELoadFilter filter, bool get_multiple = false) - : LLThread("file picker"), mLoadFilter(filter), mIsSaveDialog(false), mIsGetMultiple(get_multiple) - { - } + LLFilePickerThread(LLFilePicker::ELoadFilter filter, bool get_multiple = false) + : LLThread("file picker"), mLoadFilter(filter), mIsSaveDialog(false), mIsGetMultiple(get_multiple) + { + } - LLFilePickerThread(LLFilePicker::ESaveFilter filter, const std::string &proposed_name) - : LLThread("file picker"), mSaveFilter(filter), mIsSaveDialog(true), mProposedName(proposed_name) - { - } + LLFilePickerThread(LLFilePicker::ESaveFilter filter, const std::string &proposed_name) + : LLThread("file picker"), mSaveFilter(filter), mIsSaveDialog(true), mProposedName(proposed_name) + { + } - void getFile(); + void getFile(); - virtual void run(); + virtual void run(); void runModeless(); static void modelessStringCallback(bool success, std::string &response, void *user_data); static void modelessVectorCallback(bool success, std::vector<std::string> &responses, void *user_data); - virtual void notify(const std::vector<std::string>& filenames) = 0; + virtual void notify(const std::vector<std::string>& filenames) = 0; }; @@ -119,12 +119,12 @@ class LLFilePickerReplyThread : public LLFilePickerThread { public: - typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; + typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; static void startPicker(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()); static void startPicker(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()); - virtual void notify(const std::vector<std::string>& filenames); + virtual void notify(const std::vector<std::string>& filenames); private: 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()); @@ -132,10 +132,10 @@ private: ~LLFilePickerReplyThread(); private: - LLFilePicker::ELoadFilter mLoadFilter; - LLFilePicker::ESaveFilter mSaveFilter; - file_picked_signal_t* mFilePickedSignal; - file_picked_signal_t* mFailureSignal; + LLFilePicker::ELoadFilter mLoadFilter; + LLFilePicker::ESaveFilter mSaveFilter; + file_picked_signal_t* mFilePickedSignal; + file_picked_signal_t* mFailureSignal; }; class LLMediaFilePicker : public LLFilePickerThread -- cgit v1.2.3 From 9f540f10e687bb3889de191afbae3b52cc21f415 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 15 May 2024 18:50:51 +0300 Subject: Add trusted flag to UI callbacks, so not everything is accessible from the script --- indra/newview/lluilistener.cpp | 32 +++--- indra/newview/llviewermenu.cpp | 149 +++++++++++++------------- indra/newview/scripts/lua/LLDebugSettings.lua | 14 +-- indra/newview/scripts/lua/UI.lua | 5 +- indra/newview/scripts/lua/util.lua | 7 ++ 5 files changed, 105 insertions(+), 102 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 97a2be6aa3..c9e5cf00d6 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -59,30 +59,34 @@ LLUIListener::LLUIListener(): void LLUIListener::call(const LLSD& event) const { - LLUICtrl::commit_callback_t* func = - LLUICtrl::CommitCallbackRegistry::getValue(event["function"]); - if (! func) + Response response(LLSD(), event); + LLUICtrl::LLCommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(event["function"]); + if (!info ) { - // This API is intended for use by a script. It's a fire-and-forget - // API: we provide no reply. Therefore, a typo in the script will - // provide no feedback whatsoever to that script. To rub the coder's - // nose in such an error, crump rather than quietly ignoring it. - LL_WARNS("LLUIListener") << "function '" << event["function"] << "' not found" << LL_ENDL; + response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << "was not found")); + return; } - else + if (!info->mAllowUntrusted) + { + response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << " is not allowed to be called from the script")); + return; + } + LLUICtrl::commit_callback_t func = info->callback_func; + + if (info->callback_func) { // Interestingly, view_listener_t::addMenu() (addCommit(), // addEnable()) constructs a commit_callback_t callable that accepts // two parameters but discards the first. Only the second is passed to // handleEvent(). Therefore we feel completely safe passing NULL for // the first parameter. - (*func)(NULL, event["parameter"]); + (func)(NULL, event["parameter"]); } } void LLUIListener::getValue(const LLSD&event) const { - LLSD reply = LLSD::emptyMap(); + Response response(LLSD(), event); const LLView* root = LLUI::getInstance()->getRootView(); const LLView* view = LLUI::getInstance()->resolvePath(root, event["path"].asString()); @@ -90,12 +94,10 @@ void LLUIListener::getValue(const LLSD&event) const if (ctrl) { - reply["value"] = ctrl->getValue(); + response["value"] = ctrl->getValue(); } else { - // *TODO: ??? return something indicating failure to resolve + response.error(STRINGIZE("UI control " << std::quoted(event["path"].asString()) << " was not found")); } - - sendReply(reply, event); } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 52128a09ab..756e002540 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9361,17 +9361,17 @@ void initialize_edit_menu() view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); } - +#define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func, true)) +#define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func)) void initialize_spellcheck_menu() { - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + COMMIT_ADD_TRUSTED("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); - commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + COMMIT_ADD_TRUSTED("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); - commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + COMMIT_ADD_TRUSTED("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); } @@ -9396,7 +9396,6 @@ void initialize_menus() }; LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); // Generic enable and visible // Don't prepend MenuName.Foo because these can be used in any menu. @@ -9411,11 +9410,11 @@ void initialize_menus() enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); // Agent - commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); + COMMIT_ADD("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); - commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); - commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); - commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); + COMMIT_ADD_TRUSTED("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); + COMMIT_ADD_TRUSTED("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); + COMMIT_ADD_TRUSTED("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); @@ -9427,12 +9426,12 @@ void initialize_menus() view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); - commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); - commit.add("NowWearing", boost::bind(&handle_now_wearing)); - commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); - commit.add("EditShape", boost::bind(&handle_edit_shape)); - commit.add("HoverHeight", boost::bind(&handle_hover_height)); - commit.add("EditPhysics", boost::bind(&handle_edit_physics)); + COMMIT_ADD("CustomizeAvatar", boost::bind(&handle_customize_avatar)); + COMMIT_ADD("NowWearing", boost::bind(&handle_now_wearing)); + COMMIT_ADD("EditOutfit", boost::bind(&handle_edit_outfit)); + COMMIT_ADD("EditShape", boost::bind(&handle_edit_shape)); + COMMIT_ADD("HoverHeight", boost::bind(&handle_hover_height)); + COMMIT_ADD("EditPhysics", boost::bind(&handle_edit_physics)); // View menu view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); @@ -9465,13 +9464,13 @@ void initialize_menus() view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); // Communicate > Voice morphing > Subscribe... - commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); + COMMIT_ADD("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); // Communicate > Voice morphing > Premium perk... - commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); + COMMIT_ADD("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); - commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" + COMMIT_ADD_TRUSTED("Communicate.VoiceMorphing.NoVoiceMorphing.Click" , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); // World menu @@ -9512,14 +9511,14 @@ void initialize_menus() view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); - commit.add("Tools.Link", boost::bind(&handle_link_objects)); - commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); + COMMIT_ADD("Tools.Link", boost::bind(&handle_link_objects)); + COMMIT_ADD("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); + COMMIT_ADD("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); + COMMIT_ADD("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); + COMMIT_ADD("Tools.TakeCopy", boost::bind(&handle_take_copy)); view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); @@ -9569,7 +9568,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); - commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); + COMMIT_ADD("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); // Develop > Render @@ -9600,15 +9599,15 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); // Advanced > UI - commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser - commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater - commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); - commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); + COMMIT_ADD("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser + COMMIT_ADD("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater + COMMIT_ADD("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); + COMMIT_ADD("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); - commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); + COMMIT_ADD("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); + COMMIT_ADD("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); @@ -9629,11 +9628,11 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); // Advanced > XUI - commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); + COMMIT_ADD("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); + COMMIT_ADD("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); // Advanced > Character > Grab Baked Texture view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); @@ -9677,7 +9676,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); // Advanced > Cache - view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache"); + view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache", false); // Advanced > Recorder view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); @@ -9686,19 +9685,19 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); // Advanced > Debugging - view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); - view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint", false); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror", false); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg", false); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess", false); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro", false); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop", false); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException", false); + view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException", false); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro", false); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash", false); + view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash", false); + view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash", false); + view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer", false); // Advanced (toplevel) view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); @@ -9719,11 +9718,11 @@ void initialize_menus() view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); //Develop (clear cache immediately) - commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + COMMIT_ADD("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); // Develop (Fonts debugging) - commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); - commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); + COMMIT_ADD("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); + COMMIT_ADD("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); // Admin >Object view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); @@ -9760,12 +9759,12 @@ void initialize_menus() view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); - commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); + COMMIT_ADD("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); - commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); + COMMIT_ADD("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); + COMMIT_ADD("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); @@ -9780,35 +9779,35 @@ void initialize_menus() enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible)); - commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); + COMMIT_ADD("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); // Object pie menu view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); - commit.add("Object.Touch", boost::bind(&handle_object_touch)); - commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); - commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - commit.add("Object.Delete", boost::bind(&handle_object_delete)); + COMMIT_ADD("Object.Touch", boost::bind(&handle_object_touch)); + COMMIT_ADD("Object.ShowOriginal", boost::bind(&handle_object_show_original)); + COMMIT_ADD("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); + COMMIT_ADD("Object.Delete", boost::bind(&handle_object_delete)); view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); - commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); + COMMIT_ADD("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - commit.add("Object.Buy", boost::bind(&handle_buy)); - commit.add("Object.Edit", boost::bind(&handle_object_edit)); - commit.add("Object.Edit", boost::bind(&handle_object_edit)); - commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); - commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); - commit.add("Object.Open", boost::bind(&handle_object_open)); - commit.add("Object.Take", boost::bind(&handle_take)); - commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); + COMMIT_ADD("Object.Buy", boost::bind(&handle_buy)); + COMMIT_ADD("Object.Edit", boost::bind(&handle_object_edit)); + COMMIT_ADD("Object.Edit", boost::bind(&handle_object_edit)); + COMMIT_ADD("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); + COMMIT_ADD("Object.Inspect", boost::bind(&handle_object_inspect)); + COMMIT_ADD("Object.Open", boost::bind(&handle_object_open)); + COMMIT_ADD("Object.Take", boost::bind(&handle_take)); + COMMIT_ADD("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect)); enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); @@ -9827,7 +9826,7 @@ void initialize_menus() enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); - commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); + COMMIT_ADD("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); // Attachment pie menu enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); @@ -9849,11 +9848,11 @@ void initialize_menus() view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - commit.add("Land.Buy", boost::bind(&handle_buy_land)); + COMMIT_ADD("Land.Buy", boost::bind(&handle_buy_land)); // Generic actions - commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); - commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); + COMMIT_ADD("ReportAbuse", boost::bind(&handle_report_abuse)); + COMMIT_ADD("BuyCurrency", boost::bind(&handle_buy_currency)); view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); @@ -9865,19 +9864,19 @@ void initialize_menus() view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); - commit.add("PayObject", boost::bind(&handle_give_money_dialog)); + COMMIT_ADD("PayObject", boost::bind(&handle_give_money_dialog)); - commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); + COMMIT_ADD("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); enable.add("EnablePayObject", boost::bind(&enable_pay_object)); enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); enable.add("EnableEdit", boost::bind(&enable_object_edit)); enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); enable.add("VisibleBuild", boost::bind(&enable_object_build)); - commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); + COMMIT_ADD("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); - commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); + COMMIT_ADD("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index c1d74fe00a..06a8a63727 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,24 +1,18 @@ leap = require 'leap' - -local function check_response(res) - if res.error then - error(res.error) - end - return res -end +util = require 'util' local LLDebugSettings = {} function LLDebugSettings.set(name, value) - check_response(leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value})) + util.check_response(leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value})) end function LLDebugSettings.toggle(name) - check_response(leap.request('LLViewerControl', {op='toggle', group='Global', key=name})) + util.check_response(leap.request('LLViewerControl', {op='toggle', group='Global', key=name})) end function LLDebugSettings.get(name) - return check_response(leap.request('LLViewerControl', {op='get', group='Global', key=name}))['value'] + return util.check_response(leap.request('LLViewerControl', {op='get', group='Global', key=name}))['value'] end return LLDebugSettings diff --git a/indra/newview/scripts/lua/UI.lua b/indra/newview/scripts/lua/UI.lua index f851632bad..6101c7a312 100644 --- a/indra/newview/scripts/lua/UI.lua +++ b/indra/newview/scripts/lua/UI.lua @@ -1,16 +1,17 @@ -- Engage the UI LLEventAPI leap = require 'leap' +util = require 'util' local UI = {} function UI.call(func, parameter) -- 'call' is fire-and-forget - leap.send('UI', {op='call', ['function']=func, parameter=parameter}) + util.check_response(leap.request('UI', {op='call', ['function']=func, parameter=parameter})) end function UI.getValue(path) - return leap.request('UI', {op='getValue', path=path})['value'] + return util.check_response(leap.request('UI', {op='getValue', path=path}))['value'] end return UI diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index a2191288f6..404efdf09e 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -41,4 +41,11 @@ function util.equal(t1, t2) return util.empty(temp) end +function util.check_response(res) + if res.error then + error(res.error) + end + return res +end + return util -- cgit v1.2.3 From 7137647e90d8c11197513f542f04fb39b483d663 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 15 May 2024 12:19:54 -0400 Subject: Manual whitespace cleanup (fix_whitespace.py). --- indra/newview/llappearancemgr.cpp | 6168 +++++----- indra/newview/llappviewer.cpp | 7034 +++++------ .../newview/lldonotdisturbnotificationstorage.cpp | 214 +- indra/newview/lldonotdisturbnotificationstorage.h | 16 +- indra/newview/llfilepicker.cpp | 2080 ++-- indra/newview/llfilepicker.h | 206 +- indra/newview/llfloaterlinkreplace.cpp | 618 +- indra/newview/llfloaterlinkreplace.h | 136 +- indra/newview/llfloaterluadebug.cpp | 36 +- indra/newview/llfloaterpreference.cpp | 3284 ++--- indra/newview/llfloaterregionrestarting.cpp | 196 +- indra/newview/llfloaterregionrestarting.h | 58 +- indra/newview/llfloatersettingsdebug.cpp | 706 +- indra/newview/llfloatersettingsdebug.h | 38 +- indra/newview/llfloateruipreview.cpp | 2664 ++-- indra/newview/llimview.cpp | 5100 ++++---- indra/newview/llimview.h | 890 +- indra/newview/llinventoryfunctions.cpp | 1964 +-- indra/newview/llinventoryfunctions.h | 282 +- indra/newview/llinventorymodel.cpp | 6722 +++++----- indra/newview/lllocalbitmaps.cpp | 1646 +-- indra/newview/lllocalbitmaps.h | 160 +- indra/newview/lllocalgltfmaterials.h | 20 +- indra/newview/llmediadataclient.cpp | 980 +- indra/newview/llmediadataclient.h | 514 +- indra/newview/llpanelpeople.cpp | 2280 ++-- indra/newview/llsetkeybinddialog.cpp | 16 +- indra/newview/llspeakers.cpp | 1322 +- indra/newview/llspeakers.h | 430 +- indra/newview/llstartup.cpp | 6120 +++++----- indra/newview/lltoast.cpp | 762 +- indra/newview/lltoast.h | 284 +- indra/newview/lltoolplacer.cpp | 872 +- indra/newview/lltoolplacer.h | 36 +- indra/newview/llviewercontrollistener.cpp | 292 +- indra/newview/llviewerfloaterreg.cpp | 418 +- indra/newview/llviewermenu.cpp | 12102 +++++++++---------- indra/newview/llviewermenu.h | 56 +- indra/newview/llviewermenufile.cpp | 1408 +-- indra/newview/llviewermenufile.h | 76 +- indra/newview/llviewermessage.cpp | 10706 ++++++++-------- indra/newview/llviewerparcelmediaautoplay.cpp | 208 +- indra/newview/llviewerparcelmediaautoplay.h | 24 +- 43 files changed, 39572 insertions(+), 39572 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index dccd63af38..34a50e1fa7 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1,29 +1,29 @@ -/** +/** * @file llappearancemgr.cpp * @brief Manager for initiating appearance changes on the viewer * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #include "llviewerprecompiledheaders.h" #include <boost/lexical_cast.hpp> @@ -71,7 +71,7 @@ #pragma warning (disable:4702) #endif -namespace +namespace { const S32 BAKE_RETRY_MAX_COUNT = 5; const F32 BAKE_RETRY_TIMEOUT = 2.0F; @@ -87,8 +87,8 @@ void doAppearanceCb(LLPointer<LLInventoryCallback> cb, LLUUID id) std::string self_av_string() { - // On logout gAgentAvatarp can already be invalid - return isAgentAvatarValid() ? gAgentAvatarp->avString() : ""; + // On logout gAgentAvatarp can already be invalid + return isAgentAvatarValid() ? gAgentAvatarp->avString() : ""; } // RAII thingy to guarantee that a variable gets reset when the Setter @@ -97,17 +97,17 @@ std::string self_av_string() class BoolSetter { public: - BoolSetter(bool& var): - mVar(var) - { - mVar = true; - } - ~BoolSetter() - { - mVar = false; - } + BoolSetter(bool& var): + mVar(var) + { + mVar = true; + } + ~BoolSetter() + { + mVar = false; + } private: - bool& mVar; + bool& mVar; }; char ORDER_NUMBER_SEPARATOR('@'); @@ -115,47 +115,47 @@ char ORDER_NUMBER_SEPARATOR('@'); class LLOutfitUnLockTimer: public LLEventTimer { public: - LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) - { - // restart timer on BOF changed event - LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); }); - stop(); - } - - bool tick() override - { - LLAppearanceMgr::instance().setOutfitLocked(false); - return false; - } -// void reset() { mEventTimer.reset(); } - bool getStarted() { return isRunning(); } - -// LLTimer& getEventTimer() { return mEventTimer;} + LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) + { + // restart timer on BOF changed event + LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); }); + stop(); + } + + bool tick() override + { + LLAppearanceMgr::instance().setOutfitLocked(false); + return false; + } +// void reset() { mEventTimer.reset(); } + bool getStarted() { return isRunning(); } + +// LLTimer& getEventTimer() { return mEventTimer;} }; // support for secondlife:///app/appearance SLapps class LLAppearanceHandler : public LLCommandHandler { public: - // requests will be throttled from a non-trusted browser - LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} + // requests will be throttled from a non-trusted browser + LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) - { - // support secondlife:///app/appearance/show, but for now we just - // make all secondlife:///app/appearance SLapps behave this way - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAppearance")) - { - LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); - return true; - } + { + // support secondlife:///app/appearance/show, but for now we just + // make all secondlife:///app/appearance SLapps behave this way + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAppearance")) + { + LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); + return true; + } }; LLAppearanceHandler gAppearanceHandler; @@ -163,27 +163,27 @@ LLAppearanceHandler gAppearanceHandler; LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(name); - gInventory.collectDescendentsIf(parent_id, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - if (0 == cat_array.size()) - return LLUUID(); - else - { - LLViewerInventoryCategory *cat = cat_array.at(0); - if (cat) - return cat->getUUID(); - else - { - LL_WARNS() << "null cat" << LL_ENDL; - return LLUUID(); - } - } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLNameCategoryCollector has_name(name); + gInventory.collectDescendentsIf(parent_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + if (0 == cat_array.size()) + return LLUUID(); + else + { + LLViewerInventoryCategory *cat = cat_array.at(0); + if (cat) + return cat->getUUID(); + else + { + LL_WARNS() << "null cat" << LL_ENDL; + return LLUUID(); + } + } } // We want this to be much lower (e.g. 15.0 is usually fine), bumping @@ -196,261 +196,261 @@ const F32 DEFAULT_RETRY_AFTER_INTERVAL = 300.0; // leave at 0 if the operations become actually reliable). const S32 DEFAULT_MAX_RETRIES = 0; -class LLCallAfterInventoryBatchMgr: public LLEventTimer +class LLCallAfterInventoryBatchMgr: public LLEventTimer { public: - LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - mDstCatID(dst_cat_id), - mTrackingPhase(phase_name), - mOnCompletionFunc(on_completion_func), - mOnFailureFunc(on_failure_func), - mRetryAfter(retry_after), - mMaxRetries(max_retries), - mPendingRequests(0), - mFailCount(0), - mCompletionOrFailureCalled(false), - mRetryCount(0), - LLEventTimer(5.0) - { - if (!mTrackingPhase.empty()) - { - selfStartPhase(mTrackingPhase); - } - } - - void addItems(LLInventoryModel::item_array_t& src_items) - { - for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin(); - it != src_items.end(); - ++it) - { - LLViewerInventoryItem* item = *it; - llassert(item); - addItem(item->getUUID()); - } - } - - // Request or re-request operation for specified item. - void addItem(const LLUUID& item_id) - { - LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; - if (!requestOperation(item_id)) - { - LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; - return; - } - - mPendingRequests++; - // On a re-request, this will reset the timer. - mWaitTimes[item_id] = LLTimer(); - if (mRetryCounts.find(item_id) == mRetryCounts.end()) - { - mRetryCounts[item_id] = 0; - } - else - { - mRetryCounts[item_id]++; - } - } - - virtual bool requestOperation(const LLUUID& item_id) = 0; - - void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp) - { - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) - { - LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; - doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), - mRetryAfter); - return; - } - mPendingRequests--; - F32 elapsed = timestamp.getElapsedTimeF32(); - LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL; - if (mWaitTimes.find(src_id) == mWaitTimes.end()) - { - // No longer waiting for this item - either serviced - // already or gave up after too many retries. - LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id - << " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL; - } - mTimeStats.push(elapsed); - mWaitTimes.erase(src_id); - if (mWaitTimes.empty() && !mCompletionOrFailureCalled) - { - onCompletionOrFailure(); - } - } - - void onCompletionOrFailure() - { - assert (!mCompletionOrFailureCalled); - mCompletionOrFailureCalled = true; - - // Will never call onCompletion() if any item has been flagged as - // a failure - otherwise could wind up with corrupted - // outfit, involuntary nudity, etc. - reportStats(); - if (!mTrackingPhase.empty()) - { - selfStopPhase(mTrackingPhase); - } - if (!mFailCount) - { - onCompletion(); - } - else - { - onFailure(); - } - } - - void onFailure() - { - LL_INFOS() << "failed" << LL_ENDL; - mOnFailureFunc(); - } - - void onCompletion() - { - LL_INFOS() << "done" << LL_ENDL; - mOnCompletionFunc(); - } - - // virtual - // Will be deleted after returning true - only safe to do this if all callbacks have fired. - bool tick() override - { - // mPendingRequests will be zero if all requests have been - // responded to. mWaitTimes.empty() will be true if we have - // received at least one reply for each UUID. If requests - // have been dropped and retried, these will not necessarily - // be the same. Only safe to return true if all requests have - // been serviced, since it will result in this object being - // deleted. - bool all_done = (mPendingRequests==0); - - if (!mWaitTimes.empty()) - { - LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; - for (std::map<LLUUID,LLTimer>::iterator it = mWaitTimes.begin(); - it != mWaitTimes.end();) - { - // Use a copy of iterator because it may be erased/invalidated. - std::map<LLUUID,LLTimer>::iterator curr_it = it; - ++it; - - F32 time_waited = curr_it->second.getElapsedTimeF32(); - S32 retries = mRetryCounts[curr_it->first]; - if (time_waited > mRetryAfter) - { - if (retries < mMaxRetries) - { - LL_DEBUGS("Avatar") << "Waited " << time_waited << - " for " << curr_it->first << ", retrying" << LL_ENDL; - mRetryCount++; - addItem(curr_it->first); - } - else - { - LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; - mWaitTimes.erase(curr_it); - mFailCount++; - } - } - if (mWaitTimes.empty()) - { - onCompletionOrFailure(); - } - - } - } - return all_done; - } - - void reportStats() - { - LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL; - LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL; - LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL; - LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; - LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; - } - - virtual ~LLCallAfterInventoryBatchMgr() - { - LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; - } + LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id, + const std::string& phase_name, + nullary_func_t on_completion_func, + nullary_func_t on_failure_func = no_op, + F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, + S32 max_retries = DEFAULT_MAX_RETRIES + ): + mDstCatID(dst_cat_id), + mTrackingPhase(phase_name), + mOnCompletionFunc(on_completion_func), + mOnFailureFunc(on_failure_func), + mRetryAfter(retry_after), + mMaxRetries(max_retries), + mPendingRequests(0), + mFailCount(0), + mCompletionOrFailureCalled(false), + mRetryCount(0), + LLEventTimer(5.0) + { + if (!mTrackingPhase.empty()) + { + selfStartPhase(mTrackingPhase); + } + } + + void addItems(LLInventoryModel::item_array_t& src_items) + { + for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin(); + it != src_items.end(); + ++it) + { + LLViewerInventoryItem* item = *it; + llassert(item); + addItem(item->getUUID()); + } + } + + // Request or re-request operation for specified item. + void addItem(const LLUUID& item_id) + { + LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; + if (!requestOperation(item_id)) + { + LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; + return; + } + + mPendingRequests++; + // On a re-request, this will reset the timer. + mWaitTimes[item_id] = LLTimer(); + if (mRetryCounts.find(item_id) == mRetryCounts.end()) + { + mRetryCounts[item_id] = 0; + } + else + { + mRetryCounts[item_id]++; + } + } + + virtual bool requestOperation(const LLUUID& item_id) = 0; + + void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp) + { + if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) + { + LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; + doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), + mRetryAfter); + return; + } + mPendingRequests--; + F32 elapsed = timestamp.getElapsedTimeF32(); + LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL; + if (mWaitTimes.find(src_id) == mWaitTimes.end()) + { + // No longer waiting for this item - either serviced + // already or gave up after too many retries. + LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id + << " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL; + } + mTimeStats.push(elapsed); + mWaitTimes.erase(src_id); + if (mWaitTimes.empty() && !mCompletionOrFailureCalled) + { + onCompletionOrFailure(); + } + } + + void onCompletionOrFailure() + { + assert (!mCompletionOrFailureCalled); + mCompletionOrFailureCalled = true; + + // Will never call onCompletion() if any item has been flagged as + // a failure - otherwise could wind up with corrupted + // outfit, involuntary nudity, etc. + reportStats(); + if (!mTrackingPhase.empty()) + { + selfStopPhase(mTrackingPhase); + } + if (!mFailCount) + { + onCompletion(); + } + else + { + onFailure(); + } + } + + void onFailure() + { + LL_INFOS() << "failed" << LL_ENDL; + mOnFailureFunc(); + } + + void onCompletion() + { + LL_INFOS() << "done" << LL_ENDL; + mOnCompletionFunc(); + } + + // virtual + // Will be deleted after returning true - only safe to do this if all callbacks have fired. + bool tick() override + { + // mPendingRequests will be zero if all requests have been + // responded to. mWaitTimes.empty() will be true if we have + // received at least one reply for each UUID. If requests + // have been dropped and retried, these will not necessarily + // be the same. Only safe to return true if all requests have + // been serviced, since it will result in this object being + // deleted. + bool all_done = (mPendingRequests==0); + + if (!mWaitTimes.empty()) + { + LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; + for (std::map<LLUUID,LLTimer>::iterator it = mWaitTimes.begin(); + it != mWaitTimes.end();) + { + // Use a copy of iterator because it may be erased/invalidated. + std::map<LLUUID,LLTimer>::iterator curr_it = it; + ++it; + + F32 time_waited = curr_it->second.getElapsedTimeF32(); + S32 retries = mRetryCounts[curr_it->first]; + if (time_waited > mRetryAfter) + { + if (retries < mMaxRetries) + { + LL_DEBUGS("Avatar") << "Waited " << time_waited << + " for " << curr_it->first << ", retrying" << LL_ENDL; + mRetryCount++; + addItem(curr_it->first); + } + else + { + LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; + mWaitTimes.erase(curr_it); + mFailCount++; + } + } + if (mWaitTimes.empty()) + { + onCompletionOrFailure(); + } + + } + } + return all_done; + } + + void reportStats() + { + LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL; + LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL; + LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL; + LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; + LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; + } + + virtual ~LLCallAfterInventoryBatchMgr() + { + LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; + } protected: - std::string mTrackingPhase; - std::map<LLUUID,LLTimer> mWaitTimes; - std::map<LLUUID,S32> mRetryCounts; - LLUUID mDstCatID; - nullary_func_t mOnCompletionFunc; - nullary_func_t mOnFailureFunc; - F32 mRetryAfter; - S32 mMaxRetries; - S32 mPendingRequests; - S32 mFailCount; - S32 mRetryCount; - bool mCompletionOrFailureCalled; - LLViewerStats::StatsAccumulator mTimeStats; + std::string mTrackingPhase; + std::map<LLUUID,LLTimer> mWaitTimes; + std::map<LLUUID,S32> mRetryCounts; + LLUUID mDstCatID; + nullary_func_t mOnCompletionFunc; + nullary_func_t mOnFailureFunc; + F32 mRetryAfter; + S32 mMaxRetries; + S32 mPendingRequests; + S32 mFailCount; + S32 mRetryCount; + bool mCompletionOrFailureCalled; + LLViewerStats::StatsAccumulator mTimeStats; }; class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr { public: - LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items, - const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) - { - addItems(src_items); - sInstanceCount++; - } - - ~LLCallAfterInventoryCopyMgr() - { - sInstanceCount--; - } - - virtual bool requestOperation(const LLUUID& item_id) - { - LLViewerInventoryItem *item = gInventory.getItem(item_id); - llassert(item); - LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; - return true; - } - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - mDstCatID, - std::string(), - new LLBoostFuncInventoryCallback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())) - ); - return true; - } - - static S32 getInstanceCount() { return sInstanceCount; } - + LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items, + const LLUUID& dst_cat_id, + const std::string& phase_name, + nullary_func_t on_completion_func, + nullary_func_t on_failure_func = no_op, + F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, + S32 max_retries = DEFAULT_MAX_RETRIES + ): + LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) + { + addItems(src_items); + sInstanceCount++; + } + + ~LLCallAfterInventoryCopyMgr() + { + sInstanceCount--; + } + + virtual bool requestOperation(const LLUUID& item_id) + { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + llassert(item); + LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; + if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) + { + LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; + return true; + } + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + mDstCatID, + std::string(), + new LLBoostFuncInventoryCallback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())) + ); + return true; + } + + static S32 getInstanceCount() { return sInstanceCount; } + private: - static S32 sInstanceCount; + static S32 sInstanceCount; }; S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; @@ -458,97 +458,97 @@ S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; class LLWearCategoryAfterCopy: public LLInventoryCallback { public: - LLWearCategoryAfterCopy(bool append): - mAppend(append) - {} - - // virtual - void fire(const LLUUID& id) - { - // Wear the inventory category. - LLInventoryCategory* cat = gInventory.getCategory(id); - LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); - } + LLWearCategoryAfterCopy(bool append): + mAppend(append) + {} + + // virtual + void fire(const LLUUID& id) + { + // Wear the inventory category. + LLInventoryCategory* cat = gInventory.getCategory(id); + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); + } private: - bool mAppend; + bool mAppend; }; class LLTrackPhaseWrapper : public LLInventoryCallback { public: - LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): - mTrackingPhase(phase_name), - mCB(cb) - { - selfStartPhase(mTrackingPhase); - } - - // virtual - void fire(const LLUUID& id) - { - if (mCB) - { - mCB->fire(id); - } - } - - // virtual - ~LLTrackPhaseWrapper() - { - selfStopPhase(mTrackingPhase); - } + LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): + mTrackingPhase(phase_name), + mCB(cb) + { + selfStartPhase(mTrackingPhase); + } + + // virtual + void fire(const LLUUID& id) + { + if (mCB) + { + mCB->fire(id); + } + } + + // virtual + ~LLTrackPhaseWrapper() + { + selfStopPhase(mTrackingPhase); + } protected: - std::string mTrackingPhase; - LLPointer<LLInventoryCallback> mCB; + std::string mTrackingPhase; + LLPointer<LLInventoryCallback> mCB; }; LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, - bool enforce_ordering, - nullary_func_t post_update_func - ): - mFireCount(0), - mEnforceItemRestrictions(enforce_item_restrictions), - mEnforceOrdering(enforce_ordering), - mPostUpdateFunc(post_update_func) + bool enforce_ordering, + nullary_func_t post_update_func + ): + mFireCount(0), + mEnforceItemRestrictions(enforce_item_restrictions), + mEnforceOrdering(enforce_ordering), + mPostUpdateFunc(post_update_func) { - selfStartPhase("update_appearance_on_destroy"); + selfStartPhase("update_appearance_on_destroy"); } void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); - const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); + const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; #ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; #endif - mFireCount++; + mFireCount++; } LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { - if (!LLApp::isExiting()) - { - // speculative fix for MAINT-1150 - LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; + if (!LLApp::isExiting()) + { + // speculative fix for MAINT-1150 + LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; - selfStopPhase("update_appearance_on_destroy"); + selfStopPhase("update_appearance_on_destroy"); - LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, - mEnforceOrdering, - mPostUpdateFunc); - } + LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, + mEnforceOrdering, + mPostUpdateFunc); + } } LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): - mItemID(item_id) + mItemID(item_id) { } LLRequestServerAppearanceUpdateOnDestroy::~LLRequestServerAppearanceUpdateOnDestroy() { - LL_DEBUGS("Avatar") << "ATT requesting server appearance update" << LL_ENDL; + LL_DEBUGS("Avatar") << "ATT requesting server appearance update" << LL_ENDL; if (!LLApp::isExiting()) { LLAppearanceMgr::instance().requestServerAppearanceUpdate(); @@ -557,30 +557,30 @@ LLRequestServerAppearanceUpdateOnDestroy::~LLRequestServerAppearanceUpdateOnDest void edit_wearable_and_customize_avatar(LLUUID item_id) { - // Start editing the item if previously requested. - gAgentWearables.editWearableIfRequested(item_id); - - // TODO: camera mode may not be changed if a debug setting is tweaked - if( gAgentCamera.cameraCustomizeAvatar() ) - { - // If we're in appearance editing mode, the current tab may need to be refreshed - LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>( - LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel) - { - panel->showDefaultSubpart(); - } - } + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(item_id); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( gAgentCamera.cameraCustomizeAvatar() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>( + LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel) + { + panel->showDefaultSubpart(); + } + } } LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() { - if (!LLApp::isExiting()) - { - LLAppearanceMgr::instance().updateAppearanceFromCOF( - true,true, - boost::bind(edit_wearable_and_customize_avatar, mItemID)); - } + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().updateAppearanceFromCOF( + true,true, + boost::bind(edit_wearable_and_customize_avatar, mItemID)); + } } class LLBrokenLinkObserver : public LLInventoryObserver @@ -651,738 +651,738 @@ void LLBrokenLinkObserver::postProcess() struct LLFoundData { - LLFoundData() : - mAssetType(LLAssetType::AT_NONE), - mWearableType(LLWearableType::WT_INVALID), - mWearable(NULL) {} - - LLFoundData(const LLUUID& item_id, - const LLUUID& asset_id, - const std::string& name, - const LLAssetType::EType& asset_type, - const LLWearableType::EType& wearable_type, - const bool is_replacement = false - ) : - mItemID(item_id), - mAssetID(asset_id), - mName(name), - mAssetType(asset_type), - mWearableType(wearable_type), - mIsReplacement(is_replacement), - mWearable( NULL ) {} - - LLUUID mItemID; - LLUUID mAssetID; - std::string mName; - LLAssetType::EType mAssetType; - LLWearableType::EType mWearableType; - LLViewerWearable* mWearable; - bool mIsReplacement; + LLFoundData() : + mAssetType(LLAssetType::AT_NONE), + mWearableType(LLWearableType::WT_INVALID), + mWearable(NULL) {} + + LLFoundData(const LLUUID& item_id, + const LLUUID& asset_id, + const std::string& name, + const LLAssetType::EType& asset_type, + const LLWearableType::EType& wearable_type, + const bool is_replacement = false + ) : + mItemID(item_id), + mAssetID(asset_id), + mName(name), + mAssetType(asset_type), + mWearableType(wearable_type), + mIsReplacement(is_replacement), + mWearable( NULL ) {} + + LLUUID mItemID; + LLUUID mAssetID; + std::string mName; + LLAssetType::EType mAssetType; + LLWearableType::EType mWearableType; + LLViewerWearable* mWearable; + bool mIsReplacement; }; - + class LLWearableHoldingPattern { - LOG_CLASS(LLWearableHoldingPattern); + LOG_CLASS(LLWearableHoldingPattern); public: - LLWearableHoldingPattern(); - ~LLWearableHoldingPattern(); - - bool pollFetchCompletion(); - void onFetchCompletion(); - bool isFetchCompleted(); - bool isTimedOut(); - - void checkMissingWearables(); - bool pollMissingWearables(); - bool isMissingCompleted(); - void recoverMissingWearable(LLWearableType::EType type); - void clearCOFLinksForMissingWearables(); - - void onWearableAssetFetch(LLViewerWearable *wearable); - void onAllComplete(); - - typedef std::list<LLFoundData> found_list_t; - found_list_t& getFoundList(); - void eraseTypeToLink(LLWearableType::EType type); - void eraseTypeToRecover(LLWearableType::EType type); - void setObjItems(const LLInventoryModel::item_array_t& items); - void setGestItems(const LLInventoryModel::item_array_t& items); - bool isMostRecent(); - void handleLateArrivals(); - void resetTime(F32 timeout); - static S32 countActive() { return sActiveHoldingPatterns.size(); } - S32 index() { return mIndex; } - + LLWearableHoldingPattern(); + ~LLWearableHoldingPattern(); + + bool pollFetchCompletion(); + void onFetchCompletion(); + bool isFetchCompleted(); + bool isTimedOut(); + + void checkMissingWearables(); + bool pollMissingWearables(); + bool isMissingCompleted(); + void recoverMissingWearable(LLWearableType::EType type); + void clearCOFLinksForMissingWearables(); + + void onWearableAssetFetch(LLViewerWearable *wearable); + void onAllComplete(); + + typedef std::list<LLFoundData> found_list_t; + found_list_t& getFoundList(); + void eraseTypeToLink(LLWearableType::EType type); + void eraseTypeToRecover(LLWearableType::EType type); + void setObjItems(const LLInventoryModel::item_array_t& items); + void setGestItems(const LLInventoryModel::item_array_t& items); + bool isMostRecent(); + void handleLateArrivals(); + void resetTime(F32 timeout); + static S32 countActive() { return sActiveHoldingPatterns.size(); } + S32 index() { return mIndex; } + private: - found_list_t mFoundList; - LLInventoryModel::item_array_t mObjItems; - LLInventoryModel::item_array_t mGestItems; - typedef std::set<S32> type_set_t; - type_set_t mTypesToRecover; - type_set_t mTypesToLink; - S32 mResolved; - LLTimer mWaitTime; - bool mFired; - typedef std::set<LLWearableHoldingPattern*> type_set_hp; - static type_set_hp sActiveHoldingPatterns; - static S32 sNextIndex; - S32 mIndex; - bool mIsMostRecent; - std::set<LLViewerWearable*> mLateArrivals; - bool mIsAllComplete; + found_list_t mFoundList; + LLInventoryModel::item_array_t mObjItems; + LLInventoryModel::item_array_t mGestItems; + typedef std::set<S32> type_set_t; + type_set_t mTypesToRecover; + type_set_t mTypesToLink; + S32 mResolved; + LLTimer mWaitTime; + bool mFired; + typedef std::set<LLWearableHoldingPattern*> type_set_hp; + static type_set_hp sActiveHoldingPatterns; + static S32 sNextIndex; + S32 mIndex; + bool mIsMostRecent; + std::set<LLViewerWearable*> mLateArrivals; + bool mIsAllComplete; }; LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; S32 LLWearableHoldingPattern::sNextIndex = 0; LLWearableHoldingPattern::LLWearableHoldingPattern(): - mResolved(0), - mFired(false), - mIsMostRecent(true), - mIsAllComplete(false) -{ - if (countActive()>0) - { - LL_INFOS() << "Creating LLWearableHoldingPattern when " - << countActive() - << " other attempts are active." - << " Flagging others as invalid." - << LL_ENDL; - for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); - it != sActiveHoldingPatterns.end(); - ++it) - { - (*it)->mIsMostRecent = false; - } - - } - mIndex = sNextIndex++; - sActiveHoldingPatterns.insert(this); - LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; - selfStartPhase("holding_pattern"); + mResolved(0), + mFired(false), + mIsMostRecent(true), + mIsAllComplete(false) +{ + if (countActive()>0) + { + LL_INFOS() << "Creating LLWearableHoldingPattern when " + << countActive() + << " other attempts are active." + << " Flagging others as invalid." + << LL_ENDL; + for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); + it != sActiveHoldingPatterns.end(); + ++it) + { + (*it)->mIsMostRecent = false; + } + + } + mIndex = sNextIndex++; + sActiveHoldingPatterns.insert(this); + LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; + selfStartPhase("holding_pattern"); } LLWearableHoldingPattern::~LLWearableHoldingPattern() { - sActiveHoldingPatterns.erase(this); - if (isMostRecent()) - { - selfStopPhase("holding_pattern"); - } - LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; + sActiveHoldingPatterns.erase(this); + if (isMostRecent()) + { + selfStopPhase("holding_pattern"); + } + LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; } bool LLWearableHoldingPattern::isMostRecent() { - return mIsMostRecent; + return mIsMostRecent; } LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList() { - return mFoundList; + return mFoundList; } void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type) { - mTypesToLink.erase(type); + mTypesToLink.erase(type); } void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type) { - mTypesToRecover.erase(type); + mTypesToRecover.erase(type); } void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) { - mObjItems = items; + mObjItems = items; } void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items) { - mGestItems = items; + mGestItems = items; } bool LLWearableHoldingPattern::isFetchCompleted() { - return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? + return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? } bool LLWearableHoldingPattern::isTimedOut() { - return mWaitTime.hasExpired(); + return mWaitTime.hasExpired(); } void LLWearableHoldingPattern::checkMissingWearables() { - if (!isMostRecent()) - { - // runway why don't we actually skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0); - std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0); - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) - { - LLFoundData &data = *it; - if (data.mWearableType < LLWearableType::WT_COUNT) - requested_by_type[data.mWearableType]++; - if (data.mWearable) - found_by_type[data.mWearableType]++; - } - - for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) - { - if (requested_by_type[type] > found_by_type[type]) - { - LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL; - } - if (found_by_type[type] > 0) - continue; - if ( - // If at least one wearable of certain types (pants/shirt/skirt) - // was requested but none was found, create a default asset as a replacement. - // In all other cases, don't do anything. - // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud - // due to logic in LLVOAvatarSelf::getIsCloud(). - // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. - (requested_by_type[type] > 0) && - ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) - { - mTypesToRecover.insert(type); - mTypesToLink.insert(type); - recoverMissingWearable((LLWearableType::EType)type); - LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL; - } - } - - resetTime(60.0F); - - if (isMostRecent()) - { - selfStartPhase("get_missing_wearables_2"); - } - if (!pollMissingWearables()) - { - doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); - } + if (!isMostRecent()) + { + // runway why don't we actually skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0); + std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0); + for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + { + LLFoundData &data = *it; + if (data.mWearableType < LLWearableType::WT_COUNT) + requested_by_type[data.mWearableType]++; + if (data.mWearable) + found_by_type[data.mWearableType]++; + } + + for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) + { + if (requested_by_type[type] > found_by_type[type]) + { + LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL; + } + if (found_by_type[type] > 0) + continue; + if ( + // If at least one wearable of certain types (pants/shirt/skirt) + // was requested but none was found, create a default asset as a replacement. + // In all other cases, don't do anything. + // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud + // due to logic in LLVOAvatarSelf::getIsCloud(). + // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. + (requested_by_type[type] > 0) && + ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) + { + mTypesToRecover.insert(type); + mTypesToLink.insert(type); + recoverMissingWearable((LLWearableType::EType)type); + LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL; + } + } + + resetTime(60.0F); + + if (isMostRecent()) + { + selfStartPhase("get_missing_wearables_2"); + } + if (!pollMissingWearables()) + { + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); + } } void LLWearableHoldingPattern::onAllComplete() { - if (isAgentAvatarValid()) - { - gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); - } - - if (!isMostRecent()) - { - // runway need to skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - // Activate all gestures in this folder - if (mGestItems.size() > 0) - { - LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL; - - LLGestureMgr::instance().activateGestures(mGestItems); - - // Update the inventory item labels to reflect the fact - // they are active. - LLViewerInventoryCategory* catp = - gInventory.getCategory(LLAppearanceMgr::instance().getCOF()); - - if (catp) - { - gInventory.updateCategory(catp); - gInventory.notifyObservers(); - } - } - - if (isAgentAvatarValid()) - { - LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; - LLAgentWearables::llvo_vec_t objects_to_remove; - LLAgentWearables::llvo_vec_t objects_to_retain; - LLInventoryModel::item_array_t items_to_add; - - LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, - objects_to_remove, - objects_to_retain, - items_to_add); - - LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() - << " attachments" << LL_ENDL; - - // Here we remove the attachment pos overrides for *all* - // attachments, even those that are not being removed. This is - // needed to get joint positions all slammed down to their - // pre-attachment states. - gAgentAvatarp->clearAttachmentOverrides(); - - if (objects_to_remove.size() || items_to_add.size()) - { - LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() - << " and add " << items_to_add.size() << " items" << LL_ENDL; - } - - // Take off the attachments that will no longer be in the outfit. - LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); - - // Update wearables. - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " - << mResolved << " wearable items " << LL_ENDL; - LLAppearanceMgr::instance().updateAgentWearables(this); - - // Restore attachment pos overrides for the attachments that - // are remaining in the outfit. - for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); - it != objects_to_retain.end(); - ++it) - { - LLViewerObject *objectp = *it; + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); + } + + if (!isMostRecent()) + { + // runway need to skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + // Activate all gestures in this folder + if (mGestItems.size() > 0) + { + LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL; + + LLGestureMgr::instance().activateGestures(mGestItems); + + // Update the inventory item labels to reflect the fact + // they are active. + LLViewerInventoryCategory* catp = + gInventory.getCategory(LLAppearanceMgr::instance().getCOF()); + + if (catp) + { + gInventory.updateCategory(catp); + gInventory.notifyObservers(); + } + } + + if (isAgentAvatarValid()) + { + LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; + LLAgentWearables::llvo_vec_t objects_to_remove; + LLAgentWearables::llvo_vec_t objects_to_retain; + LLInventoryModel::item_array_t items_to_add; + + LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, + objects_to_remove, + objects_to_retain, + items_to_add); + + LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() + << " attachments" << LL_ENDL; + + // Here we remove the attachment pos overrides for *all* + // attachments, even those that are not being removed. This is + // needed to get joint positions all slammed down to their + // pre-attachment states. + gAgentAvatarp->clearAttachmentOverrides(); + + if (objects_to_remove.size() || items_to_add.size()) + { + LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() + << " and add " << items_to_add.size() << " items" << LL_ENDL; + } + + // Take off the attachments that will no longer be in the outfit. + LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); + + // Update wearables. + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " + << mResolved << " wearable items " << LL_ENDL; + LLAppearanceMgr::instance().updateAgentWearables(this); + + // Restore attachment pos overrides for the attachments that + // are remaining in the outfit. + for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); + it != objects_to_retain.end(); + ++it) + { + LLViewerObject *objectp = *it; if (!objectp->isAnimatedObject()) { gAgentAvatarp->addAttachmentOverridesForObject(objectp); } - } - - // Add new attachments to match those requested. - LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; - LLAgentWearables::userAttachMultipleAttachments(items_to_add); - } - - if (isFetchCompleted() && isMissingCompleted()) - { - // Only safe to delete if all wearable callbacks and all missing wearables completed. - delete this; - } - else - { - mIsAllComplete = true; - handleLateArrivals(); - } + } + + // Add new attachments to match those requested. + LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; + LLAgentWearables::userAttachMultipleAttachments(items_to_add); + } + + if (isFetchCompleted() && isMissingCompleted()) + { + // Only safe to delete if all wearable callbacks and all missing wearables completed. + delete this; + } + else + { + mIsAllComplete = true; + handleLateArrivals(); + } } void LLWearableHoldingPattern::onFetchCompletion() { - if (isMostRecent()) - { - selfStopPhase("get_wearables_2"); - } - - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + if (isMostRecent()) + { + selfStopPhase("get_wearables_2"); + } + + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } - checkMissingWearables(); + checkMissingWearables(); } // Runs as an idle callback until all wearables are fetched (or we time out). bool LLWearableHoldingPattern::pollFetchCompletion() { - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + bool completed = isFetchCompleted(); + bool timed_out = isTimedOut(); + bool done = completed || timed_out; - bool completed = isFetchCompleted(); - bool timed_out = isTimedOut(); - bool done = completed || timed_out; + if (done) + { + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; - if (done) - { - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; + mFired = true; - mFired = true; - - if (timed_out) - { - LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL; - } + if (timed_out) + { + LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL; + } - onFetchCompletion(); - } - return done; + onFetchCompletion(); + } + return done; } void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) { - if (!holder->isMostRecent()) - { - LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - // runway skip here? - } - - LL_INFOS("Avatar") << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; - holder->eraseTypeToLink(type); - // Add wearable to FoundData for actual wearing - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - - if (linked_item) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); - - if (item) - { - LLFoundData found(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, - true // is replacement - ); - found.mWearable = wearable; - holder->getFoundList().push_front(found); - } - else - { - LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; - } - } - else - { - LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; - } + if (!holder->isMostRecent()) + { + LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + // runway skip here? + } + + LL_INFOS("Avatar") << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; + holder->eraseTypeToLink(type); + // Add wearable to FoundData for actual wearing + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + + if (linked_item) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + + if (item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, + true // is replacement + ); + found.mWearable = wearable; + holder->getFoundList().push_front(found); + } + else + { + LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; + } + } + else + { + LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; + } } void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) { - if (!holder->isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + if (!holder->isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } - LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; - LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id); - wearable->setItemID(item_id); - holder->eraseTypeToRecover(type); - llassert(itemp); - if (itemp) - { - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); + LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; + LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id); + wearable->setItemID(item_id); + holder->eraseTypeToRecover(type); + llassert(itemp); + if (itemp) + { + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); - link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); - } + link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); + } } void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type) { - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - // Try to recover by replacing missing wearable with a new one. - LLNotificationsUtil::add("ReplacedMissingWearable"); - LL_DEBUGS("Avatar") << "Wearable of type '" << LLWearableType::getInstance()->getTypeName(type) - << "' could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; - LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - - // Add a new one in the lost and found folder. - const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this)); + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + // Try to recover by replacing missing wearable with a new one. + LLNotificationsUtil::add("ReplacedMissingWearable"); + LL_DEBUGS("Avatar") << "Wearable of type '" << LLWearableType::getInstance()->getTypeName(type) + << "' could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; + LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); + + // Add a new one in the lost and found folder. + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this)); create_inventory_wearable(gAgent.getID(), - gAgent.getSessionID(), - lost_and_found_id, - wearable->getTransactionID(), - wearable->getName(), - wearable->getDescription(), - wearable->getAssetType(), - wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), - cb); + gAgent.getSessionID(), + lost_and_found_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); } bool LLWearableHoldingPattern::isMissingCompleted() { - return mTypesToLink.size()==0 && mTypesToRecover.size()==0; + return mTypesToLink.size()==0 && mTypesToRecover.size()==0; } void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() { - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) - { - LLFoundData &data = *it; - if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) - { - // Wearable link that was never resolved; remove links to it from COF - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); - } - } + for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + { + LLFoundData &data = *it; + if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) + { + // Wearable link that was never resolved; remove links to it from COF + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; + LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); + } + } } bool LLWearableHoldingPattern::pollMissingWearables() { - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - bool timed_out = isTimedOut(); - bool missing_completed = isMissingCompleted(); - bool done = timed_out || missing_completed; - - if (!done) - { - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() - << " links " << mTypesToLink.size() - << " wearables, timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() - << " done " << done << LL_ENDL; - } - - if (done) - { - if (isMostRecent()) - { - selfStopPhase("get_missing_wearables_2"); - } - - gAgentAvatarp->debugWearablesLoaded(); - - // BAP - if we don't call clearCOFLinksForMissingWearables() - // here, we won't have to add the link back in later if the - // wearable arrives late. This is to avoid corruption of - // wearable ordering info. Also has the effect of making - // unworn item links visible in the COF under some - // circumstances. - - //clearCOFLinksForMissingWearables(); - onAllComplete(); - } - return done; -} + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } -// Handle wearables that arrived after the timeout period expired. -void LLWearableHoldingPattern::handleLateArrivals() -{ - // Only safe to run if we have previously finished the missing - // wearables and other processing - otherwise we could be in some - // intermediate state - but have not been superceded by a later - // outfit change request. - if (mLateArrivals.size() == 0) - { - // Nothing to process. - return; - } - if (!isMostRecent()) - { - LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL; - } - if (!mIsAllComplete) - { - LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; - } - - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; - - // Update mFoundList using late-arriving wearables. - std::set<LLWearableType::EType> replaced_types; - for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - iter != getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - for (std::set<LLViewerWearable*>::iterator wear_it = mLateArrivals.begin(); - wear_it != mLateArrivals.end(); - ++wear_it) - { - LLViewerWearable *wearable = *wear_it; - - if(wearable->getAssetID() == data.mAssetID) - { - data.mWearable = wearable; - - replaced_types.insert(data.mWearableType); - - // BAP - if we didn't call - // clearCOFLinksForMissingWearables() earlier, we - // don't need to restore the link here. Fixes - // wearable ordering problems. - - // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false); - - // BAP failing this means inventory or asset server - // are corrupted in a way we don't handle. - llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType)); - break; - } - } - } - - // Remove COF links for any default wearables previously used to replace the late arrivals. - // All this pussyfooting around with a while loop and explicit - // iterator incrementing is to allow removing items from the list - // without clobbering the iterator we're using to navigate. - LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - while (iter != getFoundList().end()) - { - LLFoundData& data = *iter; - - // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. - if (data.mWearable && data.mIsReplacement && - replaced_types.find(data.mWearableType) != replaced_types.end()) - { - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); - std::list<LLFoundData>::iterator clobber_ator = iter; - ++iter; - getFoundList().erase(clobber_ator); - } - else - { - ++iter; - } - } - - // Clear contents of late arrivals. - mLateArrivals.clear(); - - // Update appearance based on mFoundList - LLAppearanceMgr::instance().updateAgentWearables(this); -} + bool timed_out = isTimedOut(); + bool missing_completed = isMissingCompleted(); + bool done = timed_out || missing_completed; -void LLWearableHoldingPattern::resetTime(F32 timeout) -{ - mWaitTime.reset(); - mWaitTime.setTimerExpirySec(timeout); -} + if (!done) + { + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() + << " links " << mTypesToLink.size() + << " wearables, timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() + << " done " << done << LL_ENDL; + } -void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) -{ - if (!isMostRecent()) - { - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - mResolved += 1; // just counting callbacks, not successes. - LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; - if (!wearable) - { - LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; - } - - if (mFired) - { - LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL; - if (wearable) - { - mLateArrivals.insert(wearable); - if (mIsAllComplete) - { - handleLateArrivals(); - } - } - return; - } - - if (!wearable) - { - return; - } - - U32 use_count = 0; - for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - iter != getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - if (wearable->getAssetID() == data.mAssetID) - { - // Failing this means inventory or asset server are corrupted in a way we don't handle. - if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) - { - LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL; - break; - } - - if (use_count == 0) - { - data.mWearable = wearable; - use_count++; - } - else - { - LLViewerInventoryItem* wearable_item = gInventory.getItem(data.mItemID); - if (wearable_item && wearable_item->isFinished() && wearable_item->getPermissions().allowModifyBy(gAgentID)) - { - // We can't edit and do some other interactions with same asset twice, copy it - // Note: can't update incomplete items. Usually attached from previous viewer build, but - // consider adding fetch and completion callback - LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(wearable, wearable->getName()); - data.mWearable = new_wearable; - data.mAssetID = new_wearable->getAssetID(); - - // Update existing inventory item - wearable_item->setAssetUUID(new_wearable->getAssetID()); - wearable_item->setTransactionID(new_wearable->getTransactionID()); - gInventory.updateItem(wearable_item, LLInventoryObserver::INTERNAL); - wearable_item->updateServer(FALSE); - - use_count++; - } - else - { - // Note: technically a bug, LLViewerWearable can identify only one item id at a time, - // yet we are tying it to multiple items here. - // LLViewerWearable need to support more then one item. - LL_WARNS() << "Same LLViewerWearable is used by multiple items! " << wearable->getAssetID() << LL_ENDL; - data.mWearable = wearable; - } - } - } - } - - if (use_count > 1) - { - LL_WARNS() << "Copying wearable, multiple asset id uses! " << wearable->getAssetID() << LL_ENDL; - gInventory.notifyObservers(); - } -} + if (done) + { + if (isMostRecent()) + { + selfStopPhase("get_missing_wearables_2"); + } -static void onWearableAssetFetch(LLViewerWearable* wearable, void* data) -{ - LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; - holder->onWearableAssetFetch(wearable); -} + gAgentAvatarp->debugWearablesLoaded(); + + // BAP - if we don't call clearCOFLinksForMissingWearables() + // here, we won't have to add the link back in later if the + // wearable arrives late. This is to avoid corruption of + // wearable ordering info. Also has the effect of making + // unworn item links visible in the COF under some + // circumstances. + + //clearCOFLinksForMissingWearables(); + onAllComplete(); + } + return done; +} + +// Handle wearables that arrived after the timeout period expired. +void LLWearableHoldingPattern::handleLateArrivals() +{ + // Only safe to run if we have previously finished the missing + // wearables and other processing - otherwise we could be in some + // intermediate state - but have not been superceded by a later + // outfit change request. + if (mLateArrivals.size() == 0) + { + // Nothing to process. + return; + } + if (!isMostRecent()) + { + LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL; + } + if (!mIsAllComplete) + { + LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; + } + + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; + + // Update mFoundList using late-arriving wearables. + std::set<LLWearableType::EType> replaced_types; + for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + iter != getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + for (std::set<LLViewerWearable*>::iterator wear_it = mLateArrivals.begin(); + wear_it != mLateArrivals.end(); + ++wear_it) + { + LLViewerWearable *wearable = *wear_it; + + if(wearable->getAssetID() == data.mAssetID) + { + data.mWearable = wearable; + + replaced_types.insert(data.mWearableType); + + // BAP - if we didn't call + // clearCOFLinksForMissingWearables() earlier, we + // don't need to restore the link here. Fixes + // wearable ordering problems. + + // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false); + + // BAP failing this means inventory or asset server + // are corrupted in a way we don't handle. + llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType)); + break; + } + } + } + + // Remove COF links for any default wearables previously used to replace the late arrivals. + // All this pussyfooting around with a while loop and explicit + // iterator incrementing is to allow removing items from the list + // without clobbering the iterator we're using to navigate. + LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + while (iter != getFoundList().end()) + { + LLFoundData& data = *iter; + + // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. + if (data.mWearable && data.mIsReplacement && + replaced_types.find(data.mWearableType) != replaced_types.end()) + { + LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); + std::list<LLFoundData>::iterator clobber_ator = iter; + ++iter; + getFoundList().erase(clobber_ator); + } + else + { + ++iter; + } + } + + // Clear contents of late arrivals. + mLateArrivals.clear(); + + // Update appearance based on mFoundList + LLAppearanceMgr::instance().updateAgentWearables(this); +} + +void LLWearableHoldingPattern::resetTime(F32 timeout) +{ + mWaitTime.reset(); + mWaitTime.setTimerExpirySec(timeout); +} + +void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) +{ + if (!isMostRecent()) + { + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + mResolved += 1; // just counting callbacks, not successes. + LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; + if (!wearable) + { + LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; + } + + if (mFired) + { + LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL; + if (wearable) + { + mLateArrivals.insert(wearable); + if (mIsAllComplete) + { + handleLateArrivals(); + } + } + return; + } + + if (!wearable) + { + return; + } + + U32 use_count = 0; + for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + iter != getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + if (wearable->getAssetID() == data.mAssetID) + { + // Failing this means inventory or asset server are corrupted in a way we don't handle. + if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) + { + LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL; + break; + } + + if (use_count == 0) + { + data.mWearable = wearable; + use_count++; + } + else + { + LLViewerInventoryItem* wearable_item = gInventory.getItem(data.mItemID); + if (wearable_item && wearable_item->isFinished() && wearable_item->getPermissions().allowModifyBy(gAgentID)) + { + // We can't edit and do some other interactions with same asset twice, copy it + // Note: can't update incomplete items. Usually attached from previous viewer build, but + // consider adding fetch and completion callback + LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(wearable, wearable->getName()); + data.mWearable = new_wearable; + data.mAssetID = new_wearable->getAssetID(); + + // Update existing inventory item + wearable_item->setAssetUUID(new_wearable->getAssetID()); + wearable_item->setTransactionID(new_wearable->getTransactionID()); + gInventory.updateItem(wearable_item, LLInventoryObserver::INTERNAL); + wearable_item->updateServer(FALSE); + + use_count++; + } + else + { + // Note: technically a bug, LLViewerWearable can identify only one item id at a time, + // yet we are tying it to multiple items here. + // LLViewerWearable need to support more then one item. + LL_WARNS() << "Same LLViewerWearable is used by multiple items! " << wearable->getAssetID() << LL_ENDL; + data.mWearable = wearable; + } + } + } + } + + if (use_count > 1) + { + LL_WARNS() << "Copying wearable, multiple asset id uses! " << wearable->getAssetID() << LL_ENDL; + gInventory.notifyObservers(); + } +} + +static void onWearableAssetFetch(LLViewerWearable* wearable, void* data) +{ + LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; + holder->onWearableAssetFetch(wearable); +} static void removeDuplicateItems(LLInventoryModel::item_array_t& items) { - LLInventoryModel::item_array_t new_items; - std::set<LLUUID> items_seen; - std::deque<LLViewerInventoryItem*> tmp_list; - // Traverse from the front and keep the first of each item - // encountered, so we actually keep the *last* of each duplicate - // item. This is needed to give the right priority when adding - // duplicate items to an existing outfit. - for (S32 i=items.size()-1; i>=0; i--) - { - LLViewerInventoryItem *item = items.at(i); - LLUUID item_id = item->getLinkedUUID(); - if (items_seen.find(item_id)!=items_seen.end()) - continue; - items_seen.insert(item_id); - tmp_list.push_front(item); - } - for (std::deque<LLViewerInventoryItem*>::iterator it = tmp_list.begin(); - it != tmp_list.end(); - ++it) - { - new_items.push_back(*it); - } - items = new_items; + LLInventoryModel::item_array_t new_items; + std::set<LLUUID> items_seen; + std::deque<LLViewerInventoryItem*> tmp_list; + // Traverse from the front and keep the first of each item + // encountered, so we actually keep the *last* of each duplicate + // item. This is needed to give the right priority when adding + // duplicate items to an existing outfit. + for (S32 i=items.size()-1; i>=0; i--) + { + LLViewerInventoryItem *item = items.at(i); + LLUUID item_id = item->getLinkedUUID(); + if (items_seen.find(item_id)!=items_seen.end()) + continue; + items_seen.insert(item_id); + tmp_list.push_front(item); + } + for (std::deque<LLViewerInventoryItem*>::iterator it = tmp_list.begin(); + it != tmp_list.end(); + ++it) + { + new_items.push_back(*it); + } + items = new_items; } //========================================================================= @@ -1391,98 +1391,98 @@ const std::string LLAppearanceMgr::sExpectedTextureName = "OutfitPreview"; const LLUUID LLAppearanceMgr::getCOF() const { - return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); } S32 LLAppearanceMgr::getCOFVersion() const { - LLViewerInventoryCategory *cof = gInventory.getCategory(getCOF()); - if (cof) - { - return cof->getVersion(); - } - else - { - return LLViewerInventoryCategory::VERSION_UNKNOWN; - } + LLViewerInventoryCategory *cof = gInventory.getCategory(getCOF()); + if (cof) + { + return cof->getVersion(); + } + else + { + return LLViewerInventoryCategory::VERSION_UNKNOWN; + } } const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() { - const LLUUID& current_outfit_cat = getCOF(); - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - // Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't - // return preferred type. - LLIsType is_category( LLAssetType::AT_CATEGORY ); - gInventory.collectDescendentsIf(current_outfit_cat, - cat_array, - item_array, - false, - is_category); - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) - { - const LLViewerInventoryItem *item = (*iter); - const LLViewerInventoryCategory *cat = item->getLinkedCategory(); - if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) - { - const LLUUID parent_id = cat->getParentUUID(); - LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id); - // if base outfit moved to trash it means that we don't have base outfit - if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) - { - return NULL; - } - return item; - } - } - return NULL; + const LLUUID& current_outfit_cat = getCOF(); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + // Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't + // return preferred type. + LLIsType is_category( LLAssetType::AT_CATEGORY ); + gInventory.collectDescendentsIf(current_outfit_cat, + cat_array, + item_array, + false, + is_category); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + const LLViewerInventoryCategory *cat = item->getLinkedCategory(); + if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + const LLUUID parent_id = cat->getParentUUID(); + LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id); + // if base outfit moved to trash it means that we don't have base outfit + if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) + { + return NULL; + } + return item; + } + } + return NULL; } bool LLAppearanceMgr::getBaseOutfitName(std::string& name) { - const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); - if(outfit_link) - { - const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory(); - if (cat) - { - name = cat->getName(); - return true; - } - } - return false; + const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); + if(outfit_link) + { + const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory(); + if (cat) + { + name = cat->getName(); + return true; + } + } + return false; } const LLUUID LLAppearanceMgr::getBaseOutfitUUID() { - const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); - if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; + const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); + if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; - const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); - if (!outfit_cat) return LLUUID::null; + const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); + if (!outfit_cat) return LLUUID::null; - if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) - { - LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL; - return LLUUID::null; - } + if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL; + return LLUUID::null; + } - return outfit_cat->getUUID(); + return outfit_cat->getUUID(); } void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false) { - if (inv_item.isNull()) - return; - - LLViewerInventoryItem *item = gInventory.getItem(inv_item); - if (item) - { - LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, do_replace); - } + if (inv_item.isNull()) + return; + + LLViewerInventoryItem *item = gInventory.getItem(inv_item); + if (item) + { + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, do_replace); + } } void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, @@ -1490,8 +1490,8 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, bool replace, LLPointer<LLInventoryCallback> cb) { - LL_DEBUGS("UIUsage") << "wearItemsOnAvatar" << LL_ENDL; - LLUIUsage::instance().logCommand("Avatar.WearItem"); + LL_DEBUGS("UIUsage") << "wearItemsOnAvatar" << LL_ENDL; + LLUIUsage::instance().logCommand("Avatar.WearItem"); bool first = true; @@ -1527,13 +1527,13 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb); continue; - } + } else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) { - // not in library and not in agent's inventory + // not in library and not in agent's inventory LL_DEBUGS("Avatar") << "inventory item not in user inventory or library, skipping " << item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL; - continue; + continue; } else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) { @@ -1567,16 +1567,16 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, wearable_count-1); removeCOFItemLinks(item_id, cb); } - + items_to_link.push_back(item_to_wear); - } + } } break; case LLAssetType::AT_BODYPART: { // TODO: investigate wearables may not be loaded at this point EXT-8231 - + // Remove the existing wearables of the same type. // Remove existing body parts anyway because we must not be able to wear e.g. two skins. removeCOFLinksOfType(item_to_wear->getWearableType()); @@ -1587,7 +1587,7 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, items_to_link.push_back(item_to_wear); } break; - + case LLAssetType::AT_OBJECT: { rez_attachment(item_to_wear, NULL, replace); @@ -1601,14 +1601,14 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, // Batch up COF link creation - more efficient if using AIS. if (items_to_link.size()) { - link_inventory_array(getCOF(), items_to_link, cb); + link_inventory_array(getCOF(), items_to_link, cb); } } void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, - bool do_update, - bool replace, - LLPointer<LLInventoryCallback> cb) + bool do_update, + bool replace, + LLPointer<LLInventoryCallback> cb) { uuid_vec_t ids; ids.push_back(item_id_to_wear); @@ -1618,15 +1618,15 @@ void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, // Update appearance from outfit folder. void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append) { - if (!proceed) - return; - LLAppearanceMgr::instance().updateCOF(category,append); + if (!proceed) + return; + LLAppearanceMgr::instance().updateCOF(category,append); } void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit) { - LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); - wearInventoryCategory(cat, false, false); + LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); + wearInventoryCategory(cat, false, false); } // Remove existing photo link from outfit folder. @@ -1659,111 +1659,111 @@ void LLAppearanceMgr::removeOutfitPhoto(const LLUUID& outfit_id) // Open outfit renaming dialog. void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id) { - LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); - if (!cat) - { - return; - } + LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); + if (!cat) + { + return; + } - LLSD args; - args["NAME"] = cat->getName(); + LLSD args; + args["NAME"] = cat->getName(); - LLSD payload; - payload["cat_id"] = outfit_id; + LLSD payload; + payload["cat_id"] = outfit_id; - LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); + LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); } // User typed new outfit name. // static void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; // canceled + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled - std::string outfit_name = response["new_name"].asString(); - LLStringUtil::trim(outfit_name); - if (!outfit_name.empty()) - { - LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); - rename_category(&gInventory, cat_id, outfit_name); - } + std::string outfit_name = response["new_name"].asString(); + LLStringUtil::trim(outfit_name); + if (!outfit_name.empty()) + { + LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); + rename_category(&gInventory, cat_id, outfit_name); + } } void LLAppearanceMgr::setOutfitLocked(bool locked) { - if (mOutfitLocked == locked) - { - return; - } + if (mOutfitLocked == locked) + { + return; + } - mOutfitLocked = locked; - if (locked) - { - mUnlockOutfitTimer->start(); - } - else - { - mUnlockOutfitTimer->stop(); - } + mOutfitLocked = locked; + if (locked) + { + mUnlockOutfitTimer->start(); + } + else + { + mUnlockOutfitTimer->stop(); + } - LLOutfitObserver::instance().notifyOutfitLockChanged(); + LLOutfitObserver::instance().notifyOutfitLockChanged(); } void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id) { - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - wearInventoryCategory(cat, false, true); + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + wearInventoryCategory(cat, false, true); } void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); - - gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); - - LLInventoryModel::item_array_t::const_iterator it = items.begin(); - const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); - uuid_vec_t uuids_to_remove; - for( ; it_end != it; ++it) - { - LLViewerInventoryItem* item = *it; - uuids_to_remove.push_back(item->getUUID()); - } - removeItemsFromAvatar(uuids_to_remove); - - // deactivate all gestures in the outfit folder - LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE); - for(S32 i = 0; i < gest_items.size(); ++i) - { - LLViewerInventoryItem *gest_item = gest_items[i]; - if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) - { - LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); - } - } + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); + + gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); + + LLInventoryModel::item_array_t::const_iterator it = items.begin(); + const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); + uuid_vec_t uuids_to_remove; + for( ; it_end != it; ++it) + { + LLViewerInventoryItem* item = *it; + uuids_to_remove.push_back(item->getUUID()); + } + removeItemsFromAvatar(uuids_to_remove); + + // deactivate all gestures in the outfit folder + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE); + for(S32 i = 0; i < gest_items.size(); ++i) + { + LLViewerInventoryItem *gest_item = gest_items[i]; + if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) + { + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); + } + } } // Create a copy of src_id + contents as a subfolder of dst_id. void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, - LLPointer<LLInventoryCallback> cb) -{ - LLInventoryCategory *src_cat = gInventory.getCategory(src_id); - if (!src_cat) - { - LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL; - return; - } - LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL; - LLUUID parent_id = dst_id; - if(parent_id.isNull()) - { - parent_id = gInventory.getRootFolderID(); - } - gInventory.createNewCategory( + LLPointer<LLInventoryCallback> cb) +{ + LLInventoryCategory *src_cat = gInventory.getCategory(src_id); + if (!src_cat) + { + LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL; + return; + } + LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL; + LLUUID parent_id = dst_id; + if(parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + gInventory.createNewCategory( parent_id, LLFolderType::FT_NONE, src_cat->getName(), @@ -1778,326 +1778,326 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds } void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, - bool include_folder_links, LLPointer<LLInventoryCallback> cb) -{ - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - LLSD contents = LLSD::emptyArray(); - gInventory.getDirectDescendentsOf(src_id, cats, items); - if (!cats || !items) - { - // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean - // that the cat just doesn't have any items or subfolders). - LLViewerInventoryCategory* category = gInventory.getCategory(src_id); - if (category) - { - LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; - } - else - { - LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; - } - llassert(cats != NULL && items != NULL); - - return; - } - - LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; - for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); - iter != items->end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - switch (item->getActualType()) - { - case LLAssetType::AT_LINK: - { - LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; - //getActualDescription() is used for a new description - //to propagate ordering information saved in descriptions of links - LLSD item_contents; - item_contents["name"] = item->getName(); - item_contents["desc"] = item->getActualDescription(); - item_contents["linked_id"] = item->getLinkedUUID(); - item_contents["type"] = LLAssetType::AT_LINK; - contents.append(item_contents); - break; - } - case LLAssetType::AT_LINK_FOLDER: - { - LLViewerInventoryCategory *catp = item->getLinkedCategory(); - if (catp && include_folder_links) - { - LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; - LLSD base_contents; - base_contents["name"] = catp->getName(); - base_contents["desc"] = ""; // categories don't have descriptions. - base_contents["linked_id"] = catp->getLinkedUUID(); - base_contents["type"] = LLAssetType::AT_LINK_FOLDER; - contents.append(base_contents); - } - break; - } - default: - { - // Linux refuses to compile unless all possible enums are handled. Really, Linux? - break; - } - } - } - slam_inventory_folder(dst_id, contents, cb); + bool include_folder_links, LLPointer<LLInventoryCallback> cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + LLSD contents = LLSD::emptyArray(); + gInventory.getDirectDescendentsOf(src_id, cats, items); + if (!cats || !items) + { + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + LLViewerInventoryCategory* category = gInventory.getCategory(src_id); + if (category) + { + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; + } + else + { + LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; + } + llassert(cats != NULL && items != NULL); + + return; + } + + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + //getActualDescription() is used for a new description + //to propagate ordering information saved in descriptions of links + LLSD item_contents; + item_contents["name"] = item->getName(); + item_contents["desc"] = item->getActualDescription(); + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + if (catp && include_folder_links) + { + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + LLSD base_contents; + base_contents["name"] = catp->getName(); + base_contents["desc"] = ""; // categories don't have descriptions. + base_contents["linked_id"] = catp->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + break; + } + default: + { + // Linux refuses to compile unless all possible enums are handled. Really, Linux? + break; + } + } + } + slam_inventory_folder(dst_id, contents, cb); } // Copy contents of src_id to dst_id. void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, - LLPointer<LLInventoryCallback> cb) -{ - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(src_id, cats, items); - LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; - LLInventoryObject::const_object_list_t link_array; - for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); - iter != items->end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - switch (item->getActualType()) - { - case LLAssetType::AT_LINK: - { - LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; - link_array.push_back(LLConstPointer<LLInventoryObject>(item)); - break; - } - case LLAssetType::AT_LINK_FOLDER: - { - LLViewerInventoryCategory *catp = item->getLinkedCategory(); - // Skip copying outfit links. - if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) - { - LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; - link_array.push_back(LLConstPointer<LLInventoryObject>(item)); - } - break; - } - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_OBJECT: - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_GESTURE: - { - LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; - copy_inventory_item(gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - dst_id, - item->getName(), - cb); - break; - } - default: - // Ignore non-outfit asset types - break; - } - } - if (!link_array.empty()) - { - link_inventory_array(dst_id, link_array, cb); - } + LLPointer<LLInventoryCallback> cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(src_id, cats, items); + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + LLInventoryObject::const_object_list_t link_array; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer<LLInventoryObject>(item)); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + // Skip copying outfit links. + if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) + { + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer<LLInventoryObject>(item)); + } + break; + } + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_GESTURE: + { + LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + dst_id, + item->getName(), + cb); + break; + } + default: + // Ignore non-outfit asset types + break; + } + } + if (!link_array.empty()) + { + link_inventory_array(dst_id, link_array, cb); + } } BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) { - // These are the wearable items that are required for considering this - // folder as containing a complete outfit. - U32 required_wearables = 0; - required_wearables |= 1LL << LLWearableType::WT_SHAPE; - required_wearables |= 1LL << LLWearableType::WT_SKIN; - required_wearables |= 1LL << LLWearableType::WT_HAIR; - required_wearables |= 1LL << LLWearableType::WT_EYES; - - // These are the wearables that the folder actually contains. - U32 folder_wearables = 0; - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(folder_id, cats, items); - for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); - iter != items->end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - if (item->isWearableType()) - { - const LLWearableType::EType wearable_type = item->getWearableType(); - folder_wearables |= 1LL << wearable_type; - } - } - - // If the folder contains the required wearables, return TRUE. - return ((required_wearables & folder_wearables) == required_wearables); + // These are the wearable items that are required for considering this + // folder as containing a complete outfit. + U32 required_wearables = 0; + required_wearables |= 1LL << LLWearableType::WT_SHAPE; + required_wearables |= 1LL << LLWearableType::WT_SKIN; + required_wearables |= 1LL << LLWearableType::WT_HAIR; + required_wearables |= 1LL << LLWearableType::WT_EYES; + + // These are the wearables that the folder actually contains. + U32 folder_wearables = 0; + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, cats, items); + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + if (item->isWearableType()) + { + const LLWearableType::EType wearable_type = item->getWearableType(); + folder_wearables |= 1LL << wearable_type; + } + } + + // If the folder contains the required wearables, return TRUE. + return ((required_wearables & folder_wearables) == required_wearables); } bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) { - // Disallow removing the base outfit. - if (outfit_cat_id == getBaseOutfitUUID()) - { - return false; - } + // Disallow removing the base outfit. + if (outfit_cat_id == getBaseOutfitUUID()) + { + return false; + } - // Check if the outfit folder itself is removable. - if (!get_is_category_removable(&gInventory, outfit_cat_id)) - { - return false; - } + // Check if the outfit folder itself is removable. + if (!get_is_category_removable(&gInventory, outfit_cat_id)) + { + return false; + } - // Check for the folder's non-removable descendants. - LLFindNonRemovableObjects filter_non_removable; - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); - if (!cats.empty() || !items.empty()) - { - return false; - } + // Check for the folder's non-removable descendants. + LLFindNonRemovableObjects filter_non_removable; + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); + if (!cats.empty() || !items.empty()) + { + return false; + } - return true; + return true; } // static bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_worn); + return items.size() > 0; } // static bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) { - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + not_worn); - return items.size() > 0; + return items.size() > 0; } bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) { - // Don't allow wearing anything while we're changing appearance. - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } + // Don't allow wearing anything while we're changing appearance. + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } - // Check whether it's the base outfit. - if (outfit_cat_id.isNull()) - { - return false; - } + // Check whether it's the base outfit. + if (outfit_cat_id.isNull()) + { + return false; + } - // Check whether the outfit contains any wearables - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); + // Check whether the outfit contains any wearables + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable); - return items.size() > 0; + return items.size() > 0; } // Moved from LLWearableList::ContextMenu for wider utility. bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const { - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - U32 n_objects = 0; - U32 n_clothes = 0; - - // Count given clothes (by wearable type) and objects. - for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - const LLViewerInventoryItem* item = gInventory.getItem(*it); - if (!item) - { - return false; - } - - if (item->getType() == LLAssetType::AT_OBJECT) - { - ++n_objects; - } - else if (item->getType() == LLAssetType::AT_CLOTHING) - { - ++n_clothes; - } - else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE) - { - return isAgentAvatarValid(); - } - else - { - LL_WARNS() << "Unexpected wearable type" << LL_ENDL; - return false; - } - } - - // Check whether we can add all the objects. - if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects)) - { - return false; - } - - // Check whether we can add all the clothes. + // TODO: investigate wearables may not be loaded at this point EXT-8231 + + U32 n_objects = 0; + U32 n_clothes = 0; + + // Count given clothes (by wearable type) and objects. + for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) + { + const LLViewerInventoryItem* item = gInventory.getItem(*it); + if (!item) + { + return false; + } + + if (item->getType() == LLAssetType::AT_OBJECT) + { + ++n_objects; + } + else if (item->getType() == LLAssetType::AT_CLOTHING) + { + ++n_clothes; + } + else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE) + { + return isAgentAvatarValid(); + } + else + { + LL_WARNS() << "Unexpected wearable type" << LL_ENDL; + return false; + } + } + + // Check whether we can add all the objects. + if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects)) + { + return false; + } + + // Check whether we can add all the clothes. U32 sum_clothes = n_clothes + gAgentWearables.getClothingLayerCount(); return sum_clothes <= LLAgentWearables::MAX_CLOTHING_LAYERS; } void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(category, cats, items, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i = 0; i < items.size(); ++i) - { - LLViewerInventoryItem *item = items.at(i); - if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) - continue; - LLViewerInventoryCategory* catp = item->getLinkedCategory(); - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - remove_inventory_item(item->getUUID(), cb); - } - } + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.size(); ++i) + { + LLViewerInventoryItem *item = items.at(i); + if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) + continue; + LLViewerInventoryCategory* catp = item->getLinkedCategory(); + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + remove_inventory_item(item->getUUID(), cb); + } + } } // Keep the last N wearables of each type. For viewer 2.0, N is 1 for // both body parts and clothing items. void LLAppearanceMgr::filterWearableItems( - LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total) + LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total) { // Restrict by max total items first. if ((max_total > 0) && (items.size() > max_total)) @@ -2134,348 +2134,348 @@ void LLAppearanceMgr::filterWearableItems( void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { - LLViewerInventoryCategory *pcat = gInventory.getCategory(category); - if (!pcat) - { - LL_WARNS() << "no category found for id " << category << LL_ENDL; - return; - } - LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; - - const LLUUID cof = getCOF(); - - // Deactivate currently active gestures in the COF, if replacing outfit - if (!append) - { - LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); - for(S32 i = 0; i < gest_items.size(); ++i) - { - LLViewerInventoryItem *gest_item = gest_items.at(i); - if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) - { - LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); - } - } - } - - // Collect and filter descendents to determine new COF contents. - - // - Body parts: always include COF contents as a fallback in case any - // required parts are missing. - // Preserve body parts from COF if appending. - LLInventoryModel::item_array_t body_items; - getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); - if (append) - reverse(body_items.begin(), body_items.end()); - // Reduce body items to max of one per type. - removeDuplicateItems(body_items); - filterWearableItems(body_items, 1, 0); - - // - Wearables: include COF contents only if appending. - LLInventoryModel::item_array_t wear_items; - if (append) - getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); - // Reduce wearables to max of one per type. - removeDuplicateItems(wear_items); - filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); - - // - Attachments: include COF contents only if appending. - LLInventoryModel::item_array_t obj_items; - if (append) - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); - removeDuplicateItems(obj_items); - - // - Gestures: include COF contents only if appending. - LLInventoryModel::item_array_t gest_items; - if (append) - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); - removeDuplicateItems(gest_items); - - // Create links to new COF contents. - LLInventoryModel::item_array_t all_items; - std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items)); - std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items)); - std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); - std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); - - // Find any wearables that need description set to enforce ordering. - desc_map_t desc_map; - getWearableOrderingDescUpdates(wear_items, desc_map); - - // Will link all the above items. - // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). - LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); - LLSD contents = LLSD::emptyArray(); - - for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); - it != all_items.end(); ++it) - { - LLSD item_contents; - LLInventoryItem *item = *it; - - std::string desc; - desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); - if (desc_iter != desc_map.end()) - { - desc = desc_iter->second; - LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc - << " (was: " << item->getActualDescription() << ")" << LL_ENDL; - } - else - { - desc = item->getActualDescription(); - } - - item_contents["name"] = item->getName(); - item_contents["desc"] = desc; - item_contents["linked_id"] = item->getLinkedUUID(); - item_contents["type"] = LLAssetType::AT_LINK; - contents.append(item_contents); - } - const LLUUID& base_id = append ? getBaseOutfitUUID() : category; - LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); - if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) - { - LLSD base_contents; - base_contents["name"] = base_cat->getName(); - base_contents["desc"] = ""; - base_contents["linked_id"] = base_cat->getLinkedUUID(); - base_contents["type"] = LLAssetType::AT_LINK_FOLDER; - contents.append(base_contents); - } - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) - { - dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); - } - slam_inventory_folder(getCOF(), contents, link_waiter); - - LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; -} + LLViewerInventoryCategory *pcat = gInventory.getCategory(category); + if (!pcat) + { + LL_WARNS() << "no category found for id " << category << LL_ENDL; + return; + } + LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; -void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) -{ - LLSidepanelAppearance* panel_appearance = - dynamic_cast<LLSidepanelAppearance *>(LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel_appearance) - { - panel_appearance->refreshCurrentOutfitName(name); - } -} + const LLUUID cof = getCOF(); + + // Deactivate currently active gestures in the COF, if replacing outfit + if (!append) + { + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + for(S32 i = 0; i < gest_items.size(); ++i) + { + LLViewerInventoryItem *gest_item = gest_items.at(i); + if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) + { + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); + } + } + } + + // Collect and filter descendents to determine new COF contents. + + // - Body parts: always include COF contents as a fallback in case any + // required parts are missing. + // Preserve body parts from COF if appending. + LLInventoryModel::item_array_t body_items; + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); + if (append) + reverse(body_items.begin(), body_items.end()); + // Reduce body items to max of one per type. + removeDuplicateItems(body_items); + filterWearableItems(body_items, 1, 0); + + // - Wearables: include COF contents only if appending. + LLInventoryModel::item_array_t wear_items; + if (append) + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); + // Reduce wearables to max of one per type. + removeDuplicateItems(wear_items); + filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); + + // - Attachments: include COF contents only if appending. + LLInventoryModel::item_array_t obj_items; + if (append) + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); + removeDuplicateItems(obj_items); + + // - Gestures: include COF contents only if appending. + LLInventoryModel::item_array_t gest_items; + if (append) + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); + removeDuplicateItems(gest_items); + + // Create links to new COF contents. + LLInventoryModel::item_array_t all_items; + std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items)); + std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items)); + std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); + std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); + + // Find any wearables that need description set to enforce ordering. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + // Will link all the above items. + // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); + LLSD contents = LLSD::emptyArray(); + + for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); + it != all_items.end(); ++it) + { + LLSD item_contents; + LLInventoryItem *item = *it; + + std::string desc; + desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); + if (desc_iter != desc_map.end()) + { + desc = desc_iter->second; + LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + } + else + { + desc = item->getActualDescription(); + } + + item_contents["name"] = item->getName(); + item_contents["desc"] = desc; + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + } + const LLUUID& base_id = append ? getBaseOutfitUUID() : category; + LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); + if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) + { + LLSD base_contents; + base_contents["name"] = base_cat->getName(); + base_contents["desc"] = ""; + base_contents["linked_id"] = base_cat->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); + } + slam_inventory_folder(getCOF(), contents, link_waiter); + + LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; +} + +void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) +{ + LLSidepanelAppearance* panel_appearance = + dynamic_cast<LLSidepanelAppearance *>(LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel_appearance) + { + panel_appearance->refreshCurrentOutfitName(name); + } +} void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter) { - const LLUUID cof = getCOF(); - LLViewerInventoryCategory* catp = gInventory.getCategory(category); - std::string new_outfit_name = ""; + const LLUUID cof = getCOF(); + LLViewerInventoryCategory* catp = gInventory.getCategory(category); + std::string new_outfit_name = ""; - purgeBaseOutfitLink(cof, link_waiter); + purgeBaseOutfitLink(cof, link_waiter); + + if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + link_inventory_object(cof, catp, link_waiter); + new_outfit_name = catp->getName(); + } - if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - link_inventory_object(cof, catp, link_waiter); - new_outfit_name = catp->getName(); - } - - updatePanelOutfitName(new_outfit_name); + updatePanelOutfitName(new_outfit_name); } void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) { - LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; - LLInventoryItem::item_array_t items; - std::vector< LLViewerWearable* > wearables; - wearables.reserve(32); - - // For each wearable type, find the wearables of that type. - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) - { - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); - iter != holder->getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - LLViewerWearable* wearable = data.mWearable; - if( wearable && ((S32)wearable->getType() == i) ) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); - if( item && (item->getAssetUUID() == wearable->getAssetID()) ) - { - items.push_back(item); - wearables.push_back(wearable); - } - } - } - } - - if(wearables.size() > 0) - { - gAgentWearables.setWearableOutfit(items, wearables); - } + LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; + LLInventoryItem::item_array_t items; + std::vector< LLViewerWearable* > wearables; + wearables.reserve(32); + + // For each wearable type, find the wearables of that type. + for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + { + for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); + iter != holder->getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + LLViewerWearable* wearable = data.mWearable; + if( wearable && ((S32)wearable->getType() == i) ) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); + if( item && (item->getAssetUUID() == wearable->getAssetID()) ) + { + items.push_back(item); + wearables.push_back(wearable); + } + } + } + } + + if(wearables.size() > 0) + { + gAgentWearables.setWearableOutfit(items, wearables); + } } S32 LLAppearanceMgr::countActiveHoldingPatterns() { - return LLWearableHoldingPattern::countActive(); + return LLWearableHoldingPattern::countActive(); } static void remove_non_link_items(LLInventoryModel::item_array_t &items) { - LLInventoryModel::item_array_t pruned_items; - for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); - iter != items.end(); - ++iter) - { - const LLViewerInventoryItem *item = (*iter); - if (item && item->getIsLinkType()) - { - pruned_items.push_back((*iter)); - } - } - items = pruned_items; + LLInventoryModel::item_array_t pruned_items; + for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); + iter != items.end(); + ++iter) + { + const LLViewerInventoryItem *item = (*iter); + if (item && item->getIsLinkType()) + { + pruned_items.push_back((*iter)); + } + } + items = pruned_items; } //a predicate for sorting inventory items by actual descriptions bool sort_by_actual_description(const LLInventoryItem* item1, const LLInventoryItem* item2) { - if (!item1 || !item2) - { - LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; - return true; - } + if (!item1 || !item2) + { + LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; + return true; + } - return item1->getActualDescription() < item2->getActualDescription(); + return item1->getActualDescription() < item2->getActualDescription(); } void item_array_diff(LLInventoryModel::item_array_t& full_list, - LLInventoryModel::item_array_t& keep_list, - LLInventoryModel::item_array_t& kill_list) - -{ - for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); - it != full_list.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end()) - { - kill_list.push_back(item); - } - } + LLInventoryModel::item_array_t& keep_list, + LLInventoryModel::item_array_t& kill_list) + +{ + for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); + it != full_list.end(); + ++it) + { + LLViewerInventoryItem *item = *it; + if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end()) + { + kill_list.push_back(item); + } + } } S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, - LLAssetType::EType type, - S32 max_items_per_type, - S32 max_items_total, - LLInventoryObject::object_list_t& items_to_kill) -{ - S32 to_kill_count = 0; - - LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(cat_id, items, type); - LLInventoryModel::item_array_t curr_items = items; - removeDuplicateItems(items); - if (max_items_per_type > 0 || max_items_total > 0) - { - filterWearableItems(items, max_items_per_type, max_items_total); - } - LLInventoryModel::item_array_t kill_items; - item_array_diff(curr_items,items,kill_items); - for (LLInventoryModel::item_array_t::iterator it = kill_items.begin(); - it != kill_items.end(); - ++it) - { - items_to_kill.push_back(LLPointer<LLInventoryObject>(*it)); - to_kill_count++; - } - return to_kill_count; -} - + LLAssetType::EType type, + S32 max_items_per_type, + S32 max_items_total, + LLInventoryObject::object_list_t& items_to_kill) +{ + S32 to_kill_count = 0; + + LLInventoryModel::item_array_t items; + getDescendentsOfAssetType(cat_id, items, type); + LLInventoryModel::item_array_t curr_items = items; + removeDuplicateItems(items); + if (max_items_per_type > 0 || max_items_total > 0) + { + filterWearableItems(items, max_items_per_type, max_items_total); + } + LLInventoryModel::item_array_t kill_items; + item_array_diff(curr_items,items,kill_items); + for (LLInventoryModel::item_array_t::iterator it = kill_items.begin(); + it != kill_items.end(); + ++it) + { + items_to_kill.push_back(LLPointer<LLInventoryObject>(*it)); + to_kill_count++; + } + return to_kill_count; +} + void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, - LLInventoryObject::object_list_t& items_to_kill) + LLInventoryObject::object_list_t& items_to_kill) { - findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, - 1, 0, items_to_kill); - findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, - 0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill); - findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, - 0, 0, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, + 1, 0, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, + 0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, + 0, 0, items_to_kill); } void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb) { - LLInventoryObject::object_list_t items_to_kill; - findAllExcessOrDuplicateItems(getCOF(), items_to_kill); - if (items_to_kill.size()>0) - { - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - remove_inventory_items(items_to_kill, cb); - } + LLInventoryObject::object_list_t items_to_kill; + findAllExcessOrDuplicateItems(getCOF(), items_to_kill); + if (items_to_kill.size()>0) + { + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + remove_inventory_items(items_to_kill, cb); + } } bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2) { - if (!item1 || !item2) - { - LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL; - return true; - } + if (!item1 || !item2) + { + LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL; + return true; + } - return item1->getLinkedUUID() < item2->getLinkedUUID(); + return item1->getLinkedUUID() < item2->getLinkedUUID(); } void get_sorted_base_and_cof_items(LLInventoryModel::item_array_t& cof_item_array, LLInventoryModel::item_array_t& outfit_item_array) { - LLUUID base_outfit_id = LLAppearanceMgr::instance().getBaseOutfitUUID(); + LLUUID base_outfit_id = LLAppearanceMgr::instance().getBaseOutfitUUID(); - if (base_outfit_id.notNull()) - { - LLIsValidItemLink collector; - LLInventoryModel::cat_array_t sub_cat_array; + if (base_outfit_id.notNull()) + { + LLIsValidItemLink collector; + LLInventoryModel::cat_array_t sub_cat_array; - gInventory.collectDescendents(base_outfit_id, - sub_cat_array, - outfit_item_array, - LLInventoryModel::EXCLUDE_TRASH); + gInventory.collectDescendents(base_outfit_id, + sub_cat_array, + outfit_item_array, + LLInventoryModel::EXCLUDE_TRASH); - LLInventoryModel::cat_array_t cof_cats; + LLInventoryModel::cat_array_t cof_cats; - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cof_cats, cof_item_array, - LLInventoryModel::EXCLUDE_TRASH, collector); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cof_cats, cof_item_array, + LLInventoryModel::EXCLUDE_TRASH, collector); - for (U32 i = 0; i < outfit_item_array.size(); ++i) - { - LLViewerInventoryItem* linked_item = outfit_item_array.at(i)->getLinkedItem(); - if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) - { - outfit_item_array.erase(outfit_item_array.begin() + i); - break; - } - } + for (U32 i = 0; i < outfit_item_array.size(); ++i) + { + LLViewerInventoryItem* linked_item = outfit_item_array.at(i)->getLinkedItem(); + if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + outfit_item_array.erase(outfit_item_array.begin() + i); + break; + } + } - std::sort(cof_item_array.begin(), cof_item_array.end(), sort_by_linked_uuid); - std::sort(outfit_item_array.begin(), outfit_item_array.end(), sort_by_linked_uuid); - } + std::sort(cof_item_array.begin(), cof_item_array.end(), sort_by_linked_uuid); + std::sort(outfit_item_array.begin(), outfit_item_array.end(), sort_by_linked_uuid); + } } void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, - bool enforce_ordering, - nullary_func_t post_update_func) + bool enforce_ordering, + nullary_func_t post_update_func) { - if (mIsInUpdateAppearanceFromCOF) - { - LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL; - return; - } + if (mIsInUpdateAppearanceFromCOF) + { + LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL; + return; + } - LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; if (gInventory.hasPosiblyBrockenLinks()) { @@ -2510,263 +2510,263 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, } } - if (enforce_item_restrictions) - { - // The point here is just to call - // updateAppearanceFromCOF() again after excess items - // have been removed. That time we will set - // enforce_item_restrictions to false so we don't get - // caught in a perpetual loop. - LLPointer<LLInventoryCallback> cb( - new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); - enforceCOFItemRestrictions(cb); - return; - } - - if (enforce_ordering) - { - //checking integrity of the COF in terms of ordering of wearables, - //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - - // As with enforce_item_restrictions handling above, we want - // to wait for the update callbacks, then (finally!) call - // updateAppearanceFromCOF() with no additional COF munging needed. - LLPointer<LLInventoryCallback> cb( - new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); - updateClothingOrderingInfo(LLUUID::null, cb); - return; - } - - if (!validateClothingOrderingInfo()) - { - - LLInventoryModel::item_array_t outfit_item_array; - LLInventoryModel::item_array_t cof_item_array; - get_sorted_base_and_cof_items(cof_item_array, outfit_item_array); - - if (outfit_item_array.size() == cof_item_array.size()) - { - for (U32 i = 0; i < cof_item_array.size(); ++i) - { - LLViewerInventoryItem *cof_it = cof_item_array.at(i); - LLViewerInventoryItem *base_it = outfit_item_array.at(i); - - if (cof_it->getActualDescription() != base_it->getActualDescription()) - { - if (cof_it->getLinkedUUID() == base_it->getLinkedUUID()) - { - cof_it->setDescription(base_it->getActualDescription()); - gInventory.updateItem(cof_it); - } - } - } - LLAppearanceMgr::getInstance()->updateIsDirty(); - } - - } - - BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - selfStartPhase("update_appearance_from_cof"); - - // update dirty flag to see if the state of the COF matches - // the saved outfit stored as a folder link - updateIsDirty(); - - // Send server request for appearance update - if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) - { - requestServerAppearanceUpdate(); - } - - LLUUID current_outfit_id = getCOF(); - - // Find all the wearables that are in the COF's subtree. - LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL; - LLInventoryModel::item_array_t wear_items; - LLInventoryModel::item_array_t obj_items; - LLInventoryModel::item_array_t gest_items; - getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); - // Get rid of non-links in case somehow the COF was corrupted. - remove_non_link_items(wear_items); - remove_non_link_items(obj_items); - remove_non_link_items(gest_items); - - dumpItemArray(wear_items,"asset_dump: wear_item"); - dumpItemArray(obj_items,"asset_dump: obj_item"); - - LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); - if (!gInventory.isCategoryComplete(current_outfit_id)) - { - LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() - << " descendent_count " << cof->getDescendentCount() - << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; - } - if(!wear_items.size()) - { - LLNotificationsUtil::add("CouldNotPutOnOutfit"); - return; - } - - //preparing the list of wearables in the correct order for LLAgentWearables - sortItemsByActualDescription(wear_items); - - - LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; - LLTimer hp_block_timer; - LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; - - holder->setObjItems(obj_items); - holder->setGestItems(gest_items); - - // Note: can't do normal iteration, because if all the - // wearables can be resolved immediately, then the - // callback will be called (and this object deleted) - // before the final getNextData(). - - for(S32 i = 0; i < wear_items.size(); ++i) - { - LLViewerInventoryItem *item = wear_items.at(i); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - - // Fault injection: use debug setting to test asset - // fetch failures (should be replaced by new defaults in - // lost&found). - U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); - - if (item && item->getIsLinkType() && linked_item) - { - LLFoundData found(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID - ); - - if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) - { - found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB - } - //pushing back, not front, to preserve order of wearables for LLAgentWearables - holder->getFoundList().push_back(found); - } - else - { - if (!item) - { - LL_WARNS() << "Attempt to wear a null item " << LL_ENDL; - } - else if (!linked_item) - { - LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL; - } - } - } - - selfStartPhase("get_wearables_2"); - - for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); - it != holder->getFoundList().end(); ++it) - { - LLFoundData& found = *it; - - LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL; - - // Fetch the wearables about to be worn. - LLWearableList::instance().getAsset(found.mAssetID, - found.mName, - gAgentAvatarp, - found.mAssetType, - onWearableAssetFetch, - (void*)holder); - - } - - holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); - if (!holder->pollFetchCompletion()) - { - doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); - } - post_update_func(); - - LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; + if (enforce_item_restrictions) + { + // The point here is just to call + // updateAppearanceFromCOF() again after excess items + // have been removed. That time we will set + // enforce_item_restrictions to false so we don't get + // caught in a perpetual loop. + LLPointer<LLInventoryCallback> cb( + new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); + enforceCOFItemRestrictions(cb); + return; + } + + if (enforce_ordering) + { + //checking integrity of the COF in terms of ordering of wearables, + //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) + + // As with enforce_item_restrictions handling above, we want + // to wait for the update callbacks, then (finally!) call + // updateAppearanceFromCOF() with no additional COF munging needed. + LLPointer<LLInventoryCallback> cb( + new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); + updateClothingOrderingInfo(LLUUID::null, cb); + return; + } + + if (!validateClothingOrderingInfo()) + { + + LLInventoryModel::item_array_t outfit_item_array; + LLInventoryModel::item_array_t cof_item_array; + get_sorted_base_and_cof_items(cof_item_array, outfit_item_array); + + if (outfit_item_array.size() == cof_item_array.size()) + { + for (U32 i = 0; i < cof_item_array.size(); ++i) + { + LLViewerInventoryItem *cof_it = cof_item_array.at(i); + LLViewerInventoryItem *base_it = outfit_item_array.at(i); + + if (cof_it->getActualDescription() != base_it->getActualDescription()) + { + if (cof_it->getLinkedUUID() == base_it->getLinkedUUID()) + { + cof_it->setDescription(base_it->getActualDescription()); + gInventory.updateItem(cof_it); + } + } + } + LLAppearanceMgr::getInstance()->updateIsDirty(); + } + + } + + BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); + selfStartPhase("update_appearance_from_cof"); + + // update dirty flag to see if the state of the COF matches + // the saved outfit stored as a folder link + updateIsDirty(); + + // Send server request for appearance update + if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) + { + requestServerAppearanceUpdate(); + } + + LLUUID current_outfit_id = getCOF(); + + // Find all the wearables that are in the COF's subtree. + LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL; + LLInventoryModel::item_array_t wear_items; + LLInventoryModel::item_array_t obj_items; + LLInventoryModel::item_array_t gest_items; + getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); + // Get rid of non-links in case somehow the COF was corrupted. + remove_non_link_items(wear_items); + remove_non_link_items(obj_items); + remove_non_link_items(gest_items); + + dumpItemArray(wear_items,"asset_dump: wear_item"); + dumpItemArray(obj_items,"asset_dump: obj_item"); + + LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); + if (!gInventory.isCategoryComplete(current_outfit_id)) + { + LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() + << " descendent_count " << cof->getDescendentCount() + << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; + } + if(!wear_items.size()) + { + LLNotificationsUtil::add("CouldNotPutOnOutfit"); + return; + } + + //preparing the list of wearables in the correct order for LLAgentWearables + sortItemsByActualDescription(wear_items); + + + LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; + LLTimer hp_block_timer; + LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; + + holder->setObjItems(obj_items); + holder->setGestItems(gest_items); + + // Note: can't do normal iteration, because if all the + // wearables can be resolved immediately, then the + // callback will be called (and this object deleted) + // before the final getNextData(). + + for(S32 i = 0; i < wear_items.size(); ++i) + { + LLViewerInventoryItem *item = wear_items.at(i); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + + // Fault injection: use debug setting to test asset + // fetch failures (should be replaced by new defaults in + // lost&found). + U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); + + if (item && item->getIsLinkType() && linked_item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID + ); + + if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } + //pushing back, not front, to preserve order of wearables for LLAgentWearables + holder->getFoundList().push_back(found); + } + else + { + if (!item) + { + LL_WARNS() << "Attempt to wear a null item " << LL_ENDL; + } + else if (!linked_item) + { + LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL; + } + } + } + + selfStartPhase("get_wearables_2"); + + for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); + it != holder->getFoundList().end(); ++it) + { + LLFoundData& found = *it; + + LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL; + + // Fetch the wearables about to be worn. + LLWearableList::instance().getAsset(found.mAssetID, + found.mName, + gAgentAvatarp, + found.mAssetType, + onWearableAssetFetch, + (void*)holder); + + } + + holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); + if (!holder->pollFetchCompletion()) + { + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); + } + post_update_func(); + + LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; } void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, - LLInventoryModel::item_array_t& items, - LLAssetType::EType type) -{ - LLInventoryModel::cat_array_t cats; - LLIsType is_of_type(type); - gInventory.collectDescendentsIf(category, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_of_type); -} - -void LLAppearanceMgr::getUserDescendents(const LLUUID& category, - LLInventoryModel::item_array_t& wear_items, - LLInventoryModel::item_array_t& obj_items, - LLInventoryModel::item_array_t& gest_items) -{ - LLInventoryModel::cat_array_t wear_cats; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(category, - wear_cats, - wear_items, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); - - LLInventoryModel::cat_array_t obj_cats; - LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(category, - obj_cats, - obj_items, - LLInventoryModel::EXCLUDE_TRASH, - is_object); - - // Find all gestures in this folder - LLInventoryModel::cat_array_t gest_cats; - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(category, - gest_cats, - gest_items, - LLInventoryModel::EXCLUDE_TRASH, - is_gesture); + LLInventoryModel::item_array_t& items, + LLAssetType::EType type) +{ + LLInventoryModel::cat_array_t cats; + LLIsType is_of_type(type); + gInventory.collectDescendentsIf(category, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_of_type); +} + +void LLAppearanceMgr::getUserDescendents(const LLUUID& category, + LLInventoryModel::item_array_t& wear_items, + LLInventoryModel::item_array_t& obj_items, + LLInventoryModel::item_array_t& gest_items) +{ + LLInventoryModel::cat_array_t wear_cats; + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(category, + wear_cats, + wear_items, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable); + + LLInventoryModel::cat_array_t obj_cats; + LLIsType is_object( LLAssetType::AT_OBJECT ); + gInventory.collectDescendentsIf(category, + obj_cats, + obj_items, + LLInventoryModel::EXCLUDE_TRASH, + is_object); + + // Find all gestures in this folder + LLInventoryModel::cat_array_t gest_cats; + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + gInventory.collectDescendentsIf(category, + gest_cats, + gest_items, + LLInventoryModel::EXCLUDE_TRASH, + is_gesture); } void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) { - if(!category) return; + if(!category) return; - selfClearPhases(); - selfStartPhase("wear_inventory_category"); + selfClearPhases(); + selfStartPhase("wear_inventory_category"); - gAgentWearables.notifyLoadingStarted(); + gAgentWearables.notifyLoadingStarted(); - LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() - << " )" << LL_ENDL; + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() + << " )" << LL_ENDL; - // If we are copying from library, attempt to use AIS to copy the category. + // If we are copying from library, attempt to use AIS to copy the category. if (copy && AISAPI::isAvailable()) - { - LLUUID parent_id; - parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - if (parent_id.isNull()) - { - parent_id = gInventory.getRootFolderID(); - } - - LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append); - LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper( - std::string("wear_inventory_category_callback"), copy_cb); + { + LLUUID parent_id; + parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + if (parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + + LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append); + LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper( + std::string("wear_inventory_category_callback"), copy_cb); AISAPI::completion_t cr = boost::bind(&doAppearanceCb, track_cb, _1); AISAPI::CopyLibraryCategory(category->getUUID(), parent_id, false, cr); - } + } else - { - selfStartPhase("wear_inventory_category_fetch"); + { + selfStartPhase("wear_inventory_category_fetch"); if (AISAPI::isAvailable() && category->getPreferredType() == LLFolderType::FT_OUTFIT) { // for reliability just fetch it whole, linked items included @@ -2784,66 +2784,66 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool &LLAppearanceMgr::instance(), category->getUUID(), copy, append)); } - } + } } S32 LLAppearanceMgr::getActiveCopyOperations() const { - return LLCallAfterInventoryCopyMgr::getInstanceCount(); + return LLCallAfterInventoryCopyMgr::getInstanceCount(); } void LLAppearanceMgr::wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append) { - LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; - - selfStopPhase("wear_inventory_category_fetch"); - - // We now have an outfit ready to be copied to agent inventory. Do - // it, and wear that outfit normally. - LLInventoryCategory* cat = gInventory.getCategory(cat_id); - if(copy_items) - { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(cat_id, cats, items); - std::string name; - if(!cat) - { - // should never happen. - name = "New Outfit"; - } - else - { - name = cat->getName(); - } - LLViewerInventoryItem* item = NULL; - LLInventoryModel::item_array_t::const_iterator it = items->begin(); - LLInventoryModel::item_array_t::const_iterator end = items->end(); - LLUUID pid; - for(; it < end; ++it) - { - item = *it; - if(item) - { - if(LLInventoryType::IT_GESTURE == item->getInventoryType()) - { - pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); - } - else - { - pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - } - break; - } - } - if(pid.isNull()) - { - pid = gInventory.getRootFolderID(); - } - - gInventory.createNewCategory( - pid, - LLFolderType::FT_NONE, + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; + + selfStopPhase("wear_inventory_category_fetch"); + + // We now have an outfit ready to be copied to agent inventory. Do + // it, and wear that outfit normally. + LLInventoryCategory* cat = gInventory.getCategory(cat_id); + if(copy_items) + { + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + std::string name; + if(!cat) + { + // should never happen. + name = "New Outfit"; + } + else + { + name = cat->getName(); + } + LLViewerInventoryItem* item = NULL; + LLInventoryModel::item_array_t::const_iterator it = items->begin(); + LLInventoryModel::item_array_t::const_iterator end = items->end(); + LLUUID pid; + for(; it < end; ++it) + { + item = *it; + if(item) + { + if(LLInventoryType::IT_GESTURE == item->getInventoryType()) + { + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + } + else + { + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + } + break; + } + } + if(pid.isNull()) + { + pid = gInventory.getRootFolderID(); + } + + gInventory.createNewCategory( + pid, + LLFolderType::FT_NONE, name, [cat_id, append](const LLUUID& new_cat_id) { @@ -2863,205 +2863,205 @@ void LLAppearanceMgr::wearCategoryFinal(const LLUUID& cat_id, bool copy_items, b }, cat->getThumbnailUUID() ); - } - else - { - // Wear the inventory category. - LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append); - } + } + else + { + // Wear the inventory category. + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append); + } } // *NOTE: hack to get from avatar inventory to avatar void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append ) { - // Avoid unintentionally overwriting old wearables. We have to do - // this up front to avoid having to deal with the case of multiple - // wearables being dirty. - if (!category) return; + // Avoid unintentionally overwriting old wearables. We have to do + // this up front to avoid having to deal with the case of multiple + // wearables being dirty. + if (!category) return; - if ( !LLInventoryCallbackManager::is_instantiated() ) - { - // shutting down, ignore. - return; - } + if ( !LLInventoryCallbackManager::is_instantiated() ) + { + // shutting down, ignore. + return; + } - LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() - << "'" << LL_ENDL; - LLUIUsage::instance().logCommand("Avatar.WearCategory"); - - if (gAgentCamera.cameraCustomizeAvatar()) - { - // switching to outfit editor should automagically save any currently edited wearable - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); - } + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() + << "'" << LL_ENDL; + LLUIUsage::instance().logCommand("Avatar.WearCategory"); + + if (gAgentCamera.cameraCustomizeAvatar()) + { + // switching to outfit editor should automagically save any currently edited wearable + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); + } - LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); + LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } // FIXME do we really want to search entire inventory for matching name? void LLAppearanceMgr::wearOutfitByName(const std::string& name) { - LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(name); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - bool copy_items = false; - LLInventoryCategory* cat = NULL; - if (cat_array.size() > 0) - { - // Just wear the first one that matches - cat = cat_array.at(0); - } - else - { - gInventory.collectDescendentsIf(LLUUID::null, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - if(cat_array.size() > 0) - { - cat = cat_array.at(0); - copy_items = true; - } - } - - if(cat) - { - LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); - } - else - { - LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()" - << LL_ENDL; - } + LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLNameCategoryCollector has_name(name); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + bool copy_items = false; + LLInventoryCategory* cat = NULL; + if (cat_array.size() > 0) + { + // Just wear the first one that matches + cat = cat_array.at(0); + } + else + { + gInventory.collectDescendentsIf(LLUUID::null, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + if(cat_array.size() > 0) + { + cat = cat_array.at(0); + copy_items = true; + } + } + + if(cat) + { + LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); + } + else + { + LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()" + << LL_ENDL; + } } bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b) { - return (a->isWearableType() && b->isWearableType() && - (a->getWearableType() == b->getWearableType())); + return (a->isWearableType() && b->isWearableType() && + (a->getWearableType() == b->getWearableType())); } class LLDeferredCOFLinkObserver: public LLInventoryObserver { public: - LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description): - mItemID(item_id), - mCallback(cb), - mDescription(description) - { - } - - ~LLDeferredCOFLinkObserver() - { - } - - /* virtual */ void changed(U32 mask) - { - const LLInventoryItem *item = gInventory.getItem(mItemID); - if (item) - { - gInventory.removeObserver(this); - LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); - delete this; - } - } + LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description): + mItemID(item_id), + mCallback(cb), + mDescription(description) + { + } + + ~LLDeferredCOFLinkObserver() + { + } + + /* virtual */ void changed(U32 mask) + { + const LLInventoryItem *item = gInventory.getItem(mItemID); + if (item) + { + gInventory.removeObserver(this); + LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); + delete this; + } + } private: - const LLUUID mItemID; - std::string mDescription; - LLPointer<LLInventoryCallback> mCallback; + const LLUUID mItemID; + std::string mDescription; + LLPointer<LLInventoryCallback> mCallback; }; // BAP - note that this runs asynchronously if the item is not already loaded from inventory. // Dangerous if caller assumes link will exist after calling the function. void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, - LLPointer<LLInventoryCallback> cb, - const std::string description) + LLPointer<LLInventoryCallback> cb, + const std::string description) { - const LLInventoryItem *item = gInventory.getItem(item_id); - if (!item) - { - LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); - gInventory.addObserver(observer); - } - else - { - addCOFItemLink(item, cb, description); - } + const LLInventoryItem *item = gInventory.getItem(item_id); + if (!item) + { + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); + gInventory.addObserver(observer); + } + else + { + addCOFItemLink(item, cb, description); + } } void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, - LLPointer<LLInventoryCallback> cb, - const std::string description) -{ - const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item); - if (!vitem) - { - LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL; - return; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID()); - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::getCOF(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - bool linked_already = false; - for (S32 i=0; i<item_array.size(); i++) - { - // Are these links to the same object? - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - const LLWearableType::EType wearable_type = inv_item->getWearableType(); - - const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) - || (wearable_type == LLWearableType::WT_HAIR) - || (wearable_type == LLWearableType::WT_EYES) - || (wearable_type == LLWearableType::WT_SKIN); - - if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) - { - linked_already = true; - } - // Are these links to different items of the same body part - // type? If so, new item will replace old. - else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) - { - if (is_body_part && inv_item->getIsLinkType()) - { - remove_inventory_item(inv_item->getUUID(), cb); - } - else if (!gAgentWearables.canAddWearable(wearable_type)) - { - // MULTI-WEARABLES: make sure we don't go over clothing limits - remove_inventory_item(inv_item->getUUID(), cb); - } - } - } - - if (!linked_already) - { - LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; - copy_item->copyViewerItem(vitem); - copy_item->setDescription(description); - link_inventory_object(getCOF(), copy_item, cb); - } + LLPointer<LLInventoryCallback> cb, + const std::string description) +{ + const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item); + if (!vitem) + { + LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL; + return; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID()); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + bool linked_already = false; + for (S32 i=0; i<item_array.size(); i++) + { + // Are these links to the same object? + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + const LLWearableType::EType wearable_type = inv_item->getWearableType(); + + const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) + || (wearable_type == LLWearableType::WT_HAIR) + || (wearable_type == LLWearableType::WT_EYES) + || (wearable_type == LLWearableType::WT_SKIN); + + if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) + { + linked_already = true; + } + // Are these links to different items of the same body part + // type? If so, new item will replace old. + else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) + { + if (is_body_part && inv_item->getIsLinkType()) + { + remove_inventory_item(inv_item->getUUID(), cb); + } + else if (!gAgentWearables.canAddWearable(wearable_type)) + { + // MULTI-WEARABLES: make sure we don't go over clothing limits + remove_inventory_item(inv_item->getUUID(), cb); + } + } + } + + if (!linked_already) + { + LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; + copy_item->copyViewerItem(vitem); + copy_item->setDescription(description); + link_inventory_object(getCOF(), copy_item, cb); + } } LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) { - LLInventoryModel::item_array_t result; + LLInventoryModel::item_array_t result; LLUUID linked_id = gInventory.getLinkedItemID(item_id); LLInventoryModel::cat_array_t cat_array; @@ -3072,238 +3072,238 @@ LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& i LLInventoryModel::EXCLUDE_TRASH); for (S32 i=0; i<item_array.size(); i++) { - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - if (inv_item->getLinkedUUID() == linked_id) + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + if (inv_item->getLinkedUUID() == linked_id) + { + result.push_back(item_array.at(i)); + } + } + return result; +} + +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +{ + LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); + return links.size() > 0; +} + +void LLAppearanceMgr::removeAllClothesFromAvatar() +{ + // Fetch worn clothes (i.e. the ones in COF). + LLInventoryModel::item_array_t clothing_items; + LLInventoryModel::cat_array_t dummy; + LLIsType is_clothing(LLAssetType::AT_CLOTHING); + gInventory.collectDescendentsIf(getCOF(), + dummy, + clothing_items, + LLInventoryModel::EXCLUDE_TRASH, + is_clothing); + uuid_vec_t item_ids; + for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); + it != clothing_items.end(); ++it) + { + item_ids.push_back((*it).get()->getLinkedUUID()); + } + + // Take them off by removing from COF. + removeItemsFromAvatar(item_ids); +} + +void LLAppearanceMgr::removeAllAttachmentsFromAvatar() +{ + if (!isAgentAvatarValid()) return; + + LLAgentWearables::llvo_vec_t objects_to_remove; + + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end();) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = attachment_iter->get(); + if (attached_object) + { + objects_to_remove.push_back(attached_object); + } + } + } + uuid_vec_t ids_to_remove; + for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_remove.begin(); + it != objects_to_remove.end(); + ++it) + { + ids_to_remove.push_back((*it)->getAttachmentItemID()); + } + removeItemsFromAvatar(ids_to_remove); +} + +class LLUpdateOnCOFLinkRemove : public LLInventoryCallback +{ +public: + LLUpdateOnCOFLinkRemove(const LLUUID& remove_item_id, LLPointer<LLInventoryCallback> cb = NULL): + mItemID(remove_item_id), + mCB(cb) + { + } + + /* virtual */ void fire(const LLUUID& item_id) + { + // just removed cof link, "(wear)" suffix depends on presence of link, so update label + gInventory.addChangedMask(LLInventoryObserver::LABEL, mItemID); + if (mCB.notNull()) + { + mCB->fire(item_id); + } + } + +private: + LLUUID mItemID; + LLPointer<LLInventoryCallback> mCB; +}; + +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) +{ LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; i<item_array.size(); i++) + { + const LLInventoryItem* item = item_array.at(i).get(); + if (item->getIsLinkType() && item->getLinkedUUID() == item_id) + { + if (item->getType() == LLAssetType::AT_OBJECT) + { + // Immediate delete + remove_inventory_item(item->getUUID(), cb, true); + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + } + else + { + // Delayed delete + // Pointless to update item_id label here since link still exists and first notifyObservers + // call will restore (wear) suffix, mark for update after deletion + LLPointer<LLUpdateOnCOFLinkRemove> cb_label = new LLUpdateOnCOFLinkRemove(item_id, cb); + remove_inventory_item(item->getUUID(), cb_label, false); + } + } + } +} + +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb) +{ + LLFindWearablesOfType filter_wearables_of_type(type); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryModel::item_array_t::const_iterator it; + + gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); + for (it = items.begin(); it != items.end(); ++it) + { + const LLViewerInventoryItem* item = *it; + if (item->getIsLinkType()) // we must operate on links only { - result.push_back(item_array.at(i)); + remove_inventory_item(item->getUUID(), cb); } } - return result; } -bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +void LLAppearanceMgr::updateIsDirty() { - LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); - return links.size() > 0; -} + LLUUID cof = getCOF(); + LLUUID base_outfit; -void LLAppearanceMgr::removeAllClothesFromAvatar() -{ - // Fetch worn clothes (i.e. the ones in COF). - LLInventoryModel::item_array_t clothing_items; - LLInventoryModel::cat_array_t dummy; - LLIsType is_clothing(LLAssetType::AT_CLOTHING); - gInventory.collectDescendentsIf(getCOF(), - dummy, - clothing_items, - LLInventoryModel::EXCLUDE_TRASH, - is_clothing); - uuid_vec_t item_ids; - for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); - it != clothing_items.end(); ++it) - { - item_ids.push_back((*it).get()->getLinkedUUID()); - } - - // Take them off by removing from COF. - removeItemsFromAvatar(item_ids); -} + // find base outfit link + const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink(); + LLViewerInventoryCategory* catp = NULL; + if (base_outfit_item && base_outfit_item->getIsLinkType()) + { + catp = base_outfit_item->getLinkedCategory(); + } + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + base_outfit = catp->getUUID(); + } -void LLAppearanceMgr::removeAllAttachmentsFromAvatar() -{ - if (!isAgentAvatarValid()) return; - - LLAgentWearables::llvo_vec_t objects_to_remove; - - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end();) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = attachment_iter->get(); - if (attached_object) - { - objects_to_remove.push_back(attached_object); - } - } - } - uuid_vec_t ids_to_remove; - for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_remove.begin(); - it != objects_to_remove.end(); - ++it) - { - ids_to_remove.push_back((*it)->getAttachmentItemID()); - } - removeItemsFromAvatar(ids_to_remove); -} + // Set dirty to "false" if no base outfit found to disable "Save" + // and leave only "Save As" enabled in My Outfits. + mOutfitIsDirty = false; -class LLUpdateOnCOFLinkRemove : public LLInventoryCallback -{ -public: - LLUpdateOnCOFLinkRemove(const LLUUID& remove_item_id, LLPointer<LLInventoryCallback> cb = NULL): - mItemID(remove_item_id), - mCB(cb) - { - } - - /* virtual */ void fire(const LLUUID& item_id) - { - // just removed cof link, "(wear)" suffix depends on presence of link, so update label - gInventory.addChangedMask(LLInventoryObserver::LABEL, mItemID); - if (mCB.notNull()) - { - mCB->fire(item_id); - } - } + if (base_outfit.notNull()) + { + LLIsValidItemLink collector; -private: - LLUUID mItemID; - LLPointer<LLInventoryCallback> mCB; -}; + LLInventoryModel::cat_array_t cof_cats; + LLInventoryModel::item_array_t cof_items; + gInventory.collectDescendentsIf(cof, cof_cats, cof_items, + LLInventoryModel::EXCLUDE_TRASH, collector); -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) -{ LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::getCOF(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; i<item_array.size(); i++) - { - const LLInventoryItem* item = item_array.at(i).get(); - if (item->getIsLinkType() && item->getLinkedUUID() == item_id) - { - if (item->getType() == LLAssetType::AT_OBJECT) - { - // Immediate delete - remove_inventory_item(item->getUUID(), cb, true); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - } - else - { - // Delayed delete - // Pointless to update item_id label here since link still exists and first notifyObservers - // call will restore (wear) suffix, mark for update after deletion - LLPointer<LLUpdateOnCOFLinkRemove> cb_label = new LLUpdateOnCOFLinkRemove(item_id, cb); - remove_inventory_item(item->getUUID(), cb_label, false); - } - } - } -} + LLInventoryModel::cat_array_t outfit_cats; + LLInventoryModel::item_array_t outfit_items; + gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, + LLInventoryModel::EXCLUDE_TRASH, collector); -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb) -{ - LLFindWearablesOfType filter_wearables_of_type(type); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryModel::item_array_t::const_iterator it; + for (U32 i = 0; i < outfit_items.size(); ++i) + { + LLViewerInventoryItem* linked_item = outfit_items.at(i)->getLinkedItem(); + if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + outfit_items.erase(outfit_items.begin() + i); + break; + } + } - gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); - for (it = items.begin(); it != items.end(); ++it) - { - const LLViewerInventoryItem* item = *it; - if (item->getIsLinkType()) // we must operate on links only - { - remove_inventory_item(item->getUUID(), cb); - } - } -} + if(outfit_items.size() != cof_items.size()) + { + LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; + // Current outfit folder should have one more item than the outfit folder. + // this one item is the link back to the outfit folder itself. + mOutfitIsDirty = true; + return; + } -void LLAppearanceMgr::updateIsDirty() -{ - LLUUID cof = getCOF(); - LLUUID base_outfit; - - // find base outfit link - const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink(); - LLViewerInventoryCategory* catp = NULL; - if (base_outfit_item && base_outfit_item->getIsLinkType()) - { - catp = base_outfit_item->getLinkedCategory(); - } - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - base_outfit = catp->getUUID(); - } - - // Set dirty to "false" if no base outfit found to disable "Save" - // and leave only "Save As" enabled in My Outfits. - mOutfitIsDirty = false; - - if (base_outfit.notNull()) - { - LLIsValidItemLink collector; - - LLInventoryModel::cat_array_t cof_cats; - LLInventoryModel::item_array_t cof_items; - gInventory.collectDescendentsIf(cof, cof_cats, cof_items, - LLInventoryModel::EXCLUDE_TRASH, collector); - - LLInventoryModel::cat_array_t outfit_cats; - LLInventoryModel::item_array_t outfit_items; - gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, - LLInventoryModel::EXCLUDE_TRASH, collector); - - for (U32 i = 0; i < outfit_items.size(); ++i) - { - LLViewerInventoryItem* linked_item = outfit_items.at(i)->getLinkedItem(); - if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) - { - outfit_items.erase(outfit_items.begin() + i); - break; - } - } - - if(outfit_items.size() != cof_items.size()) - { - LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; - // Current outfit folder should have one more item than the outfit folder. - // this one item is the link back to the outfit folder itself. - mOutfitIsDirty = true; - return; - } - - //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) - std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); - std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); - - for (U32 i = 0; i < cof_items.size(); ++i) - { - LLViewerInventoryItem *item1 = cof_items.at(i); - LLViewerInventoryItem *item2 = outfit_items.at(i); - - if (item1->getLinkedUUID() != item2->getLinkedUUID() || - item1->getName() != item2->getName() || - item1->getActualDescription() != item2->getActualDescription()) - { - if (item1->getLinkedUUID() != item2->getLinkedUUID()) - { - LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; - } - else - { - if (item1->getName() != item2->getName()) - { - LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; - } - if (item1->getActualDescription() != item2->getActualDescription()) - { - LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() - << " " << item2->getActualDescription() - << " names " << item1->getName() << " " << item2->getName() << LL_ENDL; - } - } - mOutfitIsDirty = true; - return; - } - } - } - llassert(!mOutfitIsDirty); - LL_DEBUGS("Avatar") << "clean" << LL_ENDL; + //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) + std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); + std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); + + for (U32 i = 0; i < cof_items.size(); ++i) + { + LLViewerInventoryItem *item1 = cof_items.at(i); + LLViewerInventoryItem *item2 = outfit_items.at(i); + + if (item1->getLinkedUUID() != item2->getLinkedUUID() || + item1->getName() != item2->getName() || + item1->getActualDescription() != item2->getActualDescription()) + { + if (item1->getLinkedUUID() != item2->getLinkedUUID()) + { + LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; + } + else + { + if (item1->getName() != item2->getName()) + { + LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + if (item1->getActualDescription() != item2->getActualDescription()) + { + LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() + << " " << item2->getActualDescription() + << " names " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + } + mOutfitIsDirty = true; + return; + } + } + } + llassert(!mOutfitIsDirty); + LL_DEBUGS("Avatar") << "clean" << LL_ENDL; } // *HACK: Must match name in Library or agent inventory @@ -3316,152 +3316,152 @@ const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; void LLAppearanceMgr::copyLibraryGestures() { - LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; - - // Copy gestures - LLUUID lib_gesture_cat_id = - gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE); - if (lib_gesture_cat_id.isNull()) - { - LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; - } - LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); - - std::vector<std::string> gesture_folders_to_copy; - gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); - - for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin(); - it != gesture_folders_to_copy.end(); - ++it) - { - std::string& folder_name = *it; - - LLPointer<LLInventoryCallback> cb(NULL); - - // After copying gestures, activate Common, Other, plus - // Male and/or Female, depending upon the initial outfit gender. - ESex gender = gAgentAvatarp->getSex(); - - std::string activate_male_gestures; - std::string activate_female_gestures; - switch (gender) { - case SEX_MALE: - activate_male_gestures = MALE_GESTURES_FOLDER; - break; - case SEX_FEMALE: - activate_female_gestures = FEMALE_GESTURES_FOLDER; - break; - case SEX_BOTH: - activate_male_gestures = MALE_GESTURES_FOLDER; - activate_female_gestures = FEMALE_GESTURES_FOLDER; - break; - } - - if (folder_name == activate_male_gestures || - folder_name == activate_female_gestures || - folder_name == COMMON_GESTURES_FOLDER || - folder_name == OTHER_GESTURES_FOLDER) - { - cb = new LLBoostFuncInventoryCallback(activate_gesture_cb); - } - - LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); - if (cat_id.isNull()) - { - LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL; - } - else - { - LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; - callAfterCategoryFetch(cat_id, - boost::bind(&LLAppearanceMgr::shallowCopyCategory, - &LLAppearanceMgr::instance(), - cat_id, dst_id, cb)); - } - } + LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; + + // Copy gestures + LLUUID lib_gesture_cat_id = + gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE); + if (lib_gesture_cat_id.isNull()) + { + LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; + } + LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + + std::vector<std::string> gesture_folders_to_copy; + gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); + + for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin(); + it != gesture_folders_to_copy.end(); + ++it) + { + std::string& folder_name = *it; + + LLPointer<LLInventoryCallback> cb(NULL); + + // After copying gestures, activate Common, Other, plus + // Male and/or Female, depending upon the initial outfit gender. + ESex gender = gAgentAvatarp->getSex(); + + std::string activate_male_gestures; + std::string activate_female_gestures; + switch (gender) { + case SEX_MALE: + activate_male_gestures = MALE_GESTURES_FOLDER; + break; + case SEX_FEMALE: + activate_female_gestures = FEMALE_GESTURES_FOLDER; + break; + case SEX_BOTH: + activate_male_gestures = MALE_GESTURES_FOLDER; + activate_female_gestures = FEMALE_GESTURES_FOLDER; + break; + } + + if (folder_name == activate_male_gestures || + folder_name == activate_female_gestures || + folder_name == COMMON_GESTURES_FOLDER || + folder_name == OTHER_GESTURES_FOLDER) + { + cb = new LLBoostFuncInventoryCallback(activate_gesture_cb); + } + + LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); + if (cat_id.isNull()) + { + LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; + callAfterCategoryFetch(cat_id, + boost::bind(&LLAppearanceMgr::shallowCopyCategory, + &LLAppearanceMgr::instance(), + cat_id, dst_id, cb)); + } + } } // Handler for anything that's deferred until avatar de-clouds. void LLAppearanceMgr::onFirstFullyVisible() { - gAgentAvatarp->outputRezTiming("Avatar fully loaded"); - gAgentAvatarp->reportAvatarRezTime(); - gAgentAvatarp->debugAvatarVisible(); + gAgentAvatarp->outputRezTiming("Avatar fully loaded"); + gAgentAvatarp->reportAvatarRezTime(); + gAgentAvatarp->debugAvatarVisible(); - // If this is the first time we've ever logged in, - // then copy default gestures from the library. - if (gAgent.isFirstLogin()) { - copyLibraryGestures(); - } + // If this is the first time we've ever logged in, + // then copy default gestures from the library. + if (gAgent.isFirstLogin()) { + copyLibraryGestures(); + } } // update "dirty" state - defined outside class to allow for calling // after appearance mgr instance has been destroyed. void appearance_mgr_update_dirty_state() { - if (LLAppearanceMgr::instanceExists()) - { - LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); - LLUUID image_id = app_mgr.getOutfitImage(); - if(image_id.notNull()) - { - LLPointer<LLInventoryCallback> cb = NULL; - link_inventory_object(app_mgr.getBaseOutfitUUID(), image_id, cb); - } + if (LLAppearanceMgr::instanceExists()) + { + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + LLUUID image_id = app_mgr.getOutfitImage(); + if(image_id.notNull()) + { + LLPointer<LLInventoryCallback> cb = NULL; + link_inventory_object(app_mgr.getBaseOutfitUUID(), image_id, cb); + } - LLAppearanceMgr::getInstance()->updateIsDirty(); - LLAppearanceMgr::getInstance()->setOutfitLocked(false); - gAgentWearables.notifyLoadingFinished(); - } + LLAppearanceMgr::getInstance()->updateIsDirty(); + LLAppearanceMgr::getInstance()->setOutfitLocked(false); + gAgentWearables.notifyLoadingFinished(); + } } void update_base_outfit_after_ordering() { - LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); - app_mgr.setOutfitImage(LLUUID()); - LLInventoryModel::cat_array_t sub_cat_array; - LLInventoryModel::item_array_t outfit_item_array; - gInventory.collectDescendents(app_mgr.getBaseOutfitUUID(), - sub_cat_array, - outfit_item_array, - LLInventoryModel::EXCLUDE_TRASH); - for (LLViewerInventoryItem* outfit_item : outfit_item_array) - { - LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); - if (linked_item != NULL) - { - if (linked_item->getActualType() == LLAssetType::AT_TEXTURE) - { - app_mgr.setOutfitImage(linked_item->getLinkedUUID()); - if (linked_item->getName() == LLAppearanceMgr::sExpectedTextureName) - { - // Images with "appropriate" name take priority - break; - } - } - } - else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE) - { - app_mgr.setOutfitImage(outfit_item->getUUID()); - if (outfit_item->getName() == LLAppearanceMgr::sExpectedTextureName) - { - // Images with "appropriate" name take priority - break; - } - } - } - - LLPointer<LLInventoryCallback> dirty_state_updater = - new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); - - //COF contains only links so we copy to the Base Outfit only links - const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); - bool copy_folder_links = false; - app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + app_mgr.setOutfitImage(LLUUID()); + LLInventoryModel::cat_array_t sub_cat_array; + LLInventoryModel::item_array_t outfit_item_array; + gInventory.collectDescendents(app_mgr.getBaseOutfitUUID(), + sub_cat_array, + outfit_item_array, + LLInventoryModel::EXCLUDE_TRASH); + for (LLViewerInventoryItem* outfit_item : outfit_item_array) + { + LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); + if (linked_item != NULL) + { + if (linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + app_mgr.setOutfitImage(linked_item->getLinkedUUID()); + if (linked_item->getName() == LLAppearanceMgr::sExpectedTextureName) + { + // Images with "appropriate" name take priority + break; + } + } + } + else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE) + { + app_mgr.setOutfitImage(outfit_item->getUUID()); + if (outfit_item->getName() == LLAppearanceMgr::sExpectedTextureName) + { + // Images with "appropriate" name take priority + break; + } + } + } + + LLPointer<LLInventoryCallback> dirty_state_updater = + new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); + + //COF contains only links so we copy to the Base Outfit only links + const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); + bool copy_folder_links = false; + app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); if (base_outfit_id.notNull()) { @@ -3513,245 +3513,245 @@ void update_base_outfit_after_ordering() // to match the current COF. Fails if no current base outfit is set. bool LLAppearanceMgr::updateBaseOutfit() { - if (isOutfitLocked()) - { - // don't allow modify locked outfit - llassert(!isOutfitLocked()); - return false; - } + if (isOutfitLocked()) + { + // don't allow modify locked outfit + llassert(!isOutfitLocked()); + return false; + } - setOutfitLocked(true); + setOutfitLocked(true); - gAgentWearables.notifyLoadingStarted(); + gAgentWearables.notifyLoadingStarted(); - const LLUUID base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.isNull()) return false; - LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; + const LLUUID base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.isNull()) return false; + LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; - LLPointer<LLInventoryCallback> cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); - // Really shouldn't be needed unless there's a race condition - - // updateAppearanceFromCOF() already calls updateClothingOrderingInfo. - updateClothingOrderingInfo(LLUUID::null, cb); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); + // Really shouldn't be needed unless there's a race condition - + // updateAppearanceFromCOF() already calls updateClothingOrderingInfo. + updateClothingOrderingInfo(LLUUID::null, cb); - return true; + return true; } void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) { - items_by_type.resize(LLWearableType::WT_COUNT); - if (items.empty()) return; - - for (S32 i=0; i<items.size(); i++) - { - LLViewerInventoryItem *item = items.at(i); - if (!item) - { - LL_WARNS("Appearance") << "NULL item found" << LL_ENDL; - continue; - } - // Ignore non-wearables. - if (!item->isWearableType()) - continue; - LLWearableType::EType type = item->getWearableType(); - if(type < 0 || type >= LLWearableType::WT_COUNT) - { - LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; - continue; - } - items_by_type[type].push_back(item); - } + items_by_type.resize(LLWearableType::WT_COUNT); + if (items.empty()) return; + + for (S32 i=0; i<items.size(); i++) + { + LLViewerInventoryItem *item = items.at(i); + if (!item) + { + LL_WARNS("Appearance") << "NULL item found" << LL_ENDL; + continue; + } + // Ignore non-wearables. + if (!item->isWearableType()) + continue; + LLWearableType::EType type = item->getWearableType(); + if(type < 0 || type >= LLWearableType::WT_COUNT) + { + LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; + continue; + } + items_by_type[type].push_back(item); + } } std::string build_order_string(LLWearableType::EType type, U32 i) { - std::ostringstream order_num; - order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; - return order_num.str(); + std::ostringstream order_num; + order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; + return order_num.str(); } struct WearablesOrderComparator { - LOG_CLASS(WearablesOrderComparator); - WearablesOrderComparator(const LLWearableType::EType type) - { - mControlSize = build_order_string(type, 0).size(); - }; - - bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) - { - const std::string& desc1 = item1->getActualDescription(); - const std::string& desc2 = item2->getActualDescription(); - - bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); - bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); - - if (item1_valid && item2_valid) - return desc1 < desc2; - - //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, - //items with ordering information but not for the associated wearables type - if (!item1_valid && item2_valid) - return false; - else if (item1_valid && !item2_valid) - return true; - - return item1->getName() < item2->getName(); - } - - U32 mControlSize; + LOG_CLASS(WearablesOrderComparator); + WearablesOrderComparator(const LLWearableType::EType type) + { + mControlSize = build_order_string(type, 0).size(); + }; + + bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) + { + const std::string& desc1 = item1->getActualDescription(); + const std::string& desc2 = item2->getActualDescription(); + + bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); + bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); + + if (item1_valid && item2_valid) + return desc1 < desc2; + + //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, + //items with ordering information but not for the associated wearables type + if (!item1_valid && item2_valid) + return false; + else if (item1_valid && !item2_valid) + return true; + + return item1->getName() < item2->getName(); + } + + U32 mControlSize; }; void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, - desc_map_t& desc_map) -{ - wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); - divvyWearablesByType(wear_items, items_by_type); - - for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) - { - U32 size = items_by_type[type].size(); - if (!size) continue; - - //sinking down invalid items which need reordering - std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); - - //requesting updates only for those links which don't have "valid" descriptions - for (U32 i = 0; i < size; i++) - { - LLViewerInventoryItem* item = items_by_type[type][i]; - if (!item) continue; - - std::string new_order_str = build_order_string((LLWearableType::EType)type, i); - if (new_order_str == item->getActualDescription()) continue; - - desc_map[item->getUUID()] = new_order_str; - } - } + desc_map_t& desc_map) +{ + wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); + divvyWearablesByType(wear_items, items_by_type); + + for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) + { + U32 size = items_by_type[type].size(); + if (!size) continue; + + //sinking down invalid items which need reordering + std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); + + //requesting updates only for those links which don't have "valid" descriptions + for (U32 i = 0; i < size; i++) + { + LLViewerInventoryItem* item = items_by_type[type][i]; + if (!item) continue; + + std::string new_order_str = build_order_string((LLWearableType::EType)type, i); + if (new_order_str == item->getActualDescription()) continue; + + desc_map[item->getUUID()] = new_order_str; + } + } } bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id) { - // COF is processed if cat_id is not specified - if (cat_id.isNull()) - { - cat_id = getCOF(); - } - - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); - - // Identify items for which desc needs to change. - desc_map_t desc_map; - getWearableOrderingDescUpdates(wear_items, desc_map); - - for (desc_map_t::const_iterator it = desc_map.begin(); - it != desc_map.end(); ++it) - { - const LLUUID& item_id = it->first; - const std::string& new_order_str = it->second; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_WARNS() << "Order validation fails: " << item->getName() - << " needs to update desc to: " << new_order_str - << " (from: " << item->getActualDescription() << ")" << LL_ENDL; - } - - return desc_map.size() == 0; + // COF is processed if cat_id is not specified + if (cat_id.isNull()) + { + cat_id = getCOF(); + } + + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) + { + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_WARNS() << "Order validation fails: " << item->getName() + << " needs to update desc to: " << new_order_str + << " (from: " << item->getActualDescription() << ")" << LL_ENDL; + } + + return desc_map.size() == 0; } void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, - LLPointer<LLInventoryCallback> cb) + LLPointer<LLInventoryCallback> cb) { - // COF is processed if cat_id is not specified - if (cat_id.isNull()) - { - cat_id = getCOF(); - } + // COF is processed if cat_id is not specified + if (cat_id.isNull()) + { + cat_id = getCOF(); + } - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); - // Identify items for which desc needs to change. - desc_map_t desc_map; - getWearableOrderingDescUpdates(wear_items, desc_map); + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) + { + LLSD updates; + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + updates["desc"] = new_order_str; + update_inventory_item(item_id,updates,cb); + } - for (desc_map_t::const_iterator it = desc_map.begin(); - it != desc_map.end(); ++it) - { - LLSD updates; - const LLUUID& item_id = it->first; - const std::string& new_order_str = it->second; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str - << " (was: " << item->getActualDescription() << ")" << LL_ENDL; - updates["desc"] = new_order_str; - update_inventory_item(item_id,updates,cb); - } - } LLSD LLAppearanceMgr::dumpCOF() const { - LLSD links = LLSD::emptyArray(); - LLMD5 md5; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; i<item_array.size(); i++) - { - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - LLSD item; - LLUUID item_id(inv_item->getUUID()); - md5.update((unsigned char*)item_id.mData, 16); - item["description"] = inv_item->getActualDescription(); - md5.update(inv_item->getActualDescription()); - item["asset_type"] = inv_item->getActualType(); - LLUUID linked_id(inv_item->getLinkedUUID()); - item["linked_id"] = linked_id; - md5.update((unsigned char*)linked_id.mData, 16); - - if (LLAssetType::AT_LINK == inv_item->getActualType()) - { - const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem(); - if (NULL == linked_item) - { - LL_WARNS() << "Broken link for item '" << inv_item->getName() - << "' (" << inv_item->getUUID() - << ") during requestServerAppearanceUpdate" << LL_ENDL; - continue; - } - // Some assets may be 'hidden' and show up as null in the viewer. - //if (linked_item->getAssetUUID().isNull()) - //{ - // LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName() - // << "' (" << inv_item->getUUID() - // << ") during requestServerAppearanceUpdate" << LL_ENDL; - // continue; - //} - LLUUID linked_asset_id(linked_item->getAssetUUID()); - md5.update((unsigned char*)linked_asset_id.mData, 16); - U32 flags = linked_item->getFlags(); - md5.update(std::to_string(flags)); - } - else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) - { - LL_WARNS() << "Non-link item '" << inv_item->getName() - << "' (" << inv_item->getUUID() - << ") type " << (S32) inv_item->getActualType() - << " during requestServerAppearanceUpdate" << LL_ENDL; - continue; - } - links.append(item); - } - LLSD result = LLSD::emptyMap(); - result["cof_contents"] = links; - char cof_md5sum[MD5HEX_STR_SIZE]; - md5.finalize(); - md5.hex_digest(cof_md5sum); - result["cof_md5sum"] = std::string(cof_md5sum); - return result; + LLSD links = LLSD::emptyArray(); + LLMD5 md5; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; i<item_array.size(); i++) + { + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + LLSD item; + LLUUID item_id(inv_item->getUUID()); + md5.update((unsigned char*)item_id.mData, 16); + item["description"] = inv_item->getActualDescription(); + md5.update(inv_item->getActualDescription()); + item["asset_type"] = inv_item->getActualType(); + LLUUID linked_id(inv_item->getLinkedUUID()); + item["linked_id"] = linked_id; + md5.update((unsigned char*)linked_id.mData, 16); + + if (LLAssetType::AT_LINK == inv_item->getActualType()) + { + const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem(); + if (NULL == linked_item) + { + LL_WARNS() << "Broken link for item '" << inv_item->getName() + << "' (" << inv_item->getUUID() + << ") during requestServerAppearanceUpdate" << LL_ENDL; + continue; + } + // Some assets may be 'hidden' and show up as null in the viewer. + //if (linked_item->getAssetUUID().isNull()) + //{ + // LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName() + // << "' (" << inv_item->getUUID() + // << ") during requestServerAppearanceUpdate" << LL_ENDL; + // continue; + //} + LLUUID linked_asset_id(linked_item->getAssetUUID()); + md5.update((unsigned char*)linked_asset_id.mData, 16); + U32 flags = linked_item->getFlags(); + md5.update(std::to_string(flags)); + } + else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) + { + LL_WARNS() << "Non-link item '" << inv_item->getName() + << "' (" << inv_item->getUUID() + << ") type " << (S32) inv_item->getActualType() + << " during requestServerAppearanceUpdate" << LL_ENDL; + continue; + } + links.append(item); + } + LLSD result = LLSD::emptyMap(); + result["cof_contents"] = links; + char cof_md5sum[MD5HEX_STR_SIZE]; + md5.finalize(); + md5.hex_digest(cof_md5sum); + result["cof_md5sum"] = std::string(cof_md5sum); + return result; } // static @@ -3819,7 +3819,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd bool bRetry; do { - // If we have already received an update for this or higher cof version, + // If we have already received an update for this or higher cof version, // put a warning in the log and cancel the request. S32 cofVersion = getCOFVersion(); S32 lastRcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; @@ -3891,9 +3891,9 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd std::string message = (result.has("error")) ? result["error"].asString() : status.toString(); LL_WARNS("Avatar") << "Appearance Failure. server responded with \"" << message << "\"" << LL_ENDL; - // We may have requested a bake for a stale COF (especially if the inventory - // is still updating. If that is the case re send the request with the - // corrected COF version. (This may also be the case if the viewer is running + // We may have requested a bake for a stale COF (especially if the inventory + // is still updating. If that is the case re send the request with the + // corrected COF version. (This may also be the case if the viewer is running // on multiple machines. if (result.has("expected")) { @@ -3917,7 +3917,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LL_WARNS("Avatar") << "Bake retry #" << retryCount << " in " << timeout << " seconds." << LL_ENDL; - llcoro::suspendUntilTimeout(timeout); + llcoro::suspendUntilTimeout(timeout); if (LLApp::isExiting()) { return; @@ -4028,81 +4028,81 @@ void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content) std::string LLAppearanceMgr::getAppearanceServiceURL() const { - if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) - { - return mAppearanceServiceURL; - } - return gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride"); + if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) + { + return mAppearanceServiceURL; + } + return gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride"); } void show_created_outfit(LLUUID& folder_id, bool show_panel = true) { - if (!LLApp::isRunning()) - { - LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; - return; - } - - LL_DEBUGS("Avatar") << "called" << LL_ENDL; - LLSD key; - - //EXT-7727. For new accounts inventory callback is created during login process - // and may be processed after login process is finished - if (show_panel) - { - LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; - LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); - - } - LLOutfitsList *outfits_list = - dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); - if (outfits_list) - { - outfits_list->setSelectedOutfitByUUID(folder_id); - } - - LLAppearanceMgr::getInstance()->updateIsDirty(); - gAgentWearables.notifyLoadingFinished(); // New outfit is saved. - LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); - - // For SSB, need to update appearance after we add a base outfit - // link, since, the COF version has changed. There is a race - // condition in initial outfit setup which can lead to rez - // failures - SH-3860. - LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; - LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; - LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); + if (!LLApp::isRunning()) + { + LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; + return; + } + + LL_DEBUGS("Avatar") << "called" << LL_ENDL; + LLSD key; + + //EXT-7727. For new accounts inventory callback is created during login process + // and may be processed after login process is finished + if (show_panel) + { + LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; + LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); + + } + LLOutfitsList *outfits_list = + dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); + if (outfits_list) + { + outfits_list->setSelectedOutfitByUUID(folder_id); + } + + LLAppearanceMgr::getInstance()->updateIsDirty(); + gAgentWearables.notifyLoadingFinished(); // New outfit is saved. + LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + + // For SSB, need to update appearance after we add a base outfit + // link, since, the COF version has changed. There is a race + // condition in initial outfit setup which can lead to rez + // failures - SH-3860. + LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); } void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel) { - LLPointer<LLInventoryCallback> cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, - boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); - updateClothingOrderingInfo(LLUUID::null, cb); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); + updateClothingOrderingInfo(LLUUID::null, cb); } void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel) { - LLPointer<LLInventoryCallback> cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, - boost::bind(show_created_outfit,folder_id,show_panel)); - bool copy_folder_links = false; - slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); + LLPointer<LLInventoryCallback> cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(show_created_outfit,folder_id,show_panel)); + bool copy_folder_links = false; + slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); } void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) { - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) return; - LLUIUsage::instance().logCommand("Avatar.CreateNewOutfit"); + LLUIUsage::instance().logCommand("Avatar.CreateNewOutfit"); - LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; + LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; - gAgentWearables.notifyLoadingStarted(); + gAgentWearables.notifyLoadingStarted(); - // First, make a folder in the My Outfits directory. - const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + // First, make a folder in the My Outfits directory. + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); gInventory.createNewCategory( parent_id, @@ -4116,218 +4116,218 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo void LLAppearanceMgr::wearBaseOutfit() { - const LLUUID& base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.isNull()) return; - - updateCOF(base_outfit_id); + const LLUUID& base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.isNull()) return; + + updateCOF(base_outfit_id); } void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) { - LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL; - LLUIUsage::instance().logCommand("Avatar.RemoveItem"); - - if (ids_to_remove.empty()) - { - LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; - return; - } - LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; - for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) - { - const LLUUID& id_to_remove = *it; - const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); - LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); - if (item && item->getType() == LLAssetType::AT_OBJECT) - { - LL_DEBUGS("Avatar") << "ATT removing attachment " << item->getName() << " id " << item->getUUID() << LL_ENDL; - } - if (item && item->getType() == LLAssetType::AT_BODYPART) - { - continue; - } - removeCOFItemLinks(linked_item_id, cb); - addDoomedTempAttachment(linked_item_id); - } + LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL; + LLUIUsage::instance().logCommand("Avatar.RemoveItem"); + + if (ids_to_remove.empty()) + { + LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; + return; + } + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) + { + const LLUUID& id_to_remove = *it; + const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); + LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); + if (item && item->getType() == LLAssetType::AT_OBJECT) + { + LL_DEBUGS("Avatar") << "ATT removing attachment " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (item && item->getType() == LLAssetType::AT_BODYPART) + { + continue; + } + removeCOFItemLinks(linked_item_id, cb); + addDoomedTempAttachment(linked_item_id); + } } void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) { - uuid_vec_t ids_to_remove; - ids_to_remove.push_back(id_to_remove); - removeItemsFromAvatar(ids_to_remove); + uuid_vec_t ids_to_remove; + ids_to_remove.push_back(id_to_remove); + removeItemsFromAvatar(ids_to_remove); } // Adds the given item ID to mDoomedTempAttachmentIDs iff it's a temp attachment void LLAppearanceMgr::addDoomedTempAttachment(const LLUUID& id_to_remove) { - LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove); - if (attachmentp && - attachmentp->isTempAttachment()) - { // If this is a temp attachment and we want to remove it, record the ID - // so it will be deleted when attachments are synced up with COF - mDoomedTempAttachmentIDs.insert(id_to_remove); - //LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL; - } + LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove); + if (attachmentp && + attachmentp->isTempAttachment()) + { // If this is a temp attachment and we want to remove it, record the ID + // so it will be deleted when attachments are synced up with COF + mDoomedTempAttachmentIDs.insert(id_to_remove); + //LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL; + } } // Find AND REMOVES the given UUID from mDoomedTempAttachmentIDs bool LLAppearanceMgr::shouldRemoveTempAttachment(const LLUUID& item_id) { - doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id); - if (iter != mDoomedTempAttachmentIDs.end()) - { - mDoomedTempAttachmentIDs.erase(iter); - return true; - } - return false; + doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id); + if (iter != mDoomedTempAttachmentIDs.end()) + { + mDoomedTempAttachmentIDs.erase(iter); + return true; + } + return false; } bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) { - if (!item || !item->isWearableType()) return false; - if (item->getType() != LLAssetType::AT_CLOTHING) return false; - if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; + if (!item || !item->isWearableType()) return false; + if (item->getType() != LLAssetType::AT_CLOTHING) return false; + if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; + + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); + gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); + if (items.empty()) return false; - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); - gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); - if (items.empty()) return false; + // We assume that the items have valid descriptions. + std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); - // We assume that the items have valid descriptions. - std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); + if (closer_to_body && items.front() == item) return false; + if (!closer_to_body && items.back() == item) return false; - if (closer_to_body && items.front() == item) return false; - if (!closer_to_body && items.back() == item) return false; - - LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); - if (items.end() == it) return false; + LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); + if (items.end() == it) return false; - //swapping descriptions - closer_to_body ? --it : ++it; - LLViewerInventoryItem* swap_item = *it; - if (!swap_item) return false; - std::string tmp = swap_item->getActualDescription(); - swap_item->setDescription(item->getActualDescription()); - item->setDescription(tmp); + //swapping descriptions + closer_to_body ? --it : ++it; + LLViewerInventoryItem* swap_item = *it; + if (!swap_item) return false; + std::string tmp = swap_item->getActualDescription(); + swap_item->setDescription(item->getActualDescription()); + item->setDescription(tmp); - // LL_DEBUGS("Inventory") << "swap, item " - // << ll_pretty_print_sd(item->asLLSD()) - // << " swap_item " - // << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; + // LL_DEBUGS("Inventory") << "swap, item " + // << ll_pretty_print_sd(item->asLLSD()) + // << " swap_item " + // << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; - // FIXME switch to use AISv3 where supported. - //items need to be updated on a dataserver - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); + // FIXME switch to use AISv3 where supported. + //items need to be updated on a dataserver + item->setComplete(TRUE); + item->updateServer(FALSE); + gInventory.updateItem(item); - swap_item->setComplete(TRUE); - swap_item->updateServer(FALSE); - gInventory.updateItem(swap_item); + swap_item->setComplete(TRUE); + swap_item->updateServer(FALSE); + gInventory.updateItem(swap_item); - //to cause appearance of the agent to be updated - bool result = false; - if ((result = gAgentWearables.moveWearable(item, closer_to_body))) - { - gAgentAvatarp->wearableUpdated(item->getWearableType()); - } + //to cause appearance of the agent to be updated + bool result = false; + if ((result = gAgentWearables.moveWearable(item, closer_to_body))) + { + gAgentAvatarp->wearableUpdated(item->getWearableType()); + } - setOutfitDirty(true); + setOutfitDirty(true); - //*TODO do we need to notify observers here in such a way? - gInventory.notifyObservers(); + //*TODO do we need to notify observers here in such a way? + gInventory.notifyObservers(); - return result; + return result; } //static void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items) { - if (items.size() < 2) return; + if (items.size() < 2) return; - std::sort(items.begin(), items.end(), sort_by_actual_description); + std::sort(items.begin(), items.end(), sort_by_actual_description); } //#define DUMP_CAT_VERBOSE void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); #ifdef DUMP_CAT_VERBOSE - LL_INFOS() << LL_ENDL; - LL_INFOS() << str << LL_ENDL; - S32 hitcount = 0; - for(S32 i=0; i<items.size(); i++) - { - LLViewerInventoryItem *item = items.get(i); - if (item) - hitcount++; - LL_INFOS() << i <<" "<< item->getName() <<LL_ENDL; - } + LL_INFOS() << LL_ENDL; + LL_INFOS() << str << LL_ENDL; + S32 hitcount = 0; + for(S32 i=0; i<items.size(); i++) + { + LLViewerInventoryItem *item = items.get(i); + if (item) + hitcount++; + LL_INFOS() << i <<" "<< item->getName() <<LL_ENDL; + } #endif - LL_INFOS() << msg << " count " << items.size() << LL_ENDL; + LL_INFOS() << msg << " count " << items.size() << LL_ENDL; } void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, - const std::string& msg) + const std::string& msg) { - for (S32 i=0; i<items.size(); i++) - { - LLViewerInventoryItem *item = items.at(i); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - LLUUID asset_id; - if (linked_item) - { - asset_id = linked_item->getAssetUUID(); - } - LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; - } + for (S32 i=0; i<items.size(); i++) + { + LLViewerInventoryItem *item = items.at(i); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + LLUUID asset_id; + if (linked_item) + { + asset_id = linked_item->getAssetUUID(); + } + LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; + } } bool LLAppearanceMgr::mActive = true; LLAppearanceMgr::LLAppearanceMgr(): - mAttachmentInvLinkEnabled(false), - mOutfitIsDirty(false), - mOutfitLocked(false), - mInFlightTimer(), - mIsInUpdateAppearanceFromCOF(false), + mAttachmentInvLinkEnabled(false), + mOutfitIsDirty(false), + mOutfitLocked(false), + mInFlightTimer(), + mIsInUpdateAppearanceFromCOF(false), mOutstandingAppearanceBakeRequest(false), mRerequestAppearanceBake(false) { - LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); - // unlock outfit on save operation completed - outfit_observer.addCOFSavedCallback(boost::bind( - &LLAppearanceMgr::setOutfitLocked, this, false)); + LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); + // unlock outfit on save operation completed + outfit_observer.addCOFSavedCallback(boost::bind( + &LLAppearanceMgr::setOutfitLocked, this, false)); - mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( - "OutfitOperationsTimeout"))); + mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( + "OutfitOperationsTimeout"))); - gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); - gIdleCallbacks.addFunction(&LLAppearanceMgr::onIdle, NULL); //sheduling appearance update requests + gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); + gIdleCallbacks.addFunction(&LLAppearanceMgr::onIdle, NULL); //sheduling appearance update requests } LLAppearanceMgr::~LLAppearanceMgr() { - mActive = false; + mActive = false; } void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) { - LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; - mAttachmentInvLinkEnabled = val; + LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; + mAttachmentInvLinkEnabled = val; } boost::signals2::connection LLAppearanceMgr::setAttachmentsChangedCallback(attachments_changed_callback_t cb) { - return mAttachmentsChangeSignal.connect(cb); + return mAttachmentsChangeSignal.connect(cb); } void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg) @@ -4349,101 +4349,101 @@ void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg) void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) { - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_DEBUGS("Avatar") << "ATT registering attachment " - << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT registering attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - LLAttachmentsMgr::instance().onAttachmentArrived(item_id); + LLAttachmentsMgr::instance().onAttachmentArrived(item_id); - mAttachmentsChangeSignal(); + mAttachmentsChangeSignal(); } void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) { - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_DEBUGS("Avatar") << "ATT unregistering attachment " - << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT unregistering attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); LLAttachmentsMgr::instance().onDetachCompleted(item_id); - if (mAttachmentInvLinkEnabled && isLinkedInCOF(item_id)) - { - LL_DEBUGS("Avatar") << "ATT removing COF link for attachment " - << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; - LLAppearanceMgr::removeCOFItemLinks(item_id); - } - else - { - //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; - } + if (mAttachmentInvLinkEnabled && isLinkedInCOF(item_id)) + { + LL_DEBUGS("Avatar") << "ATT removing COF link for attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + LLAppearanceMgr::removeCOFItemLinks(item_id); + } + else + { + //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; + } - mAttachmentsChangeSignal(); + mAttachmentsChangeSignal(); } BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const { - const LLUUID& cof = getCOF(); - if (obj_id == cof) - return TRUE; - const LLInventoryObject* obj = gInventory.getObject(obj_id); - if (obj && obj->getParentUUID() == cof) - return TRUE; - return FALSE; + const LLUUID& cof = getCOF(); + if (obj_id == cof) + return TRUE; + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == cof) + return TRUE; + return FALSE; } BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const { - if (!getIsInCOF(obj_id)) return FALSE; + if (!getIsInCOF(obj_id)) return FALSE; - // If a non-link somehow ended up in COF, allow deletion. - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (obj && !obj->getIsLinkType()) - { - return FALSE; - } + // If a non-link somehow ended up in COF, allow deletion. + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && !obj->getIsLinkType()) + { + return FALSE; + } - // For now, don't allow direct deletion from the COF. Instead, force users - // to choose "Detach" or "Take Off". - return TRUE; + // For now, don't allow direct deletion from the COF. Instead, force users + // to choose "Detach" or "Take Off". + return TRUE; } class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver { public: - CallAfterCategoryFetchStage2(const uuid_vec_t& ids, - nullary_func_t callable) : - LLInventoryFetchItemsObserver(ids), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage2() - { - } - virtual void done() - { - LL_INFOS() << this << " done with incomplete " << mIncomplete.size() - << " complete " << mComplete.size() << " calling callable" << LL_ENDL; - - gInventory.removeObserver(this); - doOnIdleOneTime(mCallable); - delete this; - } + CallAfterCategoryFetchStage2(const uuid_vec_t& ids, + nullary_func_t callable) : + LLInventoryFetchItemsObserver(ids), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage2() + { + } + virtual void done() + { + LL_INFOS() << this << " done with incomplete " << mIncomplete.size() + << " complete " << mComplete.size() << " calling callable" << LL_ENDL; + + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); + delete this; + } protected: - nullary_func_t mCallable; + nullary_func_t mCallable; }; class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver { public: - CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : - LLInventoryFetchDescendentsObserver(cat_id), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage1() - { - } + CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : + LLInventoryFetchDescendentsObserver(cat_id), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage1() + { + } /*virtual*/ void startFetch() { bool ais3 = AISAPI::isAvailable(); @@ -4458,8 +4458,8 @@ public: // as result fetch won't start and folder will potentially get stuck as // incomplete in observer. // Likely either both should use only version or both should check descendants. - cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. - mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. + cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. + mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. } else if (!isCategoryComplete(cat)) { @@ -4511,8 +4511,8 @@ public: } } } - virtual void done() - { + virtual void done() + { if (mComplete.size() <= 0) { // Ex: timeout @@ -4524,54 +4524,54 @@ public: return; } - // What we do here is get the complete information on the - // items in the requested category, and set up an observer - // that will wait for that to happen. + // What we do here is get the complete information on the + // items in the requested category, and set up an observer + // that will wait for that to happen. LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(mComplete.front(), cats, items); - S32 count = items->size(); - if(!count) - { - LL_WARNS() << "Nothing fetched in category " << mComplete.front() - << LL_ENDL; - gInventory.removeObserver(this); - doOnIdleOneTime(mCallable); + S32 count = items->size(); + if(!count) + { + LL_WARNS() << "Nothing fetched in category " << mComplete.front() + << LL_ENDL; + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); - delete this; - return; - } + delete this; + return; + } LLViewerInventoryCategory* cat = gInventory.getCategory(mComplete.front()); S32 version = cat ? cat->getVersion() : -2; - LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL; - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) - { - ids.push_back(items->at(i)->getUUID()); - } - - gInventory.removeObserver(this); - - // do the fetch - CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); - stage2->startFetch(); - if(stage2->isFinished()) - { - // everything is already here - call done. - stage2->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(stage2); - } - delete this; - } + LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL; + uuid_vec_t ids; + for(S32 i = 0; i < count; ++i) + { + ids.push_back(items->at(i)->getUUID()); + } + + gInventory.removeObserver(this); + + // do the fetch + CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); + stage2->startFetch(); + if(stage2->isFinished()) + { + // everything is already here - call done. + stage2->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(stage2); + } + delete this; + } protected: - nullary_func_t mCallable; + nullary_func_t mCallable; }; void callAfterCOFFetch(nullary_func_t cb) @@ -4621,7 +4621,7 @@ void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb) LL_WARNS() << "AIS API v3 not available, can't use AISAPI::FetchCOF" << LL_ENDL; callAfterCategoryFetch(cat_id, cb); } - + } void add_wearable_type_counts(const uuid_vec_t& ids, @@ -4673,7 +4673,7 @@ void wear_multiple(const uuid_vec_t& ids, bool replace) { cb = new LLUpdateAppearanceOnDestroy; } - LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb); + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb); } // SLapp for easy-wearing of a stock (library) avatar @@ -4681,50 +4681,50 @@ void wear_multiple(const uuid_vec_t& ids, bool replace) class LLWearFolderHandler : public LLCommandHandler { public: - // not allowed from outside the app - LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } + // not allowed from outside the app + LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& tokens, + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) - { - LLSD::UUID folder_uuid; - - if (folder_uuid.isNull() && query_map.has("folder_name")) - { - std::string outfit_folder_name = query_map["folder_name"]; - folder_uuid = findDescendentCategoryIDByName( - gInventory.getLibraryRootFolderID(), - outfit_folder_name); - } - if (folder_uuid.isNull() && query_map.has("folder_id")) - { - folder_uuid = query_map["folder_id"].asUUID(); - } - - if (folder_uuid.notNull()) - { - LLPointer<LLInventoryCategory> category = new LLInventoryCategory(folder_uuid, - LLUUID::null, - LLFolderType::FT_CLOTHING, - "Quick Appearance"); - if ( gInventory.getCategory( folder_uuid ) != NULL ) - { - // Assume this is coming from the predefined avatars web floater - LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance"); - LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); - - // *TODOw: This may not be necessary if initial outfit is chosen already -- josh - gAgent.setOutfitChosen(TRUE); - } - } - - // release avatar picker keyboard focus - gFocusMgr.setKeyboardFocus( NULL ); - - return true; - } + { + LLSD::UUID folder_uuid; + + if (folder_uuid.isNull() && query_map.has("folder_name")) + { + std::string outfit_folder_name = query_map["folder_name"]; + folder_uuid = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + } + if (folder_uuid.isNull() && query_map.has("folder_id")) + { + folder_uuid = query_map["folder_id"].asUUID(); + } + + if (folder_uuid.notNull()) + { + LLPointer<LLInventoryCategory> category = new LLInventoryCategory(folder_uuid, + LLUUID::null, + LLFolderType::FT_CLOTHING, + "Quick Appearance"); + if ( gInventory.getCategory( folder_uuid ) != NULL ) + { + // Assume this is coming from the predefined avatars web floater + LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance"); + LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); + + // *TODOw: This may not be necessary if initial outfit is chosen already -- josh + gAgent.setOutfitChosen(TRUE); + } + } + + // release avatar picker keyboard focus + gFocusMgr.setKeyboardFocus( NULL ); + + return true; + } }; LLWearFolderHandler gWearFolderHandler; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6cc2deea80..be000473ba 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -109,7 +109,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llperfstats.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -149,7 +149,7 @@ #include <boost/throw_exception.hpp> #if LL_WINDOWS -# include <share.h> // For _SH_DENYWR in processMarkerFiles +# include <share.h> // For _SH_DENYWR in processMarkerFiles #else # include <sys/file.h> // For processMarkerFiles #endif @@ -317,16 +317,16 @@ const char* gPlatform = LL_PLATFORM_KEY; LLSD gDebugInfo; -U32 gFrameCount = 0; +U32 gFrameCount = 0; U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground LLPumpIO* gServicePump = NULL; U64MicrosecondsImplicit gFrameTime = 0; F32SecondsImplicit gFrameTimeSeconds = 0.f; F32SecondsImplicit gFrameIntervalSeconds = 0.f; -F32 gFPSClamped = 10.f; // Pretend we start at target rate. -F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets -U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds +F32 gFPSClamped = 10.f; // Pretend we start at target rate. +F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets +U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds LLTimer gRenderStartTime; LLFrameTimer gForegroundTime; @@ -339,24 +339,24 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME; S32 gPendingMetricsUploads = 0; -BOOL gDisconnected = FALSE; +BOOL gDisconnected = FALSE; // used to restore texture state after a mode switch -LLFrameTimer gRestoreGLTimer; -BOOL gRestoreGL = FALSE; -bool gUseWireframe = FALSE; +LLFrameTimer gRestoreGLTimer; +BOOL gRestoreGL = FALSE; +bool gUseWireframe = FALSE; LLMemoryInfo gSysMemory; U64Bytes gMemoryAllocated(0); // updated in display_stats() in llviewerdisplay.cpp std::string gLastVersionChannel; -LLVector3 gWindVec(3.0, 3.0, 0.0); -LLVector3 gRelativeWindVec(0.0, 0.0, 0.0); +LLVector3 gWindVec(3.0, 3.0, 0.0); +LLVector3 gRelativeWindVec(0.0, 0.0, 0.0); -U32 gPacketsIn = 0; +U32 gPacketsIn = 0; -BOOL gPrintMessagesThisFrame = FALSE; +BOOL gPrintMessagesThisFrame = FALSE; BOOL gRandomizeFramerate = FALSE; BOOL gPeriodicSlowFrame = FALSE; @@ -394,53 +394,53 @@ void processComposeSwitch(const std::string&, const std::string&, static std::set<std::string> default_trans_args; void init_default_trans_args() { - default_trans_args.insert("SECOND_LIFE"); // World - default_trans_args.insert("APP_NAME"); - default_trans_args.insert("CAPITALIZED_APP_NAME"); - default_trans_args.insert("SECOND_LIFE_GRID"); - default_trans_args.insert("SUPPORT_SITE"); - // This URL shows up in a surprising number of places in various skin - // files. We really only want to have to maintain a single copy of it. - default_trans_args.insert("create_account_url"); + default_trans_args.insert("SECOND_LIFE"); // World + default_trans_args.insert("APP_NAME"); + default_trans_args.insert("CAPITALIZED_APP_NAME"); + default_trans_args.insert("SECOND_LIFE_GRID"); + default_trans_args.insert("SUPPORT_SITE"); + // This URL shows up in a surprising number of places in various skin + // files. We really only want to have to maintain a single copy of it. + default_trans_args.insert("create_account_url"); } struct SettingsFile : public LLInitParam::Block<SettingsFile> { - Mandatory<std::string> name; - Optional<std::string> file_name; - Optional<bool> required, - persistent; - Optional<std::string> file_name_setting; - - SettingsFile() - : name("name"), - file_name("file_name"), - required("required", false), - persistent("persistent", true), - file_name_setting("file_name_setting") - {} + Mandatory<std::string> name; + Optional<std::string> file_name; + Optional<bool> required, + persistent; + Optional<std::string> file_name_setting; + + SettingsFile() + : name("name"), + file_name("file_name"), + required("required", false), + persistent("persistent", true), + file_name_setting("file_name_setting") + {} }; struct SettingsGroup : public LLInitParam::Block<SettingsGroup> { - Mandatory<std::string> name; - Mandatory<S32> path_index; - Multiple<SettingsFile> files; - - SettingsGroup() - : name("name"), - path_index("path_index"), - files("file") - {} + Mandatory<std::string> name; + Mandatory<S32> path_index; + Multiple<SettingsFile> files; + + SettingsGroup() + : name("name"), + path_index("path_index"), + files("file") + {} }; struct SettingsFiles : public LLInitParam::Block<SettingsFiles> { - Multiple<SettingsGroup> groups; + Multiple<SettingsGroup> groups; - SettingsFiles() - : groups("group") - {} + SettingsFiles() + : groups("group") + {} }; static std::string gWindowTitle; @@ -455,122 +455,122 @@ static bool app_metrics_qa_mode = false; void idle_afk_check() { - // check idle timers - F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); - F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); - if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) - { - LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; - gAgent.setAFK(); - } + // check idle timers + F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); + F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); + if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) + { + LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; + gAgent.setAFK(); + } } // A callback set in LLAppViewer::init() static void ui_audio_callback(const LLUUID& uuid) { - if (gAudiop) - { - SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - gAudiop->triggerSound(soundData); - } + if (gAudiop) + { + SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + gAudiop->triggerSound(soundData); + } } // A callback set in LLAppViewer::init() static void deferred_ui_audio_callback(const LLUUID& uuid) { - if (gAudiop) - { - SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - LLDeferredSounds::instance().deferSound(soundData); - } + if (gAudiop) + { + SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + LLDeferredSounds::instance().deferSound(soundData); + } } -bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) +bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) { - if(!match || !base || base->getPlainText()) - return false; - - LLUUID match_id = match->getID(); - - LLIconCtrl* icon; - - if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor - || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group - { - LLGroupIconCtrl::Params icon_params; - icon_params.group_id = match_id; - icon_params.rect = LLRect(0, 16, 16, 0); - icon_params.visible = true; - icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params); - } - else - { - LLAvatarIconCtrl::Params icon_params; - icon_params.avatar_id = match_id; - icon_params.rect = LLRect(0, 16, 16, 0); - icon_params.visible = true; - icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params); - } - - LLInlineViewSegment::Params params; - params.force_newline = false; - params.view = icon; - params.left_pad = 4; - params.right_pad = 4; - params.top_pad = -2; - params.bottom_pad = 2; - - base->appendWidget(params," ",false); - - return true; + if(!match || !base || base->getPlainText()) + return false; + + LLUUID match_id = match->getID(); + + LLIconCtrl* icon; + + if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor + || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group + { + LLGroupIconCtrl::Params icon_params; + icon_params.group_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params); + } + else + { + LLAvatarIconCtrl::Params icon_params; + icon_params.avatar_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params); + } + + LLInlineViewSegment::Params params; + params.force_newline = false; + params.view = icon; + params.left_pad = 4; + params.right_pad = 4; + params.top_pad = -2; + params.bottom_pad = 2; + + base->appendWidget(params," ",false); + + return true; } // Use these strictly for things that are constructed at startup, // or for things that are performance critical. JC static void settings_to_globals() { - LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); - BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); - BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); + LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); + BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); + BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); - MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); - MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); + MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); + MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); - LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); + LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); #if LL_DARWIN LLRender::sGLCoreProfile = true; #else LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile"); #endif - LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); - LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); - LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); - LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); - LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; - LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); - LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); - LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); - LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); - LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); - LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); - // clamp auto-open time to some minimum usable value - LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay")); - LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive"); - LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); - LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); - - gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); - gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); - gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); - - gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); - gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); + LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); + LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); + LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); + LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); + LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; + LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); + LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); + LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); + LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); + // clamp auto-open time to some minimum usable value + LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay")); + LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive"); + LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); + LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); + + gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); + gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); + gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); + + gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); + gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale")); - + #if LL_DARWIN LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL"); - gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); + gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); #endif } @@ -588,41 +588,41 @@ static void settings_modify() class LLFastTimerLogThread : public LLThread { public: - std::string mFile; - - LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") - { - std::string file_name = test_name + std::string(".slp"); - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); - } - - void run() - { - llofstream os(mFile.c_str()); - - while (!LLAppViewer::instance()->isQuitting()) - { - LLTrace::BlockTimer::writeLog(os); - os.flush(); - ms_sleep(32); - } - - os.close(); - } + std::string mFile; + + LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") + { + std::string file_name = test_name + std::string(".slp"); + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); + } + + void run() + { + llofstream os(mFile.c_str()); + + while (!LLAppViewer::instance()->isQuitting()) + { + LLTrace::BlockTimer::writeLog(os); + os.flush(); + ms_sleep(32); + } + + os.close(); + } }; //virtual bool LLAppViewer::initSLURLHandler() { - // does nothing unless subclassed - return false; + // does nothing unless subclassed + return false; } //virtual bool LLAppViewer::sendURLToOtherInstance(const std::string& url) { - // does nothing unless subclassed - return false; + // does nothing unless subclassed + return false; } //---------------------------------------------------------------------------- @@ -638,402 +638,402 @@ LLPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL; std::string getRuntime() { - return llformat("%.4f", (F32)LLTimer::getElapsedSeconds().value()); + return llformat("%.4f", (F32)LLTimer::getElapsedSeconds().value()); } LLAppViewer::LLAppViewer() -: mMarkerFile(), - mLogoutMarkerFile(), - mReportedCrash(false), - mNumSessions(0), +: mMarkerFile(), + mLogoutMarkerFile(), + mReportedCrash(false), + mNumSessions(0), mGeneralThreadPool(nullptr), - mPurgeCache(false), - mPurgeCacheOnExit(false), - mPurgeUserDataOnExit(false), - mSecondInstance(false), - mUpdaterNotFound(false), - mSavedFinalSnapshot(false), - mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. - mQuitRequested(false), - mLogoutRequestSent(false), - mLastAgentControlFlags(0), - mLastAgentForceUpdate(0), - mMainloopTimeout(NULL), - mAgentRegionLastAlive(false), - mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)), - mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), - mFastTimerLogThread(NULL), - mSettingsLocationList(NULL), - mIsFirstRun(false) + mPurgeCache(false), + mPurgeCacheOnExit(false), + mPurgeUserDataOnExit(false), + mSecondInstance(false), + mUpdaterNotFound(false), + mSavedFinalSnapshot(false), + mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. + mQuitRequested(false), + mLogoutRequestSent(false), + mLastAgentControlFlags(0), + mLastAgentForceUpdate(0), + mMainloopTimeout(NULL), + mAgentRegionLastAlive(false), + mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)), + mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), + mFastTimerLogThread(NULL), + mSettingsLocationList(NULL), + mIsFirstRun(false) { - if(NULL != sInstance) - { - LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; - } + if(NULL != sInstance) + { + LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; + } mDumpPath =""; - // Need to do this initialization before we do anything else, since anything - // that touches files should really go through the lldir API - gDirUtilp->initAppDirs("SecondLife"); - // - // IMPORTANT! Do NOT put anything that will write - // into the log files during normal startup until AFTER - // we run the "program crashed last time" error handler below. - // - sInstance = this; - - gLoggedInTime.stop(); - - processMarkerFiles(); - // - // OK to write stuff to logs now, we've now crash reported if necessary - // - - LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple()); - - // Under some circumstances we want to read the static_debug_info.log file - // from the previous viewer run between this constructor call and the - // init() call, which will overwrite the static_debug_info.log file for - // THIS run. So setDebugFileNames() early. + // Need to do this initialization before we do anything else, since anything + // that touches files should really go through the lldir API + gDirUtilp->initAppDirs("SecondLife"); + // + // IMPORTANT! Do NOT put anything that will write + // into the log files during normal startup until AFTER + // we run the "program crashed last time" error handler below. + // + sInstance = this; + + gLoggedInTime.stop(); + + processMarkerFiles(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // + + LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple()); + + // Under some circumstances we want to read the static_debug_info.log file + // from the previous viewer run between this constructor call and the + // init() call, which will overwrite the static_debug_info.log file for + // THIS run. So setDebugFileNames() early. # ifdef LL_BUGSPLAT - // MAINT-8917: don't create a dump directory just for the - // static_debug_info.log file - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + // MAINT-8917: don't create a dump directory just for the + // static_debug_info.log file + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); # else // ! LL_BUGSPLAT - // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); # endif // ! LL_BUGSPLAT - mDumpPath = logdir; + mDumpPath = logdir; - setDebugFileNames(logdir); + setDebugFileNames(logdir); } LLAppViewer::~LLAppViewer() { - delete mSettingsLocationList; + delete mSettingsLocationList; - destroyMainloopTimeout(); + destroyMainloopTimeout(); - // If we got to this destructor somehow, the app didn't hang. - removeMarkerFiles(); + // If we got to this destructor somehow, the app didn't hang. + removeMarkerFiles(); } class LLUITranslationBridge : public LLTranslationBridge { public: - virtual std::string getString(const std::string &xml_desc) - { - return LLTrans::getString(xml_desc); - } + virtual std::string getString(const std::string &xml_desc) + { + return LLTrans::getString(xml_desc); + } }; bool LLAppViewer::init() { - setupErrorHandling(mSecondInstance); + setupErrorHandling(mSecondInstance); - // - // Start of the application - // + // + // Start of the application + // // initialize the LLSettingsType translation bridge. LLTranslationBridge::ptr_t trans = std::make_shared<LLUITranslationBridge>(); LLSettingsType::initParamSingleton(trans); - // initialize SSE options - LLVector4a::initClass(); + // initialize SSE options + LLVector4a::initClass(); - //initialize particle index pool - LLVOPartGroup::initClass(); + //initialize particle index pool + LLVOPartGroup::initClass(); - // set skin search path to default, will be overridden later - // this allows simple skinned file lookups to work - gDirUtilp->setSkinFolder("default", "en"); + // set skin search path to default, will be overridden later + // this allows simple skinned file lookups to work + gDirUtilp->setSkinFolder("default", "en"); -// initLoggingAndGetLastDuration(); +// initLoggingAndGetLastDuration(); - // - // OK to write stuff to logs now, we've now crash reported if necessary - // - init_default_trans_args(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // + init_default_trans_args(); // inits from settings.xml and from strings.xml - if (!initConfiguration()) - return false; + if (!initConfiguration()) + return false; - LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; - //set the max heap size. - initMaxHeapSize() ; - LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); + //set the max heap size. + initMaxHeapSize() ; + LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); - // Although initLoggingAndGetLastDuration() is the right place to mess with - // setFatalFunction(), we can't query gSavedSettings until after - // initConfiguration(). - S32 rc(gSavedSettings.getS32("QAModeTermCode")); - if (rc >= 0) - { - // QAModeTermCode set, terminate with that rc on LL_ERRS. Use - // _exit() rather than exit() because normal cleanup depends too - // much on successful startup! - LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); - } + // Although initLoggingAndGetLastDuration() is the right place to mess with + // setFatalFunction(), we can't query gSavedSettings until after + // initConfiguration(). + S32 rc(gSavedSettings.getS32("QAModeTermCode")); + if (rc >= 0) + { + // QAModeTermCode set, terminate with that rc on LL_ERRS. Use + // _exit() rather than exit() because normal cleanup depends too + // much on successful startup! + LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); + } mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); - // Initialize the non-LLCurl libcurl library. Should be called - // before consumers (LLTextureFetch). - mAppCoreHttp.init(); + // Initialize the non-LLCurl libcurl library. Should be called + // before consumers (LLTextureFetch). + mAppCoreHttp.init(); - LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; LLMachineID::init(); - { - if (gSavedSettings.getBOOL("QAModeMetrics")) - { - app_metrics_qa_mode = true; - app_metrics_interval = METRICS_INTERVAL_QA; - } - LLViewerAssetStatsFF::init(); - } - - initThreads(); - LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; - - // Initialize settings early so that the defaults for ignorable dialogs are - // picked up and then correctly re-saved after launching the updater (STORM-1268). - LLUI::settings_map_t settings_map; - settings_map["config"] = &gSavedSettings; - settings_map["ignores"] = &gWarningSettings; - settings_map["floater"] = &gSavedSettings; // *TODO: New settings file - settings_map["account"] = &gSavedPerAccountSettings; - - LLUI::initParamSingleton(settings_map, - LLUIImageList::getInstance(), - ui_audio_callback, - deferred_ui_audio_callback); - LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; - - // NOW LLUI::getLanguage() should work. gDirUtilp must know the language - // for this session ASAP so all the file-loading commands that follow, - // that use findSkinnedFilenames(), will include the localized files. - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); - - // Setup LLTrans after LLUI::initClass has been called. - initStrings(); + { + if (gSavedSettings.getBOOL("QAModeMetrics")) + { + app_metrics_qa_mode = true; + app_metrics_interval = METRICS_INTERVAL_QA; + } + LLViewerAssetStatsFF::init(); + } + + initThreads(); + LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; + + // Initialize settings early so that the defaults for ignorable dialogs are + // picked up and then correctly re-saved after launching the updater (STORM-1268). + LLUI::settings_map_t settings_map; + settings_map["config"] = &gSavedSettings; + settings_map["ignores"] = &gWarningSettings; + settings_map["floater"] = &gSavedSettings; // *TODO: New settings file + settings_map["account"] = &gSavedPerAccountSettings; + + LLUI::initParamSingleton(settings_map, + LLUIImageList::getInstance(), + ui_audio_callback, + deferred_ui_audio_callback); + LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; + + // NOW LLUI::getLanguage() should work. gDirUtilp must know the language + // for this session ASAP so all the file-loading commands that follow, + // that use findSkinnedFilenames(), will include the localized files. + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); + + // Setup LLTrans after LLUI::initClass has been called. + initStrings(); // initialize LLWearableType translation bridge. // Will immediately use LLTranslationBridge to init LLWearableDictionary LLWearableType::initParamSingleton(trans); - // Setup notifications after LLUI::initClass() has been called. - LLNotifications::instance(); - LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; + // Setup notifications after LLUI::initClass() has been called. + LLNotifications::instance(); + LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - // *FIX: The following code isn't grouped into functions yet. + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + // *FIX: The following code isn't grouped into functions yet. - // - // Various introspection concerning the libs we're using - particularly - // the libs involved in getting to a full login screen. - // - LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; - LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; + // + // Various introspection concerning the libs we're using - particularly + // the libs involved in getting to a full login screen. + // + LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; + LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; - ///////////////////////////////////////////////// - // OS-specific login dialogs - ///////////////////////////////////////////////// + ///////////////////////////////////////////////// + // OS-specific login dialogs + ///////////////////////////////////////////////// - //test_cached_control(); + //test_cached_control(); - // track number of times that app has run - mNumSessions = gSavedSettings.getS32("NumSessions"); - mNumSessions++; - gSavedSettings.setS32("NumSessions", mNumSessions); + // track number of times that app has run + mNumSessions = gSavedSettings.getS32("NumSessions"); + mNumSessions++; + gSavedSettings.setS32("NumSessions", mNumSessions); - // LLKeyboard relies on LLUI to know what some accelerator keys are called. - LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); + // LLKeyboard relies on LLUI to know what some accelerator keys are called. + LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); - // Provide the text fields with callbacks for opening Urls - LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); - LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); - LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); - LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); + // Provide the text fields with callbacks for opening Urls + LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); + LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); + LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); + LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); - // Let code in llui access the viewer help floater - LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); + // Let code in llui access the viewer help floater + LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); - LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; + LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; - // Load translations for tooltips - LLFloater::initClass(); - LLUrlFloaterDispatchHandler::registerInDispatcher(); + // Load translations for tooltips + LLFloater::initClass(); + LLUrlFloaterDispatchHandler::registerInDispatcher(); - ///////////////////////////////////////////////// + ///////////////////////////////////////////////// - LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated + LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated - LLViewerFloaterReg::registerFloaters(); + LLViewerFloaterReg::registerFloaters(); - ///////////////////////////////////////////////// - // - // Load settings files - // - // - LLGroupMgr::parseRoleActions("role_actions.xml"); + ///////////////////////////////////////////////// + // + // Load settings files + // + // + LLGroupMgr::parseRoleActions("role_actions.xml"); - LLAgent::parseTeleportMessages("teleport_strings.xml"); + LLAgent::parseTeleportMessages("teleport_strings.xml"); - // load MIME type -> media impl mappings - std::string mime_types_name; + // load MIME type -> media impl mappings + std::string mime_types_name; #if LL_DARWIN - mime_types_name = "mime_types_mac.xml"; + mime_types_name = "mime_types_mac.xml"; #elif LL_LINUX - mime_types_name = "mime_types_linux.xml"; + mime_types_name = "mime_types_linux.xml"; #else - mime_types_name = "mime_types.xml"; + mime_types_name = "mime_types.xml"; #endif - LLMIMETypes::parseMIMETypes( mime_types_name ); - - // Copy settings to globals. *TODO: Remove or move to appropriage class initializers - settings_to_globals(); - // Setup settings listeners - settings_setup_listeners(); - // Modify settings based on system configuration and compile options - settings_modify(); - - // Find partition serial number (Windows) or hardware serial (Mac) - mSerialNumber = generateSerialNumber(); - - // do any necessary set-up for accepting incoming SLURLs from apps - initSLURLHandler(); - - if(false == initHardwareTest()) - { - // Early out from user choice. - return false; - } - LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; - - // Prepare for out-of-memory situations, during which we will crash on - // purpose and save a dump. + LLMIMETypes::parseMIMETypes( mime_types_name ); + + // Copy settings to globals. *TODO: Remove or move to appropriage class initializers + settings_to_globals(); + // Setup settings listeners + settings_setup_listeners(); + // Modify settings based on system configuration and compile options + settings_modify(); + + // Find partition serial number (Windows) or hardware serial (Mac) + mSerialNumber = generateSerialNumber(); + + // do any necessary set-up for accepting incoming SLURLs from apps + initSLURLHandler(); + + if(false == initHardwareTest()) + { + // Early out from user choice. + return false; + } + LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; + + // Prepare for out-of-memory situations, during which we will crash on + // purpose and save a dump. #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP - MemSetErrorHandler(first_mem_error_handler); + MemSetErrorHandler(first_mem_error_handler); #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP - // *Note: this is where gViewerStats used to be created. + // *Note: this is where gViewerStats used to be created. - if (!initCache()) - { - LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; - std::ostringstream msg; - msg << LLTrans::getString("MBUnableToAccessFile"); - OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); - return 0; - } - LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; + if (!initCache()) + { + LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; + std::ostringstream msg; + msg << LLTrans::getString("MBUnableToAccessFile"); + OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); + return 0; + } + LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; // Initialize event recorder LLViewerEventRecorder::createInstance(); - // - // Initialize the window - // - gGLActive = TRUE; - initWindow(); - LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; + // + // Initialize the window + // + gGLActive = TRUE; + initWindow(); + LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; // writeSystemInfo can be called after window is initialized (gViewerWindow non-null) writeSystemInfo(); - // initWindow also initializes the Feature List, so now we can initialize this global. - LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); + // initWindow also initializes the Feature List, so now we can initialize this global. + LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); - // call all self-registered classes - LLInitClassList::instance().fireCallbacks(); + // call all self-registered classes + LLInitClassList::instance().fireCallbacks(); - LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts + LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts - gGLManager.getGLInfo(gDebugInfo); - gGLManager.printGLInfoString(); + gGLManager.getGLInfo(gDebugInfo); + gGLManager.printGLInfoString(); - // If we don't have the right GL requirements, exit. - if (!gGLManager.mHasRequirements) - { + // If we don't have the right GL requirements, exit. + if (!gGLManager.mHasRequirements) + { // already handled with a MBVideoDrvErr - return 0; - } - - // Without SSE2 support we will crash almost immediately, warn here. - if (!gSysCPU.hasSSE2()) - { - // can't use an alert here since we're exiting and - // all hell breaks lose. - OSMessageBox( - LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), - LLStringUtil::null, - OSMB_OK); - return 0; - } - - // alert the user if they are using unsupported hardware - if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) - { - bool unsupported = false; - LLSD args; - std::string minSpecs; - - // get cpu data from xml - std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); - S32 minCPU = 0; - minCPUString >> minCPU; - - // get RAM data from XML - std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); - U64Bytes minRAM; - minRAMString >> minRAM; - - if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysCPU.getMHz() < minCPU) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysMemory.getPhysicalMemoryKB() < minRAM) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); - minSpecs += "\n"; - unsupported = true; - } - - if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) - { - LLNotificationsUtil::add("UnknownGPU"); - } - - if(unsupported) - { - if(!gSavedSettings.controlExists("WarnUnsupportedHardware") - || gSavedSettings.getBOOL("WarnUnsupportedHardware")) - { - args["MINSPECS"] = minSpecs; - LLNotificationsUtil::add("UnsupportedHardware", args ); - } - - } - } + return 0; + } + + // Without SSE2 support we will crash almost immediately, warn here. + if (!gSysCPU.hasSSE2()) + { + // can't use an alert here since we're exiting and + // all hell breaks lose. + OSMessageBox( + LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), + LLStringUtil::null, + OSMB_OK); + return 0; + } + + // alert the user if they are using unsupported hardware + if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) + { + bool unsupported = false; + LLSD args; + std::string minSpecs; + + // get cpu data from xml + std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); + S32 minCPU = 0; + minCPUString >> minCPU; + + // get RAM data from XML + std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); + U64Bytes minRAM; + minRAMString >> minRAM; + + if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysCPU.getMHz() < minCPU) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysMemory.getPhysicalMemoryKB() < minRAM) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); + minSpecs += "\n"; + unsupported = true; + } + + if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) + { + LLNotificationsUtil::add("UnknownGPU"); + } + + if(unsupported) + { + if(!gSavedSettings.controlExists("WarnUnsupportedHardware") + || gSavedSettings.getBOOL("WarnUnsupportedHardware")) + { + args["MINSPECS"] = minSpecs; + LLNotificationsUtil::add("UnsupportedHardware", args ); + } + + } + } #if LL_WINDOWS && ADDRESS_SIZE == 64 if (gGLManager.mIsIntel) @@ -1084,54 +1084,54 @@ bool LLAppViewer::init() // Obsolete? mExpectedGLVersion is always zero #if LL_WINDOWS - if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) - { - std::string url; - if (gGLManager.mIsIntel) - { - url = LLTrans::getString("IntelDriverPage"); - } - else if (gGLManager.mIsNVIDIA) - { - url = LLTrans::getString("NvidiaDriverPage"); - } - else if (gGLManager.mIsAMD) - { - url = LLTrans::getString("AMDDriverPage"); - } - - if (!url.empty()) - { - LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); - } - } + if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) + { + std::string url; + if (gGLManager.mIsIntel) + { + url = LLTrans::getString("IntelDriverPage"); + } + else if (gGLManager.mIsNVIDIA) + { + url = LLTrans::getString("NvidiaDriverPage"); + } + else if (gGLManager.mIsAMD) + { + url = LLTrans::getString("AMDDriverPage"); + } + + if (!url.empty()) + { + LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); + } + } #endif - // save the graphics card - gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); + // save the graphics card + gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); - // Save the current version to the prefs file - gSavedSettings.setString("LastRunVersion", - LLVersionInfo::instance().getChannelAndVersion()); + // Save the current version to the prefs file + gSavedSettings.setString("LastRunVersion", + LLVersionInfo::instance().getChannelAndVersion()); - gSimLastTime = gRenderStartTime.getElapsedTimeF32(); - gSimFrames = (F32)gFrameCount; + gSimLastTime = gRenderStartTime.getElapsedTimeF32(); + gSimFrames = (F32)gFrameCount; if (gSavedSettings.getBOOL("JoystickEnabled")) { LLViewerJoystick::getInstance()->init(false); } - try { - initializeSecHandler(); - } - catch (LLProtectedDataException&) - { - LLNotificationsUtil::add("CorruptedProtectedDataStore"); - } + try { + initializeSecHandler(); + } + catch (LLProtectedDataException&) + { + LLNotificationsUtil::add("CorruptedProtectedDataStore"); + } - gGLActive = FALSE; + gGLActive = FALSE; #if LL_RELEASE_FOR_DOWNLOAD // Skip updater if this is a non-interactive instance @@ -1230,25 +1230,25 @@ bool LLAppViewer::init() << LL_ENDL; } - LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; + LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; - //EXT-7013 - On windows for some locale (Japanese) standard - //datetime formatting functions didn't support some parameters such as "weekday". - //Names for days and months localized in xml are also useful for Polish locale(STORM-107). - std::string language = gSavedSettings.getString("Language"); - if(language == "ja" || language == "pl") - { - LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames")); - LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames")); - LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames")); - LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames")); - LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat")); - - LLStringOps::sAM = LLTrans::getString("dateTimeAM"); - LLStringOps::sPM = LLTrans::getString("dateTimePM"); - } + //EXT-7013 - On windows for some locale (Japanese) standard + //datetime formatting functions didn't support some parameters such as "weekday". + //Names for days and months localized in xml are also useful for Polish locale(STORM-107). + std::string language = gSavedSettings.getString("Language"); + if(language == "ja" || language == "pl") + { + LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames")); + LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames")); + LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames")); + LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames")); + LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat")); + + LLStringOps::sAM = LLTrans::getString("dateTimeAM"); + LLStringOps::sPM = LLTrans::getString("dateTimePM"); + } - LLAgentLanguage::init(); + LLAgentLanguage::init(); /// Tell the Coprocedure manager how to discover and store the pool sizes // what I wanted @@ -1256,27 +1256,27 @@ bool LLAppViewer::init() boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1), boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS)); - // TODO: consider moving proxy initialization here or LLCopocedureManager after proxy initialization, may be implement - // some other protection to make sure we don't use network before initializng proxy + // TODO: consider moving proxy initialization here or LLCopocedureManager after proxy initialization, may be implement + // some other protection to make sure we don't use network before initializng proxy - /*----------------------------------------------------------------------*/ - // nat 2016-06-29 moved the following here from the former mainLoop(). - mMainloopTimeout = new LLWatchdogTimeout(); + /*----------------------------------------------------------------------*/ + // nat 2016-06-29 moved the following here from the former mainLoop(). + mMainloopTimeout = new LLWatchdogTimeout(); - // Create IO Pump to use for HTTP Requests. - gServicePump = new LLPumpIO(gAPRPoolp); + // Create IO Pump to use for HTTP Requests. + gServicePump = new LLPumpIO(gAPRPoolp); - // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. - LLVoiceChannel::initClass(); - LLVoiceClient::initParamSingleton(gServicePump); - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); + LLVoiceChannel::initClass(); + LLVoiceClient::initParamSingleton(gServicePump); + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); - joystick = LLViewerJoystick::getInstance(); - joystick->setNeedsReset(true); - /*----------------------------------------------------------------------*/ - // Load User's bindings - loadKeyBindings(); + joystick = LLViewerJoystick::getInstance(); + joystick->setNeedsReset(true); + /*----------------------------------------------------------------------*/ + // Load User's bindings + loadKeyBindings(); //LLSimpleton creations LLEnvironment::createInstance(); @@ -1291,7 +1291,7 @@ bool LLAppViewer::init() } #endif - return true; + return true; } void processComposeSwitch(const std::string& option, @@ -1317,18 +1317,18 @@ void processComposeSwitch(const std::string& option, void LLAppViewer::initMaxHeapSize() { - //set the max heap size. - //here is some info regarding to the max heap size: - //------------------------------------------------------------------------------------------ - // OS | setting | SL address bits | max manageable memory space | max heap size - // Win 32 | default | 32-bit | 2GB | < 1.7GB - // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB - //Linux 32 | default | 32-bit | 3GB | < 2.7GB - //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB - //64-bit OS |default | 32-bit | 4GB | < 3.7GB - //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) - //------------------------------------------------------------------------------------------ - //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. + //set the max heap size. + //here is some info regarding to the max heap size: + //------------------------------------------------------------------------------------------ + // OS | setting | SL address bits | max manageable memory space | max heap size + // Win 32 | default | 32-bit | 2GB | < 1.7GB + // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB + //Linux 32 | default | 32-bit | 3GB | < 2.7GB + //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) + //------------------------------------------------------------------------------------------ + //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. #ifndef LL_X86_64 F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; @@ -1345,42 +1345,42 @@ LLTrace::BlockTimerStatHandle FTM_FRAME("Frame"); bool LLAppViewer::frame() { - bool ret = false; - - if (gSimulateMemLeak) - { - try - { - ret = doFrame(); - } - catch (const LLContinueError&) - { - LOG_UNHANDLED_EXCEPTION(""); - } - catch (std::bad_alloc&) - { - LLMemory::logMemoryInfo(TRUE); - LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); - if (mem_leak_instance) - { - mem_leak_instance->stop(); - } - LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL; - } - } - else - { - try - { - ret = doFrame(); - } - catch (const LLContinueError&) - { - LOG_UNHANDLED_EXCEPTION(""); - } - } - - return ret; + bool ret = false; + + if (gSimulateMemLeak) + { + try + { + ret = doFrame(); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); + } + catch (std::bad_alloc&) + { + LLMemory::logMemoryInfo(TRUE); + LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); + if (mem_leak_instance) + { + mem_leak_instance->stop(); + } + LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL; + } + } + else + { + try + { + ret = doFrame(); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); + } + } + + return ret; } bool LLAppViewer::doFrame() @@ -1473,63 +1473,63 @@ bool LLAppViewer::doFrame() } } - if (!LLApp::isExiting()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) - pingMainloopTimeout("Main:JoystickKeyboard"); - - // 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 - && (gHeadlessClient || gViewerWindow->getWindow()->getVisible()) - && gViewerWindow->getActive() - && !gViewerWindow->getWindow()->getMinimized() - && LLStartUp::getStartupState() == STATE_STARTED - && (gHeadlessClient || !gViewerWindow->getShowProgress()) - && !gFocusMgr.focusLocked()) - { + if (!LLApp::isExiting()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) + pingMainloopTimeout("Main:JoystickKeyboard"); + + // 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 + && (gHeadlessClient || gViewerWindow->getWindow()->getVisible()) + && gViewerWindow->getActive() + && !gViewerWindow->getWindow()->getMinimized() + && LLStartUp::getStartupState() == STATE_STARTED + && (gHeadlessClient || !gViewerWindow->getShowProgress()) + && !gFocusMgr.focusLocked()) + { LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); - joystick->scanJoystick(); - gKeyboard->scanKeyboard(); + joystick->scanJoystick(); + gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); - } + } - // Update state based on messages, user input, object idle. - { - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) - pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! - } + // Update state based on messages, user input, object idle. + { + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! + } - { + { LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); - idle(); - } + idle(); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) - resumeMainloopTimeout(); - } - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } + } - if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) - { - pauseMainloopTimeout(); - saveFinalSnapshot(); + if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) + { + pauseMainloopTimeout(); + saveFinalSnapshot(); if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->terminate(); } - disconnectViewer(); - resumeMainloopTimeout(); - } + disconnectViewer(); + resumeMainloopTimeout(); + } - // Render scene. - // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 + // Render scene. + // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Display"); @@ -1553,159 +1553,159 @@ bool LLAppViewer::doFrame() LLViewerStatsRecorder::instance().idle(); } } - } + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) - pingMainloopTimeout("Main:Sleep"); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pingMainloopTimeout("Main:Sleep"); - pauseMainloopTimeout(); - } + pauseMainloopTimeout(); + } - // Sleep and run background threads - { - //LL_RECORD_BLOCK_TIME(SLEEP2); - LL_PROFILE_ZONE_WARN( "Sleep2" ) + // Sleep and run background threads + { + //LL_RECORD_BLOCK_TIME(SLEEP2); + LL_PROFILE_ZONE_WARN( "Sleep2" ) - // yield some time to the os based on command line option - static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1); - if(yield_time >= 0) - { + // yield some time to the os based on command line option + static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1); + if(yield_time >= 0) + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Yield"); - LL_PROFILE_ZONE_NUM( yield_time ) - ms_sleep(yield_time); - } - - if (gNonInteractive) - { - S32 non_interactive_ms_sleep_time = 100; - LLAppViewer::getTextureCache()->pause(); - ms_sleep(non_interactive_ms_sleep_time); - } - - // yield cooperatively when not running as foreground window - // and when not quiting (causes trouble at mac's cleanup stage) - if (!LLApp::isExiting() - && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) - || !gFocusMgr.getAppHasFocus())) - { - // Sleep if we're not rendering, or the window is minimized. - static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); - S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); - // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads - // of equal priority on Windows - if (milliseconds_to_sleep > 0) - { + LL_PROFILE_ZONE_NUM( yield_time ) + ms_sleep(yield_time); + } + + if (gNonInteractive) + { + S32 non_interactive_ms_sleep_time = 100; + LLAppViewer::getTextureCache()->pause(); + ms_sleep(non_interactive_ms_sleep_time); + } + + // yield cooperatively when not running as foreground window + // and when not quiting (causes trouble at mac's cleanup stage) + if (!LLApp::isExiting() + && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) + || !gFocusMgr.getAppHasFocus())) + { + // Sleep if we're not rendering, or the window is minimized. + static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); + // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads + // of equal priority on Windows + if (milliseconds_to_sleep > 0) + { LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); - // also pause worker threads during this wait period - LLAppViewer::getTextureCache()->pause(); - } - } - - if (mRandomizeFramerate) - { - ms_sleep(rand() % 200); - } - - if (mPeriodicSlowFrame - && (gFrameCount % 10 == 0)) - { - LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; - ms_sleep(500); - } - - S32 total_work_pending = 0; - S32 total_io_pending = 0; - { - S32 work_pending = 0; - S32 io_pending = 0; - F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f); - - work_pending += updateTextureThreads(max_time); - - { + // also pause worker threads during this wait period + LLAppViewer::getTextureCache()->pause(); + } + } + + if (mRandomizeFramerate) + { + ms_sleep(rand() % 200); + } + + if (mPeriodicSlowFrame + && (gFrameCount % 10 == 0)) + { + LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; + ms_sleep(500); + } + + S32 total_work_pending = 0; + S32 total_io_pending = 0; + { + S32 work_pending = 0; + S32 io_pending = 0; + F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f); + + work_pending += updateTextureThreads(max_time); + + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("LFS Thread"); - io_pending += LLLFSThread::updateClass(1); - } - - if (io_pending > 1000) - { - ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up - } - - total_work_pending += work_pending ; - total_io_pending += io_pending ; - - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) - gMeshRepo.update() ; - } - - if(!total_work_pending) //pause texture fetching threads if nothing to process. - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) - LLAppViewer::getTextureCache()->pause(); - LLAppViewer::getTextureFetch()->pause(); - } - if(!total_io_pending) //pause file threads if nothing to process. - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) - LLLFSThread::sLocal->pause(); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) - resumeMainloopTimeout(); - } - pingMainloopTimeout("Main:End"); - } - } - - if (LLApp::isExiting()) - { - // Save snapshot for next time, if we made it through initialization - if (STATE_STARTED == LLStartUp::getStartupState()) - { - saveFinalSnapshot(); - } - - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->terminate(); - } - - delete gServicePump; - gServicePump = NULL; - - destroyMainloopTimeout(); - - LL_INFOS() << "Exiting main_loop" << LL_ENDL; - } + io_pending += LLLFSThread::updateClass(1); + } + + if (io_pending > 1000) + { + ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up + } + + total_work_pending += work_pending ; + total_io_pending += io_pending ; + + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) + gMeshRepo.update() ; + } + + if(!total_work_pending) //pause texture fetching threads if nothing to process. + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) + LLAppViewer::getTextureCache()->pause(); + LLAppViewer::getTextureFetch()->pause(); + } + if(!total_io_pending) //pause file threads if nothing to process. + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) + LLLFSThread::sLocal->pause(); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } + pingMainloopTimeout("Main:End"); + } + } + + if (LLApp::isExiting()) + { + // Save snapshot for next time, if we made it through initialization + if (STATE_STARTED == LLStartUp::getStartupState()) + { + saveFinalSnapshot(); + } + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->terminate(); + } + + delete gServicePump; + gServicePump = NULL; + + destroyMainloopTimeout(); + + LL_INFOS() << "Exiting main_loop" << LL_ENDL; + } }LLPerfStats::StatsRecorder::endFrame(); LL_PROFILER_FRAME_END - return ! LLApp::isRunning(); + return ! LLApp::isRunning(); } S32 LLAppViewer::updateTextureThreads(F32 max_time) { - S32 work_pending = 0; - { + S32 work_pending = 0; + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Texture Cache"); - work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread - } - { + work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + } + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Image Decode"); - work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread - } - { + work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + } + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Image Fetch"); - work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread - } - return work_pending; + work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + } + return work_pending; } void LLAppViewer::flushLFSIO() @@ -1730,200 +1730,200 @@ bool LLAppViewer::cleanup() { LLAtmosphere::cleanupClass(); - //ditch LLVOAvatarSelf instance - gAgentAvatarp = NULL; + //ditch LLVOAvatarSelf instance + gAgentAvatarp = NULL; LLNotifications::instance().clear(); - // workaround for DEV-35406 crash on shutdown - LLEventPumps::instance().reset(true); + // workaround for DEV-35406 crash on shutdown + LLEventPumps::instance().reset(true); - //dump scene loading monitor results - if (LLSceneMonitor::instanceExists()) - { - if (!isSecondInstance()) - { + //dump scene loading monitor results + if (LLSceneMonitor::instanceExists()) + { + if (!isSecondInstance()) + { std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv"); - LLSceneMonitor::instance().dumpToFile(dump_path); - } - LLSceneMonitor::deleteSingleton(); - } - - // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block - // here, completely redundant with the one that occurs later in this same - // function. Presumably the duplication was due to an automated merge gone - // bad. Not knowing which instance to prefer, we chose to retain the later - // one because it happens just after mFastTimerLogThread is deleted. This - // comment is in case we guessed wrong, so we can move it here instead. + LLSceneMonitor::instance().dumpToFile(dump_path); + } + LLSceneMonitor::deleteSingleton(); + } + + // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block + // here, completely redundant with the one that occurs later in this same + // function. Presumably the duplication was due to an automated merge gone + // bad. Not knowing which instance to prefer, we chose to retain the later + // one because it happens just after mFastTimerLogThread is deleted. This + // comment is in case we guessed wrong, so we can move it here instead. #if LL_LINUX - // remove any old breakpad minidump files from the log directory - if (! isError()) - { - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); - gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); - } + // remove any old breakpad minidump files from the log directory + if (! isError()) + { + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); + } #endif - // Kill off LLLeap objects. We can find them all because LLLeap is derived - // from LLInstanceTracker. - LLLeap::instance_snapshot().deleteAll(); + // Kill off LLLeap objects. We can find them all because LLLeap is derived + // from LLInstanceTracker. + LLLeap::instance_snapshot().deleteAll(); - //flag all elements as needing to be destroyed immediately - // to ensure shutdown order - LLMortician::setZealous(TRUE); + //flag all elements as needing to be destroyed immediately + // to ensure shutdown order + LLMortician::setZealous(TRUE); // Give any remaining SLPlugin instances a chance to exit cleanly. LLPluginProcessParent::shutdown(); - disconnectViewer(); - LLViewerCamera::deleteSingleton(); + disconnectViewer(); + LLViewerCamera::deleteSingleton(); + + LL_INFOS() << "Viewer disconnected" << LL_ENDL; - LL_INFOS() << "Viewer disconnected" << LL_ENDL; - - if (gKeyboard) - { - gKeyboard->resetKeys(); - } + if (gKeyboard) + { + gKeyboard->resetKeys(); + } - display_cleanup(); + display_cleanup(); - release_start_screen(); // just in case + release_start_screen(); // just in case - LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder + LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder - LL_INFOS() << "Cleaning Up" << LL_ENDL; + LL_INFOS() << "Cleaning Up" << LL_ENDL; - // shut down mesh streamer - gMeshRepo.shutdown(); + // shut down mesh streamer + gMeshRepo.shutdown(); - // shut down Havok - LLPhysicsExtensions::quitSystem(); + // shut down Havok + LLPhysicsExtensions::quitSystem(); - // Must clean up texture references before viewer window is destroyed. - if(LLHUDManager::instanceExists()) - { - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDObject::cleanupHUDObjects(); - LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; - } + // Must clean up texture references before viewer window is destroyed. + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDObject::cleanupHUDObjects(); + LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; + } - LLKeyframeDataCache::clear(); + LLKeyframeDataCache::clear(); - // End TransferManager before deleting systems it depends on (Audio, AssetStorage) + // End TransferManager before deleting systems it depends on (Audio, AssetStorage) #if 0 // this seems to get us stuck in an infinite loop... - gTransferManager.cleanup(); + gTransferManager.cleanup(); #endif - // Note: this is where gWorldMap used to be deleted. + // Note: this is where gWorldMap used to be deleted. - // Note: this is where gHUDManager used to be deleted. - if(LLHUDManager::instanceExists()) - { - LLHUDManager::getInstance()->shutdownClass(); - } + // Note: this is where gHUDManager used to be deleted. + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->shutdownClass(); + } - delete gAssetStorage; - gAssetStorage = NULL; + delete gAssetStorage; + gAssetStorage = NULL; - LLPolyMesh::freeAllMeshes(); + LLPolyMesh::freeAllMeshes(); - LLStartUp::cleanupNameCache(); + LLStartUp::cleanupNameCache(); - // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. - if (LLWorldMap::instanceExists()) - { - LLWorldMap::getInstance()->reset(); // release any images - } + if (LLWorldMap::instanceExists()) + { + LLWorldMap::getInstance()->reset(); // release any images + } - LLCalc::cleanUp(); + LLCalc::cleanUp(); - LL_INFOS() << "Global stuff deleted" << LL_ENDL; + LL_INFOS() << "Global stuff deleted" << LL_ENDL; - if (gAudiop) - { + if (gAudiop) + { LL_INFOS() << "Shutting down audio" << LL_ENDL; // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it. gAudiop->stopInternetStream(); // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); - delete sai; - gAudiop->setStreamingAudioImpl(NULL); + delete sai; + gAudiop->setStreamingAudioImpl(NULL); // shut down the audio subsystem gAudiop->shutdown(); - delete gAudiop; - gAudiop = NULL; - } - - // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. + delete gAudiop; + gAudiop = NULL; + } - // Patch up settings for next time - // Must do this before we delete the viewer window, - // such that we can suck rectangle information out of - // it. - cleanupSavedSettings(); - LL_INFOS() << "Settings patched up" << LL_ENDL; + // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. - // delete some of the files left around in the cache. - removeCacheFiles("*.wav"); - removeCacheFiles("*.tmp"); - removeCacheFiles("*.lso"); - removeCacheFiles("*.out"); - removeCacheFiles("*.dsf"); - removeCacheFiles("*.bodypart"); - removeCacheFiles("*.clothing"); + // Patch up settings for next time + // Must do this before we delete the viewer window, + // such that we can suck rectangle information out of + // it. + cleanupSavedSettings(); + LL_INFOS() << "Settings patched up" << LL_ENDL; - LL_INFOS() << "Cache files removed" << LL_ENDL; + // delete some of the files left around in the cache. + removeCacheFiles("*.wav"); + removeCacheFiles("*.tmp"); + removeCacheFiles("*.lso"); + removeCacheFiles("*.out"); + removeCacheFiles("*.dsf"); + removeCacheFiles("*.bodypart"); + removeCacheFiles("*.clothing"); - LL_INFOS() << "Shutting down Views" << LL_ENDL; + LL_INFOS() << "Cache files removed" << LL_ENDL; - // Destroy the UI - if( gViewerWindow) - gViewerWindow->shutdownViews(); + LL_INFOS() << "Shutting down Views" << LL_ENDL; - LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; + // Destroy the UI + if( gViewerWindow) + gViewerWindow->shutdownViews(); - // Cleanup Inventory after the UI since it will delete any remaining observers - // (Deleted observers should have already removed themselves) - gInventory.cleanupInventory(); + LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; - LLCoros::getInstance()->printActiveCoroutines(); + // Cleanup Inventory after the UI since it will delete any remaining observers + // (Deleted observers should have already removed themselves) + gInventory.cleanupInventory(); - LL_INFOS() << "Cleaning up Selections" << LL_ENDL; + LLCoros::getInstance()->printActiveCoroutines(); - // Clean up selection managers after UI is destroyed, as UI may be observing them. - // Clean up before GL is shut down because we might be holding on to objects with texture references - LLSelectMgr::cleanupGlobals(); + LL_INFOS() << "Cleaning up Selections" << LL_ENDL; - LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; + // Clean up selection managers after UI is destroyed, as UI may be observing them. + // Clean up before GL is shut down because we might be holding on to objects with texture references + LLSelectMgr::cleanupGlobals(); - // Shut down OpenGL - if( gViewerWindow) - { - gViewerWindow->shutdownGL(); + LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; - // Destroy window, and make sure we're not fullscreen - // This may generate window reshape and activation events. - // Therefore must do this before destroying the message system. - delete gViewerWindow; - gViewerWindow = NULL; - LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; - } + // Shut down OpenGL + if( gViewerWindow) + { + gViewerWindow->shutdownGL(); + + // Destroy window, and make sure we're not fullscreen + // This may generate window reshape and activation events. + // Therefore must do this before destroying the message system. + delete gViewerWindow; + gViewerWindow = NULL; + LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; + } LLSplashScreen::show(); LLSplashScreen::update(LLTrans::getString("ShuttingDown")); - LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; + LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; - // viewer UI relies on keyboard so keep it aound until viewer UI isa gone - delete gKeyboard; - gKeyboard = NULL; + // viewer UI relies on keyboard so keep it aound until viewer UI isa gone + delete gKeyboard; + gKeyboard = NULL; if (LLViewerJoystick::instanceExists()) { @@ -1931,280 +1931,280 @@ bool LLAppViewer::cleanup() LLViewerJoystick::getInstance()->terminate(); } - LL_INFOS() << "Cleaning up Objects" << LL_ENDL; + LL_INFOS() << "Cleaning up Objects" << LL_ENDL; - LLViewerObject::cleanupVOClasses(); + LLViewerObject::cleanupVOClasses(); - SUBSYSTEM_CLEANUP(LLAvatarAppearance); + SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLPostProcess); + SUBSYSTEM_CLEANUP(LLPostProcess); - LLTracker::cleanupInstance(); + LLTracker::cleanupInstance(); - // *FIX: This is handled in LLAppViewerWin32::cleanup(). - // I'm keeping the comment to remember its order in cleanup, - // in case of unforseen dependency. - //#if LL_WINDOWS - // gDXHardware.cleanup(); - //#endif // LL_WINDOWS + // *FIX: This is handled in LLAppViewerWin32::cleanup(). + // I'm keeping the comment to remember its order in cleanup, + // in case of unforseen dependency. + //#if LL_WINDOWS + // gDXHardware.cleanup(); + //#endif // LL_WINDOWS - LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); - if (!volume_manager->cleanup()) - { - LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; - } - LLPrimitive::cleanupVolumeManager(); + LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); + if (!volume_manager->cleanup()) + { + LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; + } + LLPrimitive::cleanupVolumeManager(); - LL_INFOS() << "Additional Cleanup..." << LL_ENDL; + LL_INFOS() << "Additional Cleanup..." << LL_ENDL; - LLViewerParcelMgr::cleanupGlobals(); + LLViewerParcelMgr::cleanupGlobals(); - // *Note: this is where gViewerStats used to be deleted. + // *Note: this is where gViewerStats used to be deleted. - //end_messaging_system(); + //end_messaging_system(); - LLPrimitive::cleanupVolumeManager(); - SUBSYSTEM_CLEANUP(LLWorldMapView); - SUBSYSTEM_CLEANUP(LLFolderViewItem); + LLPrimitive::cleanupVolumeManager(); + SUBSYSTEM_CLEANUP(LLWorldMapView); + SUBSYSTEM_CLEANUP(LLFolderViewItem); - LL_INFOS() << "Saving Data" << LL_ENDL; + LL_INFOS() << "Saving Data" << LL_ENDL; - // Store the time of our current logoff - gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + // Store the time of our current logoff + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); if (LLEnvironment::instanceExists()) { - //Store environment settings if necessary + //Store environment settings if necessary LLEnvironment::getInstance()->saveToSettings(); } - // Must do this after all panels have been deleted because panels that have persistent rects - // save their rects on delete. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - - LLUIColorTable::instance().saveUserSettings(); - - // PerAccountSettingsFile should be empty if no user has been logged on. - // *FIX:Mani This should get really saved in a "logoff" mode. - if (gSavedSettings.getString("PerAccountSettingsFile").empty()) - { - LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; - } - // Only save per account settings if the previous login succeeded, otherwise - // we might end up with a cleared out settings file in case a previous login - // failed after loading per account settings. - else if (!mSavePerAccountSettings) - { - LL_INFOS() << "Not saving per-account settings; last login was not successful." << LL_ENDL; - } - else - { - gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - LL_INFOS() << "Saved settings" << LL_ENDL; - - if (LLViewerParcelAskPlay::instanceExists()) - { - LLViewerParcelAskPlay::getInstance()->saveSettings(); - } - } - - std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); - gWarningSettings.saveToFile(warnings_settings_filename, TRUE); - - // Save URL history file - LLURLHistory::saveFile("url_history.xml"); - - // save mute list. gMuteList used to also be deleted here too. - if (gAgent.isInitialized() && LLMuteList::instanceExists()) - { - LLMuteList::getInstance()->cache(gAgent.getID()); - } - - //save call log list - if (LLConversationLog::instanceExists()) - { - LLConversationLog::instance().cache(); - } - - clearSecHandler(); + // Must do this after all panels have been deleted because panels that have persistent rects + // save their rects on delete. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - if (mPurgeCacheOnExit) - { - LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); - } - - writeDebugInfo(); - - LLLocationHistory::getInstance()->save(); - - LLAvatarIconIDCache::getInstance()->save(); - - // Stop the plugin read thread if it's running. - LLPluginProcessParent::setUseReadThread(false); - - LL_INFOS() << "Shutting down Threads" << LL_ENDL; - - // Let threads finish - LLTimer idleTimer; - idleTimer.reset(); - const F64 max_idle_time = 5.f; // 5 seconds - while(1) - { - S32 pending = 0; - pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread - pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - pending += LLLFSThread::updateClass(0); - F64 idle_time = idleTimer.getElapsedTimeF64(); - if(!pending) - { - break ; //done - } - else if(idle_time >= max_idle_time) - { - LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; - break; - } - } + LLUIColorTable::instance().saveUserSettings(); - if (mPurgeUserDataOnExit) + // PerAccountSettingsFile should be empty if no user has been logged on. + // *FIX:Mani This should get really saved in a "logoff" mode. + if (gSavedSettings.getString("PerAccountSettingsFile").empty()) { - // Ideally we should not save anything from this session since it is going to be purged now, - // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code - std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); - gDirUtilp->deleteDirAndContents(user_path); + LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; } + // Only save per account settings if the previous login succeeded, otherwise + // we might end up with a cleared out settings file in case a previous login + // failed after loading per account settings. + else if (!mSavePerAccountSettings) + { + LL_INFOS() << "Not saving per-account settings; last login was not successful." << LL_ENDL; + } + else + { + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + LL_INFOS() << "Saved settings" << LL_ENDL; - // Delete workers first - // shotdown all worker threads before deleting them in case of co-dependencies - mAppCoreHttp.requestStop(); - sTextureFetch->shutdown(); - sTextureCache->shutdown(); - sImageDecodeThread->shutdown(); - sPurgeDiskCacheThread->shutdown(); - if (mGeneralThreadPool) - { - mGeneralThreadPool->close(); - } - - sTextureFetch->shutDownTextureCacheThread() ; - LLLFSThread::sLocal->shutdown(); + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->saveSettings(); + } + } - LL_INFOS() << "Shutting down message system" << LL_ENDL; - end_messaging_system(); + std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); + gWarningSettings.saveToFile(warnings_settings_filename, TRUE); - // Non-LLCurl libcurl library - mAppCoreHttp.cleanup(); + // Save URL history file + LLURLHistory::saveFile("url_history.xml"); - SUBSYSTEM_CLEANUP(LLFilePickerThread); - SUBSYSTEM_CLEANUP(LLDirPickerThread); + // save mute list. gMuteList used to also be deleted here too. + if (gAgent.isInitialized() && LLMuteList::instanceExists()) + { + LLMuteList::getInstance()->cache(gAgent.getID()); + } - //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) - delete sTextureCache; - sTextureCache = NULL; - if (sTextureFetch) + //save call log list + if (LLConversationLog::instanceExists()) + { + LLConversationLog::instance().cache(); + } + + clearSecHandler(); + + if (mPurgeCacheOnExit) + { + LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); + } + + writeDebugInfo(); + + LLLocationHistory::getInstance()->save(); + + LLAvatarIconIDCache::getInstance()->save(); + + // Stop the plugin read thread if it's running. + LLPluginProcessParent::setUseReadThread(false); + + LL_INFOS() << "Shutting down Threads" << LL_ENDL; + + // Let threads finish + LLTimer idleTimer; + idleTimer.reset(); + const F64 max_idle_time = 5.f; // 5 seconds + while(1) + { + S32 pending = 0; + pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread + pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + pending += LLLFSThread::updateClass(0); + F64 idle_time = idleTimer.getElapsedTimeF64(); + if(!pending) + { + break ; //done + } + else if(idle_time >= max_idle_time) + { + LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; + break; + } + } + + if (mPurgeUserDataOnExit) + { + // Ideally we should not save anything from this session since it is going to be purged now, + // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); + gDirUtilp->deleteDirAndContents(user_path); + } + + // Delete workers first + // shotdown all worker threads before deleting them in case of co-dependencies + mAppCoreHttp.requestStop(); + sTextureFetch->shutdown(); + sTextureCache->shutdown(); + sImageDecodeThread->shutdown(); + sPurgeDiskCacheThread->shutdown(); + if (mGeneralThreadPool) + { + mGeneralThreadPool->close(); + } + + sTextureFetch->shutDownTextureCacheThread() ; + LLLFSThread::sLocal->shutdown(); + + LL_INFOS() << "Shutting down message system" << LL_ENDL; + end_messaging_system(); + + // Non-LLCurl libcurl library + mAppCoreHttp.cleanup(); + + SUBSYSTEM_CLEANUP(LLFilePickerThread); + SUBSYSTEM_CLEANUP(LLDirPickerThread); + + //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) + delete sTextureCache; + sTextureCache = NULL; + if (sTextureFetch) { sTextureFetch->shutdown(); sTextureFetch->waitOnPending(); delete sTextureFetch; sTextureFetch = NULL; } - delete sImageDecodeThread; + delete sImageDecodeThread; sImageDecodeThread = NULL; - delete mFastTimerLogThread; - mFastTimerLogThread = NULL; - delete sPurgeDiskCacheThread; - sPurgeDiskCacheThread = NULL; + delete mFastTimerLogThread; + mFastTimerLogThread = NULL; + delete sPurgeDiskCacheThread; + sPurgeDiskCacheThread = NULL; delete mGeneralThreadPool; mGeneralThreadPool = NULL; - if (LLFastTimerView::sAnalyzePerformance) - { - LL_INFOS() << "Analyzing performance" << LL_ENDL; + if (LLFastTimerView::sAnalyzePerformance) + { + LL_INFOS() << "Analyzing performance" << LL_ENDL; - std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; - std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; - std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; + std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; + std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; + std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); - } + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); + } - SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; + SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; - LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; + LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; - //Note: - //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() - //because some new image might be generated during cleaning up media. --bao - gTextureList.shutdown(); // shutdown again in case a callback added something - LLUIImageList::getInstance()->cleanUp(); + //Note: + //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() + //because some new image might be generated during cleaning up media. --bao + gTextureList.shutdown(); // shutdown again in case a callback added something + LLUIImageList::getInstance()->cleanUp(); - SUBSYSTEM_CLEANUP(LLImage); - SUBSYSTEM_CLEANUP(LLLFSThread); + SUBSYSTEM_CLEANUP(LLImage); + SUBSYSTEM_CLEANUP(LLLFSThread); - LL_INFOS() << "Misc Cleanup" << LL_ENDL; + LL_INFOS() << "Misc Cleanup" << LL_ENDL; - gSavedSettings.cleanup(); - LLUIColorTable::instance().clear(); + gSavedSettings.cleanup(); + LLUIColorTable::instance().clear(); - LLWatchdog::getInstance()->cleanup(); + LLWatchdog::getInstance()->cleanup(); - LLViewerAssetStatsFF::cleanup(); + LLViewerAssetStatsFF::cleanup(); - // If we're exiting to launch an URL, do that here so the screen - // is at the right resolution before we launch IE. - if (!gLaunchFileOnQuit.empty()) - { - LL_INFOS() << "Launch file on quit." << LL_ENDL; + // If we're exiting to launch an URL, do that here so the screen + // is at the right resolution before we launch IE. + if (!gLaunchFileOnQuit.empty()) + { + LL_INFOS() << "Launch file on quit." << LL_ENDL; #if LL_WINDOWS - // Indicate an application is starting. - SetCursor(LoadCursor(NULL, IDC_WAIT)); + // Indicate an application is starting. + SetCursor(LoadCursor(NULL, IDC_WAIT)); #endif - // HACK: Attempt to wait until the screen res. switch is complete. - ms_sleep(1000); + // HACK: Attempt to wait until the screen res. switch is complete. + ms_sleep(1000); - LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); - LL_INFOS() << "File launched." << LL_ENDL; - } - // make sure nothing uses applyProxySettings by this point. - LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; - SUBSYSTEM_CLEANUP(LLProxy); + LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); + LL_INFOS() << "File launched." << LL_ENDL; + } + // make sure nothing uses applyProxySettings by this point. + LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; + SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); - ll_close_fail_log(); + ll_close_fail_log(); - LLError::LLCallStacks::cleanup(); + LLError::LLCallStacks::cleanup(); - LLEnvironment::deleteSingleton(); - LLSelectMgr::deleteSingleton(); - LLViewerEventRecorder::deleteSingleton(); + LLEnvironment::deleteSingleton(); + LLSelectMgr::deleteSingleton(); + LLViewerEventRecorder::deleteSingleton(); LLWorld::deleteSingleton(); LLVoiceClient::deleteSingleton(); - // It's not at first obvious where, in this long sequence, a generic cleanup - // call OUGHT to go. So let's say this: as we migrate cleanup from - // explicit hand-placed calls into the generic mechanism, eventually - // all cleanup will get subsumed into the generic call. So the calls you - // still see above are calls that MUST happen before the generic cleanup - // kicks in. + // It's not at first obvious where, in this long sequence, a generic cleanup + // call OUGHT to go. So let's say this: as we migrate cleanup from + // explicit hand-placed calls into the generic mechanism, eventually + // all cleanup will get subsumed into the generic call. So the calls you + // still see above are calls that MUST happen before the generic cleanup + // kicks in. - // This calls every remaining LLSingleton's cleanupSingleton() and - // deleteSingleton() methods. - LLSingletonBase::deleteAll(); + // This calls every remaining LLSingleton's cleanupSingleton() and + // deleteSingleton() methods. + LLSingletonBase::deleteAll(); LLSplashScreen::hide(); LL_INFOS() << "Goodbye!" << LL_ENDL; - removeDumpDir(); + removeDumpDir(); - // return 0; - return true; + // return 0; + return true; } void LLAppViewer::initGeneralThread() @@ -2220,11 +2220,11 @@ void LLAppViewer::initGeneralThread() bool LLAppViewer::initThreads() { - static const bool enable_threads = true; + static const bool enable_threads = true; - LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); + LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); - LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo + LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo //auto configure thread count LLSD threadCounts = gSavedSettings.getLLSD("ThreadPoolSizes"); @@ -2239,39 +2239,39 @@ bool LLAppViewer::initThreads() } // The only configurable thread count right now is ImageDecode - // The viewer typically starts around 8 threads not including image decode, + // The viewer typically starts around 8 threads not including image decode, // so try to leave at least one core free S32 image_decode_count = llclamp(cores - 9, 1, 8); threadCounts["ImageDecode"] = image_decode_count; gSavedSettings.setLLSD("ThreadPoolSizes", threadCounts); - // Image decoding - LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); - LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); - LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), - enable_threads && true, - app_metrics_qa_mode); + // Image decoding + LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); + LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); + LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), + enable_threads && true, + app_metrics_qa_mode); // general task background thread (LLPerfStats, etc) LLAppViewer::instance()->initGeneralThread(); - LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); + LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); - if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) - { - LLTrace::BlockTimer::setLogLock(new LLMutex()); - mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); - mFastTimerLogThread->start(); - } + if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) + { + LLTrace::BlockTimer::setLogLock(new LLMutex()); + mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); + mFastTimerLogThread->start(); + } - // Mesh streaming and caching - gMeshRepo.init(); + // Mesh streaming and caching + gMeshRepo.init(); - LLFilePickerThread::initClass(); - LLDirPickerThread::initClass(); + LLFilePickerThread::initClass(); + LLDirPickerThread::initClass(); - // *FIX: no error handling here! - return true; + // *FIX: no error handling here! + return true; } void errorCallback(LLError::ELevel level, const std::string &error_string) @@ -2315,7 +2315,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() if (mSecondInstance) { LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); - + LLUUID uid; uid.generate(); LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); @@ -2386,123 +2386,123 @@ void LLAppViewer::initLoggingAndGetLastDuration() } bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults) + bool set_defaults) { - if (!mSettingsLocationList) - { - LL_ERRS() << "Invalid settings location list" << LL_ENDL; - } - - for (const SettingsGroup& group : mSettingsLocationList->groups) - { - // skip settings groups that aren't the one we requested - if (group.name() != location_key) continue; - - ELLPath path_index = (ELLPath)group.path_index(); - if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) - { - LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; - return false; - } - - for (const SettingsFile& file : group.files) - { - LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() - << " - from location " << location_key << LL_ENDL; - - auto settings_group = LLControlGroup::getInstance(file.name); - if(!settings_group) - { - LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; - continue; - } - - std::string full_settings_path; - - if (file.file_name_setting.isProvided() - && gSavedSettings.controlExists(file.file_name_setting)) - { - // try to find filename stored in file_name_setting control - full_settings_path = gSavedSettings.getString(file.file_name_setting); - if (full_settings_path.empty()) - { - continue; - } - else if (!gDirUtilp->fileExists(full_settings_path)) - { - // search in default path - full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path); - } - } - else - { - // by default, use specified file name - full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); - } - - if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) - { // success! - LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; - } - else - { // failed to load - if(file.required) - { + if (!mSettingsLocationList) + { + LL_ERRS() << "Invalid settings location list" << LL_ENDL; + } + + for (const SettingsGroup& group : mSettingsLocationList->groups) + { + // skip settings groups that aren't the one we requested + if (group.name() != location_key) continue; + + ELLPath path_index = (ELLPath)group.path_index(); + if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) + { + LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; + return false; + } + + for (const SettingsFile& file : group.files) + { + LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() + << " - from location " << location_key << LL_ENDL; + + auto settings_group = LLControlGroup::getInstance(file.name); + if(!settings_group) + { + LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; + continue; + } + + std::string full_settings_path; + + if (file.file_name_setting.isProvided() + && gSavedSettings.controlExists(file.file_name_setting)) + { + // try to find filename stored in file_name_setting control + full_settings_path = gSavedSettings.getString(file.file_name_setting); + if (full_settings_path.empty()) + { + continue; + } + else if (!gDirUtilp->fileExists(full_settings_path)) + { + // search in default path + full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path); + } + } + else + { + // by default, use specified file name + full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); + } + + if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) + { // success! + LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; + } + else + { // failed to load + if(file.required) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; - return false; - } - else - { - // only complain if we actually have a filename at this point - if (!full_settings_path.empty()) - { - LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; - } - } - } - } - } - - return true; + LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; + return false; + } + else + { + // only complain if we actually have a filename at this point + if (!full_settings_path.empty()) + { + LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; + } + } + } + } + } + + return true; } std::string LLAppViewer::getSettingsFilename(const std::string& location_key, - const std::string& file) + const std::string& file) { - for (const SettingsGroup& group : mSettingsLocationList->groups) - { - if (group.name() == location_key) - { - for (const SettingsFile& settings_file : group.files) - { - if (settings_file.name() == file) - { - return settings_file.file_name; - } - } - } - } - - return std::string(); + for (const SettingsGroup& group : mSettingsLocationList->groups) + { + if (group.name() == location_key) + { + for (const SettingsFile& settings_file : group.files) + { + if (settings_file.name() == file) + { + return settings_file.file_name; + } + } + } + } + + return std::string(); } void LLAppViewer::loadColorSettings() { - LLUIColorTable::instance().loadFromSettings(); + LLUIColorTable::instance().loadFromSettings(); } namespace { void handleCommandLineError(LLControlGroupCLP& clp) { - LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; + LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; - LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; + LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; - OSMessageBox(STRINGIZE(LLTrans::getString("MBCmdLineError") << clp.getErrorMessage()), - LLStringUtil::null, - OSMB_OK); + OSMessageBox(STRINGIZE(LLTrans::getString("MBCmdLineError") << clp.getErrorMessage()), + LLStringUtil::null, + OSMB_OK); } } // anonymous namespace @@ -2510,42 +2510,42 @@ namespace // Name can be specified as "<control_group>.<control_name>", with default group being Global. bool tempSetControl(const std::string& name, const std::string& value) { - std::string name_part; - std::string group_part; - LLControlVariable* control = NULL; - - // Name can be further split into ControlGroup.Name, with the default control group being Global - size_t pos = name.find('.'); - if (pos != std::string::npos) - { - group_part = name.substr(0, pos); - name_part = name.substr(pos+1); - LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; - auto g = LLControlGroup::getInstance(group_part); - if (g) control = g->getControl(name_part); - } - else - { - LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; - control = gSavedSettings.getControl(name); - } - - if (control) - { - control->setValue(value, false); - return true; - } - return false; + std::string name_part; + std::string group_part; + LLControlVariable* control = NULL; + + // Name can be further split into ControlGroup.Name, with the default control group being Global + size_t pos = name.find('.'); + if (pos != std::string::npos) + { + group_part = name.substr(0, pos); + name_part = name.substr(pos+1); + LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; + auto g = LLControlGroup::getInstance(group_part); + if (g) control = g->getControl(name_part); + } + else + { + LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; + control = gSavedSettings.getControl(name); + } + + if (control) + { + control->setValue(value, false); + return true; + } + return false; } bool LLAppViewer::initConfiguration() { - //Load settings files list - std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); - LLXMLNodePtr root; - BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL); - if (!success) - { + //Load settings files list + std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); + LLXMLNodePtr root; + BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL); + if (!success) + { LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL; LLError::LLUserWarningMsg::showMissingFiles(); if (gDirUtilp->fileExists(settings_file_list)) @@ -2562,175 +2562,175 @@ bool LLAppViewer::initConfiguration() << "and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; } - } + } - mSettingsLocationList = new SettingsFiles(); + mSettingsLocationList = new SettingsFiles(); - LLXUIParser parser; - parser.readXUI(root, *mSettingsLocationList, settings_file_list); + LLXUIParser parser; + parser.readXUI(root, *mSettingsLocationList, settings_file_list); - if (!mSettingsLocationList->validateBlock()) - { + if (!mSettingsLocationList->validateBlock()) + { LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Invalid settings file list " << settings_file_list << LL_ENDL; - } - - // The settings and command line parsing have a fragile - // order-of-operation: - // - load defaults from app_settings - // - set procedural settings values - // - read command line settings - // - selectively apply settings needed to load user settings. + } + + // The settings and command line parsing have a fragile + // order-of-operation: + // - load defaults from app_settings + // - set procedural settings values + // - read command line settings + // - selectively apply settings needed to load user settings. // - load overrides from user_settings - // - apply command line settings (to override the overrides) - // - load per account settings (happens in llstartup - - // - load defaults - bool set_defaults = true; - if(!loadSettingsFromDirectory("Default", set_defaults)) - { - OSMessageBox( - "Unable to load default settings file. The installation may be corrupted.", - LLStringUtil::null,OSMB_OK); - return false; - } - - initStrings(); // setup paths for LLTrans based on settings files only - // - set procedural settings - // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet - gSavedSettings.setString("ClientSettingsFile", + // - apply command line settings (to override the overrides) + // - load per account settings (happens in llstartup + + // - load defaults + bool set_defaults = true; + if(!loadSettingsFromDirectory("Default", set_defaults)) + { + OSMessageBox( + "Unable to load default settings file. The installation may be corrupted.", + LLStringUtil::null,OSMB_OK); + return false; + } + + initStrings(); // setup paths for LLTrans based on settings files only + // - set procedural settings + // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet + gSavedSettings.setString("ClientSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); -#ifndef LL_RELEASE_FOR_DOWNLOAD - // provide developer build only overrides for these control variables that are not - // persisted to settings.xml - LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); - if (c) - { - c->setValue(true, false); - } - - gSavedSettings.setBOOL("QAMode", TRUE ); - gSavedSettings.setS32("WatchdogEnabled", 0); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // provide developer build only overrides for these control variables that are not + // persisted to settings.xml + LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); + if (c) + { + c->setValue(true, false); + } + + gSavedSettings.setBOOL("QAMode", TRUE ); + gSavedSettings.setS32("WatchdogEnabled", 0); #endif - // These are warnings that appear on the first experience of that condition. - // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse - // for disable/reset ability -// LLFirstUse::addConfigVariable("FirstBalanceIncrease"); -// LLFirstUse::addConfigVariable("FirstBalanceDecrease"); -// LLFirstUse::addConfigVariable("FirstSit"); -// LLFirstUse::addConfigVariable("FirstMap"); -// LLFirstUse::addConfigVariable("FirstGoTo"); -// LLFirstUse::addConfigVariable("FirstBuild"); -// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); -// LLFirstUse::addConfigVariable("FirstTeleport"); -// LLFirstUse::addConfigVariable("FirstOverrideKeys"); -// LLFirstUse::addConfigVariable("FirstAttach"); -// LLFirstUse::addConfigVariable("FirstAppearance"); -// LLFirstUse::addConfigVariable("FirstInventory"); -// LLFirstUse::addConfigVariable("FirstSandbox"); -// LLFirstUse::addConfigVariable("FirstFlexible"); -// LLFirstUse::addConfigVariable("FirstDebugMenus"); -// LLFirstUse::addConfigVariable("FirstSculptedPrim"); -// LLFirstUse::addConfigVariable("FirstVoice"); -// LLFirstUse::addConfigVariable("FirstMedia"); - - // - read command line settings. - 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)) - { - handleCommandLineError(clp); - return false; - } - - // - selectively apply settings - - // If the user has specified a alternate settings file name. - // Load it now before loading the user_settings/settings.xml - if(clp.hasOption("settings")) - { - std::string user_settings_filename = - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - clp.getOption("settings")[0]); - gSavedSettings.setString("ClientSettingsFile", user_settings_filename); - LL_INFOS("Settings") << "Using command line specified settings filename: " - << user_settings_filename << LL_ENDL; - } - - // - load overrides from user_settings - loadSettingsFromDirectory("User"); - - if (gSavedSettings.getBOOL("FirstRunThisInstall")) - { - // Set firstrun flag to indicate that some further init actiona should be taken - // like determining screen DPI value and so on - mIsFirstRun = true; - - gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); - } - - if (clp.hasOption("sessionsettings")) - { - std::string session_settings_filename = clp.getOption("sessionsettings")[0]; - gSavedSettings.setString("SessionSettingsFile", session_settings_filename); - LL_INFOS("Settings") << "Using session settings filename: " - << session_settings_filename << LL_ENDL; - } - loadSettingsFromDirectory("Session"); - - if (clp.hasOption("usersessionsettings")) - { - std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0]; - gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename); - LL_INFOS("Settings") << "Using user session settings filename: " - << user_session_settings_filename << LL_ENDL; - - } - loadSettingsFromDirectory("UserSession"); - - // - apply command line settings - if (! clp.notify()) - { - handleCommandLineError(clp); - return false; - } - - // Register the core crash option as soon as we can - // if we want gdb post-mortem on cores we need to be up and running - // ASAP or we might miss init issue etc. - if(gSavedSettings.getBOOL("DisableCrashLogger")) - { - LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << LL_ENDL; - disableCrashlogger(); - } - - gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); - // Handle initialization from settings. - // Start up the debugging console before handling other options. - if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) - { - initConsole(); - } - - if(clp.hasOption("help")) - { - std::ostringstream msg; - msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; - LL_INFOS() << msg.str() << LL_ENDL; - - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - - return false; - } + // These are warnings that appear on the first experience of that condition. + // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse + // for disable/reset ability +// LLFirstUse::addConfigVariable("FirstBalanceIncrease"); +// LLFirstUse::addConfigVariable("FirstBalanceDecrease"); +// LLFirstUse::addConfigVariable("FirstSit"); +// LLFirstUse::addConfigVariable("FirstMap"); +// LLFirstUse::addConfigVariable("FirstGoTo"); +// LLFirstUse::addConfigVariable("FirstBuild"); +// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); +// LLFirstUse::addConfigVariable("FirstTeleport"); +// LLFirstUse::addConfigVariable("FirstOverrideKeys"); +// LLFirstUse::addConfigVariable("FirstAttach"); +// LLFirstUse::addConfigVariable("FirstAppearance"); +// LLFirstUse::addConfigVariable("FirstInventory"); +// LLFirstUse::addConfigVariable("FirstSandbox"); +// LLFirstUse::addConfigVariable("FirstFlexible"); +// LLFirstUse::addConfigVariable("FirstDebugMenus"); +// LLFirstUse::addConfigVariable("FirstSculptedPrim"); +// LLFirstUse::addConfigVariable("FirstVoice"); +// LLFirstUse::addConfigVariable("FirstMedia"); + + // - read command line settings. + 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)) + { + handleCommandLineError(clp); + return false; + } + + // - selectively apply settings + + // If the user has specified a alternate settings file name. + // Load it now before loading the user_settings/settings.xml + if(clp.hasOption("settings")) + { + std::string user_settings_filename = + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + clp.getOption("settings")[0]); + gSavedSettings.setString("ClientSettingsFile", user_settings_filename); + LL_INFOS("Settings") << "Using command line specified settings filename: " + << user_settings_filename << LL_ENDL; + } + + // - load overrides from user_settings + loadSettingsFromDirectory("User"); + + if (gSavedSettings.getBOOL("FirstRunThisInstall")) + { + // Set firstrun flag to indicate that some further init actiona should be taken + // like determining screen DPI value and so on + mIsFirstRun = true; + + gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); + } + + if (clp.hasOption("sessionsettings")) + { + std::string session_settings_filename = clp.getOption("sessionsettings")[0]; + gSavedSettings.setString("SessionSettingsFile", session_settings_filename); + LL_INFOS("Settings") << "Using session settings filename: " + << session_settings_filename << LL_ENDL; + } + loadSettingsFromDirectory("Session"); + + if (clp.hasOption("usersessionsettings")) + { + std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0]; + gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename); + LL_INFOS("Settings") << "Using user session settings filename: " + << user_session_settings_filename << LL_ENDL; + + } + loadSettingsFromDirectory("UserSession"); + + // - apply command line settings + if (! clp.notify()) + { + handleCommandLineError(clp); + return false; + } + + // Register the core crash option as soon as we can + // if we want gdb post-mortem on cores we need to be up and running + // ASAP or we might miss init issue etc. + if(gSavedSettings.getBOOL("DisableCrashLogger")) + { + LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << LL_ENDL; + disableCrashlogger(); + } + + gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); + // Handle initialization from settings. + // Start up the debugging console before handling other options. + if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) + { + initConsole(); + } + + if(clp.hasOption("help")) + { + std::ostringstream msg; + msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; + LL_INFOS() << msg.str() << LL_ENDL; + + OSMessageBox( + msg.str(), + LLStringUtil::null, + OSMB_OK); + + return false; + } if(clp.hasOption("set")) { @@ -2748,43 +2748,43 @@ bool LLAppViewer::initConfiguration() const std::string& value = *(++itr); if (!tempSetControl(name,value)) { - LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; + LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; } } } } if (clp.hasOption("logevents")) { - LLViewerEventRecorder::instance().setEventLoggingOn(); + LLViewerEventRecorder::instance().setEventLoggingOn(); } - std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); - if(! CmdLineChannel.empty()) + std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); + if(! CmdLineChannel.empty()) { - LLVersionInfo::instance().resetChannel(CmdLineChannel); - } + LLVersionInfo::instance().resetChannel(CmdLineChannel); + } - // If we have specified crash on startup, set the global so we'll trigger the crash at the right time - gCrashOnStartup = gSavedSettings.getBOOL("CrashOnStartup"); + // If we have specified crash on startup, set the global so we'll trigger the crash at the right time + gCrashOnStartup = gSavedSettings.getBOOL("CrashOnStartup"); - if (gSavedSettings.getBOOL("LogPerformance")) - { - LLTrace::BlockTimer::sLog = true; - LLTrace::BlockTimer::sLogName = std::string("performance"); - } + if (gSavedSettings.getBOOL("LogPerformance")) + { + LLTrace::BlockTimer::sLog = true; + LLTrace::BlockTimer::sLogName = std::string("performance"); + } - std::string test_name(gSavedSettings.getString("LogMetrics")); - if (! test_name.empty()) - { - LLTrace::BlockTimer::sMetricLog = TRUE; - // '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test - // In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...) - LL_INFOS() << "'--logmetrics' argument : " << test_name << LL_ENDL; - LLTrace::BlockTimer::sLogName = test_name; - } + std::string test_name(gSavedSettings.getString("LogMetrics")); + if (! test_name.empty()) + { + LLTrace::BlockTimer::sMetricLog = TRUE; + // '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test + // In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...) + LL_INFOS() << "'--logmetrics' argument : " << test_name << LL_ENDL; + LLTrace::BlockTimer::sLogName = test_name; + } - if (clp.hasOption("graphicslevel")) - { + if (clp.hasOption("graphicslevel")) + { // User explicitly requested --graphicslevel on the command line. We // expect this switch has already set RenderQualityPerformance. Check // that value for validity later. @@ -2793,18 +2793,18 @@ bool LLAppViewer::initConfiguration() // will call LLFeatureManager::applyRecommendedSettings(), which // overwrites this settings variable! mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance"); - } + } - LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); - gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); + LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); + gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); - if (gSavedSettings.getBOOL("DebugSession")) - { - gDebugSession = TRUE; - gDebugGL = TRUE; + if (gSavedSettings.getBOOL("DebugSession")) + { + gDebugSession = TRUE; + gDebugGL = TRUE; - ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); - } + ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); + } if (gSavedSettings.getBOOL("RenderDebugGLSession")) { @@ -2815,47 +2815,47 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setBOOL("RenderDebugGLSession", FALSE); } - const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); - if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) - { - // Examining "Language" may not suffice -- see LLUI::getLanguage() - // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much - // good because we haven't yet called LLUI::initClass(). - gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), - gSavedSettings.getString("Language")); - } - - if (gSavedSettings.getBOOL("SpellCheck")) - { - std::list<std::string> dict_list; - std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); - boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); - if (!dict_list.empty()) - { - LLSpellChecker::setUseSpellCheck(dict_list.front()); - dict_list.pop_front(); - LLSpellChecker::instance().setSecondaryDictionaries(dict_list); - } - } - - if (gNonInteractive) - { - tempSetControl("AllowMultipleViewers", "TRUE"); - tempSetControl("SLURLPassToOtherInstance", "FALSE"); - tempSetControl("RenderWater", "FALSE"); - tempSetControl("FlyingAtExit", "FALSE"); - tempSetControl("WindowWidth", "1024"); - tempSetControl("WindowHeight", "200"); - LLError::setEnabledLogTypesMask(0); - llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); - } - - - // Handle slurl use. NOTE: Don't let SL-55321 reappear. - // This initial-SLURL logic, up through the call to - // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- - // because if sendURLToOtherInstance() succeeds, we take a fast exit, - // SKIPPING the splash screen and everything else. + const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); + if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) + { + // Examining "Language" may not suffice -- see LLUI::getLanguage() + // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much + // good because we haven't yet called LLUI::initClass(). + gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), + gSavedSettings.getString("Language")); + } + + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list<std::string> dict_list; + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + } + } + + if (gNonInteractive) + { + tempSetControl("AllowMultipleViewers", "TRUE"); + tempSetControl("SLURLPassToOtherInstance", "FALSE"); + tempSetControl("RenderWater", "FALSE"); + tempSetControl("FlyingAtExit", "FALSE"); + tempSetControl("WindowWidth", "1024"); + tempSetControl("WindowHeight", "200"); + LLError::setEnabledLogTypesMask(0); + llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); + } + + + // Handle slurl use. NOTE: Don't let SL-55321 reappear. + // This initial-SLURL logic, up through the call to + // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- + // because if sendURLToOtherInstance() succeeds, we take a fast exit, + // SKIPPING the splash screen and everything else. // *FIX: This init code should be made more robust to prevent // the issue SL-55321 from returning. One thought is to allow @@ -2873,143 +2873,143 @@ bool LLAppViewer::initConfiguration() // other browsers) and do the rough equivalent of command // injection and steal passwords. Phoenix. SL-55321 - std::string starting_location; - - std::string cmd_line_login_location(gSavedSettings.getString("CmdLineLoginLocation")); - if(! cmd_line_login_location.empty()) - { - starting_location = cmd_line_login_location; - } - else - { - std::string default_login_location(gSavedSettings.getString("DefaultLoginLocation")); - if (! default_login_location.empty()) - { - starting_location = default_login_location; - } - } - - LLSLURL start_slurl; - if (! starting_location.empty()) - { - start_slurl = starting_location; - LLStartUp::setStartSLURL(start_slurl); - if(start_slurl.getType() == LLSLURL::LOCATION) - { - LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); - } - } - - // NextLoginLocation is set as a side effect of LLStartUp::setStartSLURL() - std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); - if ( !nextLoginLocation.empty() ) - { - LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL; - LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation)); - } - else if ( ( clp.hasOption("login") || clp.hasOption("autologin")) - && gSavedSettings.getString("CmdLineLoginLocation").empty()) - { - // If automatic login from command line with --login switch - // init StartSLURL location. - std::string start_slurl_setting = gSavedSettings.getString("LoginLocation"); - LL_DEBUGS("AppInit") << "start slurl setting '" << start_slurl_setting << "'" << LL_ENDL; - LLStartUp::setStartSLURL(LLSLURL(start_slurl_setting)); - } - else - { - // the login location will be set by the login panel (see LLPanelLogin) - } - - //RN: if we received a URL, hand it off to the existing instance. - // don't call anotherInstanceRunning() when doing URL handoff, as - // it relies on checking a marker file which will not work when running - // out of different directories - - if (start_slurl.isValid() && - (gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) - { - if (sendURLToOtherInstance(start_slurl.getSLURLString())) - { - // successfully handed off URL to existing instance, exit - return false; - } - } - - // Display splash screen. Must be after above check for previous - // crash as this dialog is always frontmost. - std::string splash_msg; - LLStringUtil::format_map_t args; - args["[APP_NAME]"] = LLTrans::getString("SECOND_LIFE"); - splash_msg = LLTrans::getString("StartupLoading", args); - LLSplashScreen::show(); - LLSplashScreen::update(splash_msg); - - //LLVolumeMgr::initClass(); - LLVolumeMgr* volume_manager = new LLVolumeMgr(); - volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled - LLPrimitive::setVolumeManager(volume_manager); - - // Note: this is where we used to initialize gFeatureManagerp. - - gStartTime = totalTime(); - - // - // Set the name of the window - // - gWindowTitle = LLTrans::getString("APP_NAME"); + std::string starting_location; + + std::string cmd_line_login_location(gSavedSettings.getString("CmdLineLoginLocation")); + if(! cmd_line_login_location.empty()) + { + starting_location = cmd_line_login_location; + } + else + { + std::string default_login_location(gSavedSettings.getString("DefaultLoginLocation")); + if (! default_login_location.empty()) + { + starting_location = default_login_location; + } + } + + LLSLURL start_slurl; + if (! starting_location.empty()) + { + start_slurl = starting_location; + LLStartUp::setStartSLURL(start_slurl); + if(start_slurl.getType() == LLSLURL::LOCATION) + { + LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); + } + } + + // NextLoginLocation is set as a side effect of LLStartUp::setStartSLURL() + std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); + if ( !nextLoginLocation.empty() ) + { + LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL; + LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation)); + } + else if ( ( clp.hasOption("login") || clp.hasOption("autologin")) + && gSavedSettings.getString("CmdLineLoginLocation").empty()) + { + // If automatic login from command line with --login switch + // init StartSLURL location. + std::string start_slurl_setting = gSavedSettings.getString("LoginLocation"); + LL_DEBUGS("AppInit") << "start slurl setting '" << start_slurl_setting << "'" << LL_ENDL; + LLStartUp::setStartSLURL(LLSLURL(start_slurl_setting)); + } + else + { + // the login location will be set by the login panel (see LLPanelLogin) + } + + //RN: if we received a URL, hand it off to the existing instance. + // don't call anotherInstanceRunning() when doing URL handoff, as + // it relies on checking a marker file which will not work when running + // out of different directories + + if (start_slurl.isValid() && + (gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) + { + if (sendURLToOtherInstance(start_slurl.getSLURLString())) + { + // successfully handed off URL to existing instance, exit + return false; + } + } + + // Display splash screen. Must be after above check for previous + // crash as this dialog is always frontmost. + std::string splash_msg; + LLStringUtil::format_map_t args; + args["[APP_NAME]"] = LLTrans::getString("SECOND_LIFE"); + splash_msg = LLTrans::getString("StartupLoading", args); + LLSplashScreen::show(); + LLSplashScreen::update(splash_msg); + + //LLVolumeMgr::initClass(); + LLVolumeMgr* volume_manager = new LLVolumeMgr(); + volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled + LLPrimitive::setVolumeManager(volume_manager); + + // Note: this is where we used to initialize gFeatureManagerp. + + gStartTime = totalTime(); + + // + // Set the name of the window + // + gWindowTitle = LLTrans::getString("APP_NAME"); #if LL_DEBUG - gWindowTitle += std::string(" [DEBUG]"); + gWindowTitle += std::string(" [DEBUG]"); #endif - if (!gArgs.empty()) - { - gWindowTitle += std::string(" ") + gArgs; - } - LLStringUtil::truncate(gWindowTitle, 255); - - // - // Check for another instance of the app running - // This happens AFTER LLSplashScreen::show(). That may or may not be - // important. - // - if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) - { - OSMessageBox( - LLTrans::getString("MBAlreadyRunning"), - LLStringUtil::null, - OSMB_OK); - return false; - } - - if (mSecondInstance) - { - // This is the second instance of SL. Mute voice, - // but make sure the setting is *not* persisted. - // Also see LLVivoxVoiceClient::voiceEnabled() - LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); - if(enable_voice) - { - const BOOL DO_NOT_PERSIST = FALSE; - enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); - } - } - - gLastRunVersion = gSavedSettings.getString("LastRunVersion"); - - loadColorSettings(); - - // Let anyone else who cares know that we've populated our settings - // variables. - for (const auto& key : LLControlGroup::key_snapshot()) - { - // For each named instance of LLControlGroup, send an event saying - // we've initialized an LLControlGroup instance by that name. - LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); - } + if (!gArgs.empty()) + { + gWindowTitle += std::string(" ") + gArgs; + } + LLStringUtil::truncate(gWindowTitle, 255); + + // + // Check for another instance of the app running + // This happens AFTER LLSplashScreen::show(). That may or may not be + // important. + // + if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) + { + OSMessageBox( + LLTrans::getString("MBAlreadyRunning"), + LLStringUtil::null, + OSMB_OK); + return false; + } + + if (mSecondInstance) + { + // This is the second instance of SL. Mute voice, + // but make sure the setting is *not* persisted. + // Also see LLVivoxVoiceClient::voiceEnabled() + LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); + if(enable_voice) + { + const BOOL DO_NOT_PERSIST = FALSE; + enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); + } + } + + gLastRunVersion = gSavedSettings.getString("LastRunVersion"); + + loadColorSettings(); + + // Let anyone else who cares know that we've populated our settings + // variables. + for (const auto& key : LLControlGroup::key_snapshot()) + { + // For each named instance of LLControlGroup, send an event saying + // we've initialized an LLControlGroup instance by that name. + LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); + } LLError::LLUserWarningMsg::setOutOfMemoryStrings(LLTrans::getString("MBOutOfMemoryTitle"), LLTrans::getString("MBOutOfMemoryErr")); - return true; // Config was successful. + return true; // Config was successful. } // The following logic is replicated in initConfiguration() (to be able to get @@ -3018,214 +3018,214 @@ bool LLAppViewer::initConfiguration() // keeps growing, necessitating a method all its own. void LLAppViewer::initStrings() { - std::string strings_file = "strings.xml"; - std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); - if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) - { - if (strings_path_full.empty()) - { - LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; - } - else - { - llstat st; - int rc = LLFile::stat(strings_path_full, &st); - if (rc != 0) - { - LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; - } - else if (S_ISDIR(st.st_mode)) - { - LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; - } - else - { - LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; - } - } - - // initial check to make sure files are there failed - gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); + std::string strings_file = "strings.xml"; + std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); + if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) + { + if (strings_path_full.empty()) + { + LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; + } + else + { + llstat st; + int rc = LLFile::stat(strings_path_full, &st); + if (rc != 0) + { + LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; + } + else if (S_ISDIR(st.st_mode)) + { + LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; + } + else + { + LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; + } + } + + // initial check to make sure files are there failed + gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Viewer failed to find localization and UI files." - << " Please reinstall viewer from https://secondlife.com/support/downloads" - << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; - } - LLTransUtil::parseStrings(strings_file, default_trans_args); - LLTransUtil::parseLanguageStrings("language_settings.xml"); - - // parseStrings() sets up the LLTrans substitution table. Add this one item. - LLTrans::setDefaultArg("[sourceid]", gSavedSettings.getString("sourceid")); - - // Now that we've set "[sourceid]", have to go back through - // default_trans_args and reinitialize all those other keys because some - // of them, in turn, reference "[sourceid]". - for (const std::string& key : default_trans_args) - { - std::string brackets(key), nobrackets(key); - // Invalid to inspect key[0] if key is empty(). But then, the entire - // body of this loop is pointless if key is empty(). - if (key.empty()) - continue; - - if (key[0] != '[') - { - // key was passed without brackets. That means that 'nobrackets' - // is correct but 'brackets' is not. - brackets = STRINGIZE('[' << brackets << ']'); - } - else - { - // key was passed with brackets. That means that 'brackets' is - // correct but 'nobrackets' is not. Erase the left bracket. - nobrackets.erase(0, 1); - std::string::size_type length(nobrackets.length()); - if (length && nobrackets[length - 1] == ']') - { - nobrackets.erase(length - 1); - } - } - // Calling LLTrans::getString() is what embeds the other default - // translation strings into this one. - LLTrans::setDefaultArg(brackets, LLTrans::getString(nobrackets)); - } + LL_ERRS() << "Viewer failed to find localization and UI files." + << " Please reinstall viewer from https://secondlife.com/support/downloads" + << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; + } + LLTransUtil::parseStrings(strings_file, default_trans_args); + LLTransUtil::parseLanguageStrings("language_settings.xml"); + + // parseStrings() sets up the LLTrans substitution table. Add this one item. + LLTrans::setDefaultArg("[sourceid]", gSavedSettings.getString("sourceid")); + + // Now that we've set "[sourceid]", have to go back through + // default_trans_args and reinitialize all those other keys because some + // of them, in turn, reference "[sourceid]". + for (const std::string& key : default_trans_args) + { + std::string brackets(key), nobrackets(key); + // Invalid to inspect key[0] if key is empty(). But then, the entire + // body of this loop is pointless if key is empty(). + if (key.empty()) + continue; + + if (key[0] != '[') + { + // key was passed without brackets. That means that 'nobrackets' + // is correct but 'brackets' is not. + brackets = STRINGIZE('[' << brackets << ']'); + } + else + { + // key was passed with brackets. That means that 'brackets' is + // correct but 'nobrackets' is not. Erase the left bracket. + nobrackets.erase(0, 1); + std::string::size_type length(nobrackets.length()); + if (length && nobrackets[length - 1] == ']') + { + nobrackets.erase(length - 1); + } + } + // Calling LLTrans::getString() is what embeds the other default + // translation strings into this one. + LLTrans::setDefaultArg(brackets, LLTrans::getString(nobrackets)); + } } bool LLAppViewer::meetsRequirementsForMaximizedStart() { bool maximizedOk = (gSysMemory.getPhysicalMemoryKB() >= U32Gigabytes(1)); - return maximizedOk; + return maximizedOk; } bool LLAppViewer::initWindow() { - LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; - - // store setting in a global for easy access and modification - gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); - - // always start windowed - BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); - - LLViewerWindow::Params window_params; - window_params - .title(gWindowTitle) - .name(VIEWER_WINDOW_CLASSNAME) - .x(gSavedSettings.getS32("WindowX")) - .y(gSavedSettings.getS32("WindowY")) - .width(gSavedSettings.getU32("WindowWidth")) - .height(gSavedSettings.getU32("WindowHeight")) - .min_width(gSavedSettings.getU32("MinWindowWidth")) - .min_height(gSavedSettings.getU32("MinWindowHeight")) - .fullscreen(gSavedSettings.getBOOL("FullScreen")) - .ignore_pixel_depth(ignorePixelDepth) - .first_run(mIsFirstRun); - - gViewerWindow = new LLViewerWindow(window_params); - - LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL; - - // Need to load feature table before cheking to start watchdog. - bool use_watchdog = false; - int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled"); - if (watchdog_enabled_setting == -1) - { - use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled"); - } - else - { - // The user has explicitly set this setting; always use that value. - use_watchdog = bool(watchdog_enabled_setting); - } - - LL_INFOS("AppInit") << "watchdog" - << (use_watchdog ? " " : " NOT ") - << "enabled" - << " (setting = " << watchdog_enabled_setting << ")" - << LL_ENDL; - - if (use_watchdog) - { - LLWatchdog::getInstance()->init(); - } - - LLNotificationsUI::LLNotificationManager::getInstance(); + LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; + + // store setting in a global for easy access and modification + gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); + + // always start windowed + BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); + + LLViewerWindow::Params window_params; + window_params + .title(gWindowTitle) + .name(VIEWER_WINDOW_CLASSNAME) + .x(gSavedSettings.getS32("WindowX")) + .y(gSavedSettings.getS32("WindowY")) + .width(gSavedSettings.getU32("WindowWidth")) + .height(gSavedSettings.getU32("WindowHeight")) + .min_width(gSavedSettings.getU32("MinWindowWidth")) + .min_height(gSavedSettings.getU32("MinWindowHeight")) + .fullscreen(gSavedSettings.getBOOL("FullScreen")) + .ignore_pixel_depth(ignorePixelDepth) + .first_run(mIsFirstRun); + + gViewerWindow = new LLViewerWindow(window_params); + + LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL; + + // Need to load feature table before cheking to start watchdog. + bool use_watchdog = false; + int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled"); + if (watchdog_enabled_setting == -1) + { + use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled"); + } + else + { + // The user has explicitly set this setting; always use that value. + use_watchdog = bool(watchdog_enabled_setting); + } + + LL_INFOS("AppInit") << "watchdog" + << (use_watchdog ? " " : " NOT ") + << "enabled" + << " (setting = " << watchdog_enabled_setting << ")" + << LL_ENDL; + + if (use_watchdog) + { + LLWatchdog::getInstance()->init(); + } + + LLNotificationsUI::LLNotificationManager::getInstance(); #ifdef LL_DARWIN - //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) - LLOSInfo& os_info = LLOSInfo::instance(); - if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) - { - if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) - gViewerWindow->getWindow()->setOldResize(true); - } + //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) + LLOSInfo& os_info = LLOSInfo::instance(); + if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) + { + if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) + gViewerWindow->getWindow()->setOldResize(true); + } #endif - if (gSavedSettings.getBOOL("WindowMaximized")) - { - gViewerWindow->getWindow()->maximize(); - } + if (gSavedSettings.getBOOL("WindowMaximized")) + { + gViewerWindow->getWindow()->maximize(); + } - // - // Initialize GL stuff - // + // + // Initialize GL stuff + // - if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) - { - LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false); - gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel); - } + if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) + { + LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false); + gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel); + } - // Set this flag in case we crash while initializing GL - gSavedSettings.setBOOL("RenderInitError", TRUE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); + // Set this flag in case we crash while initializing GL + gSavedSettings.setBOOL("RenderInitError", TRUE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - gPipeline.init(); - LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; + gPipeline.init(); + LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; - stop_glerror(); - gViewerWindow->initGLDefaults(); + stop_glerror(); + gViewerWindow->initGLDefaults(); - gSavedSettings.setBOOL("RenderInitError", FALSE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); + gSavedSettings.setBOOL("RenderInitError", FALSE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - //If we have a startup crash, it's usually near GL initialization, so simulate that. - if(gCrashOnStartup) - { - LLAppViewer::instance()->forceErrorLLError(); - } + //If we have a startup crash, it's usually near GL initialization, so simulate that. + if(gCrashOnStartup) + { + LLAppViewer::instance()->forceErrorLLError(); + } - // - // Determine if the window should start maximized on initial run based - // on graphics capability - // - if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart()) - { - LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL; - gSavedSettings.setBOOL("WindowMaximized", TRUE); - } + // + // Determine if the window should start maximized on initial run based + // on graphics capability + // + if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart()) + { + LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL; + gSavedSettings.setBOOL("WindowMaximized", TRUE); + } - if (gSavedSettings.getBOOL("WindowMaximized")) - { - gViewerWindow->getWindow()->maximize(); - } + if (gSavedSettings.getBOOL("WindowMaximized")) + { + gViewerWindow->getWindow()->maximize(); + } - LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); + LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); - // Show watch cursor - gViewerWindow->setCursor(UI_CURSOR_WAIT); + // Show watch cursor + gViewerWindow->setCursor(UI_CURSOR_WAIT); - // Finish view initialization - gViewerWindow->initBase(); + // Finish view initialization + gViewerWindow->initBase(); - // show viewer window - //gViewerWindow->getWindow()->show(); + // show viewer window + //gViewerWindow->getWindow()->show(); - LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; + LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; - return true; + return true; } bool LLAppViewer::isUpdaterMissing() @@ -3264,28 +3264,28 @@ void LLAppViewer::writeDebugInfo(bool isStatic) LLSD LLAppViewer::getViewerInfo() const { - // The point of having one method build an LLSD info block and the other - // construct the user-visible About string is to ensure that the same info - // is available to a getInfo() caller as to the user opening - // LLFloaterAbout. - LLSD info; - auto& versionInfo(LLVersionInfo::instance()); - // With GitHub builds, the build number is too big to fit in a 32-bit int, - // and LLSD doesn't deal with integers wider than int. Use string. - info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), - versionInfo.getPatch(), stringize(versionInfo.getBuild())); - info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); - info["CHANNEL"] = versionInfo.getChannel(); - info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = versionInfo.getBuildConfig(); - if (build_config != "Release") - { - info["BUILD_CONFIG"] = build_config; - } - - // return a URL to the release notes for this viewer, such as: - // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html - std::string url = versionInfo.getReleaseNotes(); // VVM supplied + // The point of having one method build an LLSD info block and the other + // construct the user-visible About string is to ensure that the same info + // is available to a getInfo() caller as to the user opening + // LLFloaterAbout. + LLSD info; + auto& versionInfo(LLVersionInfo::instance()); + // With GitHub builds, the build number is too big to fit in a 32-bit int, + // and LLSD doesn't deal with integers wider than int. Use string. + info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), + versionInfo.getPatch(), stringize(versionInfo.getBuild())); + info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); + info["CHANNEL"] = versionInfo.getChannel(); + info["ADDRESS_SIZE"] = ADDRESS_SIZE; + std::string build_config = versionInfo.getBuildConfig(); + if (build_config != "Release") + { + info["BUILD_CONFIG"] = build_config; + } + + // return a URL to the release notes for this viewer, such as: + // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html + std::string url = versionInfo.getReleaseNotes(); // VVM supplied if (url.empty()) { url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); @@ -3293,32 +3293,32 @@ LLSD LLAppViewer::getViewerInfo() const url += "/"; url += LLURI::escape(versionInfo.getVersion()) + ".html"; } - info["VIEWER_RELEASE_NOTES_URL"] = url; - - // Position - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - LLVector3d pos = gAgent.getPositionGlobal(); - info["POSITION"] = ll_sd_from_vector3d(pos); - info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); - - boost::regex regex("\\.(secondlife|lindenlab)\\..*"); - info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); - info["SERVER_VERSION"] = gLastVersionChannel; - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - info["SLURL"] = slurl.getSLURLString(); - } - - // CPU - info["CPU"] = gSysCPU.getCPUString(); - info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits<LLUnits::Megabytes>()); - // Moved hack adjustment to Windows memory size into llsys.cpp - info["OS_VERSION"] = LLOSInfo::instance().getOSString(); - info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); - info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); + info["VIEWER_RELEASE_NOTES_URL"] = url; + + // Position + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLVector3d pos = gAgent.getPositionGlobal(); + info["POSITION"] = ll_sd_from_vector3d(pos); + info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); + info["REGION"] = gAgent.getRegion()->getName(); + + boost::regex regex("\\.(secondlife|lindenlab)\\..*"); + info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); + info["SERVER_VERSION"] = gLastVersionChannel; + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + info["SLURL"] = slurl.getSLURLString(); + } + + // CPU + info["CPU"] = gSysCPU.getCPUString(); + info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits<LLUnits::Megabytes>()); + // Moved hack adjustment to Windows memory size into llsys.cpp + info["OS_VERSION"] = LLOSInfo::instance().getOSString(); + info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); + info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); #if LL_WINDOWS std::string drvinfo; @@ -3343,22 +3343,22 @@ LLSD LLAppViewer::getViewerInfo() const drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_ANY); } - if (!drvinfo.empty()) - { - info["GRAPHICS_DRIVER_VERSION"] = drvinfo; - } - else - { - LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; - LLSD driver_info = gDXHardware.getDisplayInfo(); - if (driver_info.has("DriverVersion")) - { - info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; - } - } + if (!drvinfo.empty()) + { + info["GRAPHICS_DRIVER_VERSION"] = drvinfo; + } + else + { + LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; + LLSD driver_info = gDXHardware.getDisplayInfo(); + if (driver_info.has("DriverVersion")) + { + info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; + } + } #endif - info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); + info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); // Settings @@ -3377,16 +3377,16 @@ LLSD LLAppViewer::getViewerInfo() const info["HIDPI"] = gHiDPISupport; #endif - // Libraries + // Libraries - info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); - bool want_fullname = true; - info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined"; - if(LLVoiceClient::getInstance()->voiceEnabled()) - { + info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); + bool want_fullname = true; + info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined"; + if(LLVoiceClient::getInstance()->voiceEnabled()) + { LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion(); const std::string build_version = version.mBuildVersion; - std::ostringstream version_string; + std::ostringstream version_string; if (std::equal(build_version.begin(), build_version.begin() + version.serverVersion.size(), version.serverVersion.begin())) { // Normal case: Show type and build version. @@ -3396,210 +3396,210 @@ LLSD LLAppViewer::getViewerInfo() const { // Mismatch: Show both versions. version_string << version.serverVersion << "/" << build_version << std::endl; } - info["VOICE_VERSION"] = version_string.str(); - } - else - { - info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); - } + info["VOICE_VERSION"] = version_string.str(); + } + else + { + info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); + } #if !LL_LINUX - std::ostringstream cef_ver_codec; - cef_ver_codec << "Dullahan: "; - cef_ver_codec << DULLAHAN_VERSION_MAJOR; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_MINOR; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_POINT; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_BUILD; - - cef_ver_codec << std::endl; - cef_ver_codec << " CEF: "; - cef_ver_codec << CEF_VERSION; - - cef_ver_codec << std::endl; - cef_ver_codec << " Chromium: "; - cef_ver_codec << CHROME_VERSION_MAJOR; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_MINOR; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_BUILD; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_PATCH; - - info["LIBCEF_VERSION"] = cef_ver_codec.str(); + std::ostringstream cef_ver_codec; + cef_ver_codec << "Dullahan: "; + cef_ver_codec << DULLAHAN_VERSION_MAJOR; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_MINOR; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_POINT; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_BUILD; + + cef_ver_codec << std::endl; + cef_ver_codec << " CEF: "; + cef_ver_codec << CEF_VERSION; + + cef_ver_codec << std::endl; + cef_ver_codec << " Chromium: "; + cef_ver_codec << CHROME_VERSION_MAJOR; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_MINOR; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_BUILD; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_PATCH; + + info["LIBCEF_VERSION"] = cef_ver_codec.str(); #else - info["LIBCEF_VERSION"] = "Undefined"; + info["LIBCEF_VERSION"] = "Undefined"; #endif #if !LL_LINUX - std::ostringstream vlc_ver_codec; - vlc_ver_codec << LIBVLC_VERSION_MAJOR; - vlc_ver_codec << "."; - vlc_ver_codec << LIBVLC_VERSION_MINOR; - vlc_ver_codec << "."; - vlc_ver_codec << LIBVLC_VERSION_REVISION; - info["LIBVLC_VERSION"] = vlc_ver_codec.str(); + std::ostringstream vlc_ver_codec; + vlc_ver_codec << LIBVLC_VERSION_MAJOR; + vlc_ver_codec << "."; + vlc_ver_codec << LIBVLC_VERSION_MINOR; + vlc_ver_codec << "."; + vlc_ver_codec << LIBVLC_VERSION_REVISION; + info["LIBVLC_VERSION"] = vlc_ver_codec.str(); #else - info["LIBVLC_VERSION"] = "Undefined"; + info["LIBVLC_VERSION"] = "Undefined"; #endif - S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); - if (packets_in > 0) - { - info["PACKETS_LOST"] = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_LOST); - info["PACKETS_IN"] = packets_in; - info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); - } - - if (mServerReleaseNotesURL.empty()) - { - if (gAgent.getRegion()) - { - info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("RetrievingData"); - } - else - { - info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("NotConnected"); - } - } - else if (LLStringUtil::startsWith(mServerReleaseNotesURL, "http")) // it's an URL - { - info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(mServerReleaseNotesURL) + " " + LLTrans::getString("ReleaseNotes") + "]"; - } - else - { - info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; - } + S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); + if (packets_in > 0) + { + info["PACKETS_LOST"] = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_LOST); + info["PACKETS_IN"] = packets_in; + info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); + } + + if (mServerReleaseNotesURL.empty()) + { + if (gAgent.getRegion()) + { + info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("RetrievingData"); + } + else + { + info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("NotConnected"); + } + } + else if (LLStringUtil::startsWith(mServerReleaseNotesURL, "http")) // it's an URL + { + info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(mServerReleaseNotesURL) + " " + LLTrans::getString("ReleaseNotes") + "]"; + } + else + { + info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; + } // populate field for new local disk cache with some details info["DISK_CACHE_INFO"] = LLDiskCache::getInstance()->getCacheInfo(); - return info; + return info; } std::string LLAppViewer::getViewerInfoString(bool default_string) const { - std::ostringstream support; - - LLSD info(getViewerInfo()); - - // Render the LLSD from getInfo() as a format_map_t - LLStringUtil::format_map_t args; - - // allow the "Release Notes" URL label to be localized - args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes", default_string); - - for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap()); - ii != iend; ++ii) - { - if (! ii->second.isArray()) - { - // Scalar value - if (ii->second.isUndefined()) - { - args[ii->first] = LLTrans::getString("none_text", default_string); - } - else - { - // don't forget to render value asString() - args[ii->first] = ii->second.asString(); - } - } - else - { - // array value: build KEY_0, KEY_1 etc. entries - for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n) - { - args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString(); - } - } - } - - // Now build the various pieces - support << LLTrans::getString("AboutHeader", args, default_string); - if (info.has("BUILD_CONFIG")) - { - support << "\n" << LLTrans::getString("BuildConfig", args, default_string); - } - if (info.has("REGION")) - { - support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); - } - support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); - support << "\n"; - if (info.has("GRAPHICS_DRIVER_VERSION")) - { - support << "\n" << LLTrans::getString("AboutDriver", args, default_string); - } - support << "\n" << LLTrans::getString("AboutOGL", args, default_string); - support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string); + std::ostringstream support; + + LLSD info(getViewerInfo()); + + // Render the LLSD from getInfo() as a format_map_t + LLStringUtil::format_map_t args; + + // allow the "Release Notes" URL label to be localized + args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes", default_string); + + for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap()); + ii != iend; ++ii) + { + if (! ii->second.isArray()) + { + // Scalar value + if (ii->second.isUndefined()) + { + args[ii->first] = LLTrans::getString("none_text", default_string); + } + else + { + // don't forget to render value asString() + args[ii->first] = ii->second.asString(); + } + } + else + { + // array value: build KEY_0, KEY_1 etc. entries + for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n) + { + args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString(); + } + } + } + + // Now build the various pieces + support << LLTrans::getString("AboutHeader", args, default_string); + if (info.has("BUILD_CONFIG")) + { + support << "\n" << LLTrans::getString("BuildConfig", args, default_string); + } + if (info.has("REGION")) + { + support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); + } + support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); + support << "\n"; + if (info.has("GRAPHICS_DRIVER_VERSION")) + { + support << "\n" << LLTrans::getString("AboutDriver", args, default_string); + } + support << "\n" << LLTrans::getString("AboutOGL", args, default_string); + support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string); #if LL_DARWIN - support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string); + support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string); #endif - support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string); - if (info.has("COMPILER")) - { - support << "\n" << LLTrans::getString("AboutCompiler", args, default_string); - } - if (info.has("PACKETS_IN")) - { - support << '\n' << LLTrans::getString("AboutTraffic", args, default_string); - } - - // SLT timestamp - LLSD substitution; - substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected(); - support << "\n" << LLTrans::getString("AboutTime", substitution, default_string); - - return support.str(); + support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string); + if (info.has("COMPILER")) + { + support << "\n" << LLTrans::getString("AboutCompiler", args, default_string); + } + if (info.has("PACKETS_IN")) + { + support << '\n' << LLTrans::getString("AboutTraffic", args, default_string); + } + + // SLT timestamp + LLSD substitution; + substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected(); + support << "\n" << LLTrans::getString("AboutTime", substitution, default_string); + + return support.str(); } void LLAppViewer::cleanupSavedSettings() { - gSavedSettings.setBOOL("MouseSun", FALSE); + gSavedSettings.setBOOL("MouseSun", FALSE); - gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator + gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator - gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); + gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); - gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); + gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); - if (gDebugView) - { - gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); - } + if (gDebugView) + { + gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); + } - // save window position if not maximized - // as we don't track it in callbacks - if(NULL != gViewerWindow) - { - BOOL maximized = gViewerWindow->getWindow()->getMaximized(); - if (!maximized) - { - LLCoordScreen window_pos; + // save window position if not maximized + // as we don't track it in callbacks + if(NULL != gViewerWindow) + { + BOOL maximized = gViewerWindow->getWindow()->getMaximized(); + if (!maximized) + { + LLCoordScreen window_pos; - if (gViewerWindow->getWindow()->getPosition(&window_pos)) - { - gSavedSettings.setS32("WindowX", window_pos.mX); - gSavedSettings.setS32("WindowY", window_pos.mY); - } - } - } + if (gViewerWindow->getWindow()->getPosition(&window_pos)) + { + gSavedSettings.setS32("WindowX", window_pos.mX); + gSavedSettings.setS32("WindowY", window_pos.mY); + } + } + } gSavedSettings.setF32("MapScale", LLWorldMapView::getScaleSetting()); - // Some things are cached in LLAgent. - if (gAgent.isInitialized()) - { - gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); - } + // Some things are cached in LLAgent. + if (gAgent.isInitialized()) + { + gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); + } } void LLAppViewer::removeCacheFiles(const std::string& file_mask) { - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask); + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask); } void LLAppViewer::writeSystemInfo() @@ -3609,96 +3609,96 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["Dynamic"] = LLSD::emptyMap(); #if LL_WINDOWS && !LL_BUGSPLAT - gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); + gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); #else //Not ideal but sufficient for good reporting. gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); //LLError::logFileName(); #endif - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); - gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); + gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); - gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); - gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString(); - gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); - gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz(); - gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); - gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); - gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); + gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString(); + gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); + gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz(); + gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); + gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); + gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); - gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); - gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); - gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); + gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); + gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); + gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); - // The user is not logged on yet, but record the current grid choice login url - // which may have been the intended grid. - gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); + // The user is not logged on yet, but record the current grid choice login url + // which may have been the intended grid. + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); - // *FIX:Mani - move this down in llappviewerwin32 + // *FIX:Mani - move this down in llappviewerwin32 #ifdef LL_WINDOWS - DWORD thread_id = GetCurrentThreadId(); - gDebugInfo["MainloopThreadID"] = (S32)thread_id; + DWORD thread_id = GetCurrentThreadId(); + gDebugInfo["MainloopThreadID"] = (S32)thread_id; #endif #ifndef LL_BUGSPLAT - // "CrashNotHandled" is set here, while things are running well, - // in case of a freeze. If there is a freeze, the crash logger will be launched - // and can read this value from the debug_info.log. - gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); + // "CrashNotHandled" is set here, while things are running well, + // in case of a freeze. If there is a freeze, the crash logger will be launched + // and can read this value from the debug_info.log. + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); #else // LL_BUGSPLAT - // "CrashNotHandled" is obsolete; it used (not very successsfully) + // "CrashNotHandled" is obsolete; it used (not very successsfully) // to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze - gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); #endif // ! LL_BUGSPLAT - // Insert crash host url (url to post crash log to) if configured. This insures - // that the crash report will go to the proper location in the case of a - // prior freeze. - std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl"); - if(crashHostUrl != "") - { - gDebugInfo["CrashHostUrl"] = crashHostUrl; - } - - // Dump some debugging info - LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; - LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; - - // Dump the local time and time zone - time_t now; - time(&now); - char tbuffer[256]; /* Flawfinder: ignore */ - strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now)); - LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL; - - // query some system information - LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL; - LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL; - LL_INFOS("SystemInfo") << "OS: " << LLOSInfo::instance().getOSStringSimple() << LL_ENDL; - LL_INFOS("SystemInfo") << "OS info: " << LLOSInfo::instance() << LL_ENDL; + // Insert crash host url (url to post crash log to) if configured. This insures + // that the crash report will go to the proper location in the case of a + // prior freeze. + std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl"); + if(crashHostUrl != "") + { + gDebugInfo["CrashHostUrl"] = crashHostUrl; + } + + // Dump some debugging info + LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; + LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; + + // Dump the local time and time zone + time_t now; + time(&now); + char tbuffer[256]; /* Flawfinder: ignore */ + strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now)); + LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL; + + // query some system information + LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL; + LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL; + LL_INFOS("SystemInfo") << "OS: " << LLOSInfo::instance().getOSStringSimple() << LL_ENDL; + LL_INFOS("SystemInfo") << "OS info: " << LLOSInfo::instance() << LL_ENDL; gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); - gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); - gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); - gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); + gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); + gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); if (gViewerWindow) { - std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); - for (auto res_iter : resolutions) - { - gDebugInfo["DisplayInfo"].append(res_iter); - } + std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); + for (auto res_iter : resolutions) + { + gDebugInfo["DisplayInfo"].append(res_iter); + } } - writeDebugInfo(); // Save out debug_info.log early, in case of crash. + writeDebugInfo(); // Save out debug_info.log early, in case of crash. } #ifdef LL_WINDOWS @@ -3710,265 +3710,265 @@ void LLAppViewer::writeSystemInfo() // TODO make this a member function. void getFileList() { - std::stringstream filenames; - - typedef std::vector<std::string> vec; - std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); - vec file_vec = gDirUtilp->getFilesInDir(pathname); - for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) - { - filenames << *iter << " "; - if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) - { - std::string fullname = pathname + *iter; - llifstream fdat( fullname.c_str(), std::ifstream::binary); - if (fdat) - { - char buf[5]; - fdat.read(buf,4); - fdat.close(); - if (!strncmp(buf,"MDMP",4)) - { - gDebugInfo["Dynamic"]["MinidumpPath"] = fullname; - break; - } - } - } - } - filenames << std::endl; - gDebugInfo["Dynamic"]["DumpDirContents"] = filenames.str(); + std::stringstream filenames; + + typedef std::vector<std::string> vec; + std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); + vec file_vec = gDirUtilp->getFilesInDir(pathname); + for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) + { + filenames << *iter << " "; + if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) + { + std::string fullname = pathname + *iter; + llifstream fdat( fullname.c_str(), std::ifstream::binary); + if (fdat) + { + char buf[5]; + fdat.read(buf,4); + fdat.close(); + if (!strncmp(buf,"MDMP",4)) + { + gDebugInfo["Dynamic"]["MinidumpPath"] = fullname; + break; + } + } + } + } + filenames << std::endl; + gDebugInfo["Dynamic"]["DumpDirContents"] = filenames.str(); } #endif // static void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) { - std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); - if ( marker_version.length() > MAX_MARKER_LENGTH ) - { - LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" - << " greater than maximum (" << MAX_MARKER_LENGTH << ")" - << ": marker matching may be incorrect" - << LL_ENDL; - } - - // record the viewer version in the marker file - marker_file.write(marker_version.data(), marker_version.length()); + std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); + if ( marker_version.length() > MAX_MARKER_LENGTH ) + { + LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" + << " greater than maximum (" << MAX_MARKER_LENGTH << ")" + << ": marker matching may be incorrect" + << LL_ENDL; + } + + // record the viewer version in the marker file + marker_file.write(marker_version.data(), marker_version.length()); } bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const { - bool sameVersion = false; - - std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); - char marker_version[MAX_MARKER_LENGTH]; - S32 marker_version_length; - - LLAPRFile marker_file; - marker_file.open(marker_name, LL_APR_RB); - if (marker_file.getFileHandle()) - { - marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); - std::string marker_string(marker_version, marker_version_length); - if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) - { - sameVersion = true; - } - LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " - << "\n mine '" << my_version << "'" - << "\n marker '" << marker_string << "'" - << "\n " << ( sameVersion ? "same" : "different" ) << " version" - << LL_ENDL; - marker_file.close(); - } - return sameVersion; + bool sameVersion = false; + + std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); + char marker_version[MAX_MARKER_LENGTH]; + S32 marker_version_length; + + LLAPRFile marker_file; + marker_file.open(marker_name, LL_APR_RB); + if (marker_file.getFileHandle()) + { + marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); + std::string marker_string(marker_version, marker_version_length); + if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) + { + sameVersion = true; + } + LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " + << "\n mine '" << my_version << "'" + << "\n marker '" << marker_string << "'" + << "\n " << ( sameVersion ? "same" : "different" ) << " version" + << LL_ENDL; + marker_file.close(); + } + return sameVersion; } void LLAppViewer::processMarkerFiles() { - //We've got 4 things to test for here - // - Other Process Running (SecondLife.exec_marker present, locked) - // - Freeze (SecondLife.exec_marker present, not locked) - // - LLError Crash (SecondLife.llerror_marker present) - // - Other Crash (SecondLife.error_marker present) - // These checks should also remove these files for the last 2 cases if they currently exist - - std::ostringstream marker_log_stream; - bool marker_is_same_version = true; - // first, look for the marker created at startup and deleted on a clean exit - mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) - { - // File exists... - // first, read it to see if it was created by the same version (we need this later) - marker_is_same_version = markerIsSameVersion(mMarkerFileName); - - // now test to see if this file is locked by a running process (try to open for write) - marker_log_stream << "Checking exec marker file for lock..."; - mMarkerFile.open(mMarkerFileName, LL_APR_WB); - apr_file_t* fMarker = mMarkerFile.getFileHandle() ; - if (!fMarker) - { - marker_log_stream << "Exec marker file open failed - assume it is locked."; - mSecondInstance = true; // lock means that instance is running. - } - else - { - // We were able to open it, now try to lock it ourselves... - if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) - { - marker_log_stream << "Locking exec marker failed."; - mSecondInstance = true; // lost a race? be conservative - } - else - { - // No other instances; we've locked this file now, so record our version; delete on quit. - recordMarkerVersion(mMarkerFile); - marker_log_stream << "Exec marker file existed but was not locked; rewritten."; - } - } - initLoggingAndGetLastDuration(); - - std::string marker_log_msg(marker_log_stream.str()); - LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; - - if (mSecondInstance) - { - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; - } - else if (marker_is_same_version) - { - // the file existed, is ours, and matched our version, so we can report on what it says - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; - gLastExecEvent = LAST_EXEC_OTHER_CRASH; - } - else - { - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; - } - } - else // marker did not exist... last exec (if any) did not freeze - { - initLoggingAndGetLastDuration(); - // Create the marker file for this execution & lock it; it will be deleted on a clean exit - apr_status_t s; - s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); - - if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) - { - LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; - if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) - { - recordMarkerVersion(mMarkerFile); - LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; - } - } - else - { - LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; - } - } - - // now check for cases in which the exec marker may have been cleaned up by crash handlers - - // check for any last exec event report based on whether or not it happened during logout - // (the logout marker is created when logout begins) - std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(logout_marker_file)) - { - gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; - LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; - } - else - { - LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(logout_marker_file); - } - // further refine based on whether or not a marker created during an llerr crash is found - std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(llerror_marker_file)) - { - if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_LLERROR_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(llerror_marker_file); - } - // and last refine based on whether or not a marker created during a non-llerr crash is found - std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(error_marker_file)) - { - if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_OTHER_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(error_marker_file); - } + //We've got 4 things to test for here + // - Other Process Running (SecondLife.exec_marker present, locked) + // - Freeze (SecondLife.exec_marker present, not locked) + // - LLError Crash (SecondLife.llerror_marker present) + // - Other Crash (SecondLife.error_marker present) + // These checks should also remove these files for the last 2 cases if they currently exist + + std::ostringstream marker_log_stream; + bool marker_is_same_version = true; + // first, look for the marker created at startup and deleted on a clean exit + mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); + if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) + { + // File exists... + // first, read it to see if it was created by the same version (we need this later) + marker_is_same_version = markerIsSameVersion(mMarkerFileName); + + // now test to see if this file is locked by a running process (try to open for write) + marker_log_stream << "Checking exec marker file for lock..."; + mMarkerFile.open(mMarkerFileName, LL_APR_WB); + apr_file_t* fMarker = mMarkerFile.getFileHandle() ; + if (!fMarker) + { + marker_log_stream << "Exec marker file open failed - assume it is locked."; + mSecondInstance = true; // lock means that instance is running. + } + else + { + // We were able to open it, now try to lock it ourselves... + if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) + { + marker_log_stream << "Locking exec marker failed."; + mSecondInstance = true; // lost a race? be conservative + } + else + { + // No other instances; we've locked this file now, so record our version; delete on quit. + recordMarkerVersion(mMarkerFile); + marker_log_stream << "Exec marker file existed but was not locked; rewritten."; + } + } + initLoggingAndGetLastDuration(); + + std::string marker_log_msg(marker_log_stream.str()); + LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; + + if (mSecondInstance) + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; + } + else if (marker_is_same_version) + { + // the file existed, is ours, and matched our version, so we can report on what it says + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + } + else + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; + } + } + else // marker did not exist... last exec (if any) did not freeze + { + initLoggingAndGetLastDuration(); + // Create the marker file for this execution & lock it; it will be deleted on a clean exit + apr_status_t s; + s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); + + if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) + { + LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; + if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) + { + recordMarkerVersion(mMarkerFile); + LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; + } + } + else + { + LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; + } + } + + // now check for cases in which the exec marker may have been cleaned up by crash handlers + + // check for any last exec event report based on whether or not it happened during logout + // (the logout marker is created when logout begins) + std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); + if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(logout_marker_file)) + { + gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; + } + else + { + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(logout_marker_file); + } + // further refine based on whether or not a marker created during an llerr crash is found + std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); + if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(llerror_marker_file)) + { + if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(llerror_marker_file); + } + // and last refine based on whether or not a marker created during a non-llerr crash is found + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(error_marker_file)) + { + if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(error_marker_file); + } } void LLAppViewer::removeMarkerFiles() { - if (!mSecondInstance) - { - if (mMarkerFile.getFileHandle()) - { - mMarkerFile.close() ; - LLAPRFile::remove( mMarkerFileName ); - LL_DEBUGS("MarkerFile") << "removed exec marker '"<<mMarkerFileName<<"'"<< LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "marker '"<<mMarkerFileName<<"' not open"<< LL_ENDL; - } - - if (mLogoutMarkerFile.getFileHandle()) - { - mLogoutMarkerFile.close(); - LLAPRFile::remove( mLogoutMarkerFileName ); - LL_DEBUGS("MarkerFile") << "removed logout marker '"<<mLogoutMarkerFileName<<"'"<< LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL; - } - } - else - { - LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; - } + if (!mSecondInstance) + { + if (mMarkerFile.getFileHandle()) + { + mMarkerFile.close() ; + LLAPRFile::remove( mMarkerFileName ); + LL_DEBUGS("MarkerFile") << "removed exec marker '"<<mMarkerFileName<<"'"<< LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "marker '"<<mMarkerFileName<<"' not open"<< LL_ENDL; + } + + if (mLogoutMarkerFile.getFileHandle()) + { + mLogoutMarkerFile.close(); + LLAPRFile::remove( mLogoutMarkerFileName ); + LL_DEBUGS("MarkerFile") << "removed logout marker '"<<mLogoutMarkerFileName<<"'"<< LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL; + } + } + else + { + LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; + } } void LLAppViewer::removeDumpDir() @@ -3991,212 +3991,212 @@ void LLAppViewer::removeDumpDir() void LLAppViewer::forceQuit() { - LLApp::setQuitting(); + LLApp::setQuitting(); } //TODO: remove void LLAppViewer::fastQuit(S32 error_code) { - // finish pending transfers - flushLFSIO(); - // let sim know we're logging out - sendLogoutRequest(); - // flush network buffers by shutting down messaging system - end_messaging_system(); - // figure out the error code - S32 final_error_code = error_code ? error_code : (S32)isError(); - // this isn't a crash - removeMarkerFiles(); - // get outta here - _exit(final_error_code); + // finish pending transfers + flushLFSIO(); + // let sim know we're logging out + sendLogoutRequest(); + // flush network buffers by shutting down messaging system + end_messaging_system(); + // figure out the error code + S32 final_error_code = error_code ? error_code : (S32)isError(); + // this isn't a crash + removeMarkerFiles(); + // get outta here + _exit(final_error_code); } void LLAppViewer::requestQuit() { - LL_INFOS() << "requestQuit" << LL_ENDL; - - LLViewerRegion* region = gAgent.getRegion(); - - if( (LLStartUp::getStartupState() < STATE_STARTED) || !region ) - { - // If we have a region, make some attempt to send a logout request first. - // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes. - if(region) - { - sendLogoutRequest(); - } - - // Quit immediately - forceQuit(); - return; - } - - // Try to send metrics back to the grid - metricsSend(!gDisconnected); - - // Try to send last batch of avatar rez metrics. - if (!gDisconnected && isAgentAvatarValid()) - { - gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent. - } - - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - effectp->markDead() ;//remove it. - - // Attempt to close all floaters that might be - // editing things. - if (gFloaterView) - { - // application is quitting - gFloaterView->closeAllChildren(true); - } - - // Send preferences once, when exiting - bool include_preferences = true; - send_viewer_stats(include_preferences); - - gLogoutTimer.reset(); - mQuitRequested = true; + LL_INFOS() << "requestQuit" << LL_ENDL; + + LLViewerRegion* region = gAgent.getRegion(); + + if( (LLStartUp::getStartupState() < STATE_STARTED) || !region ) + { + // If we have a region, make some attempt to send a logout request first. + // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes. + if(region) + { + sendLogoutRequest(); + } + + // Quit immediately + forceQuit(); + return; + } + + // Try to send metrics back to the grid + metricsSend(!gDisconnected); + + // Try to send last batch of avatar rez metrics. + if (!gDisconnected && isAgentAvatarValid()) + { + gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent. + } + + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + effectp->markDead() ;//remove it. + + // Attempt to close all floaters that might be + // editing things. + if (gFloaterView) + { + // application is quitting + gFloaterView->closeAllChildren(true); + } + + // Send preferences once, when exiting + bool include_preferences = true; + send_viewer_stats(include_preferences); + + gLogoutTimer.reset(); + mQuitRequested = true; } static bool finish_quit(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLAppViewer::instance()->requestQuit(); - } - return false; + if (option == 0) + { + LLAppViewer::instance()->requestQuit(); + } + return false; } static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit); void LLAppViewer::userQuit() { - LL_INFOS() << "User requested quit" << LL_ENDL; - if (gDisconnected - || !gViewerWindow - || !gViewerWindow->getProgressView() - || gViewerWindow->getProgressView()->getVisible()) - { - requestQuit(); - } - else - { - LLNotificationsUtil::add("ConfirmQuit"); - } + LL_INFOS() << "User requested quit" << LL_ENDL; + if (gDisconnected + || !gViewerWindow + || !gViewerWindow->getProgressView() + || gViewerWindow->getProgressView()->getVisible()) + { + requestQuit(); + } + else + { + LLNotificationsUtil::add("ConfirmQuit"); + } } static bool finish_early_exit(const LLSD& notification, const LLSD& response) { - LLAppViewer::instance()->forceQuit(); - return false; + LLAppViewer::instance()->forceQuit(); + return false; } void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) { - LL_WARNS() << "app_early_exit: " << name << LL_ENDL; - gDoDisconnect = TRUE; - LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); + LL_WARNS() << "app_early_exit: " << name << LL_ENDL; + gDoDisconnect = TRUE; + LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); } // case where we need the viewer to exit without any need for notifications void LLAppViewer::earlyExitNoNotify() { - LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL; - gDoDisconnect = TRUE; - finish_early_exit( LLSD(), LLSD() ); + LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL; + gDoDisconnect = TRUE; + finish_early_exit( LLSD(), LLSD() ); } void LLAppViewer::abortQuit() { LL_INFOS() << "abortQuit()" << LL_ENDL; - mQuitRequested = false; + mQuitRequested = false; } void LLAppViewer::migrateCacheDirectory() { #if LL_WINDOWS || LL_DARWIN - // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from - // /library/application support/SecondLife/cache This should clear/delete the old dir. - - // As of 1.23 the Windows cache moved from - // C:\Documents and Settings\James\Application Support\SecondLife\cache - // to - // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife - // - // The Windows Vista equivalent is from - // C:\Users\James\AppData\Roaming\SecondLife\cache - // to - // C:\Users\James\AppData\Local\SecondLife - // - // Note the absence of \cache on the second path. James. - - // Only do this once per fresh install of this version. - if (gSavedSettings.getBOOL("MigrateCacheDirectory")) - { - gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); - - std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); - std::string new_cache_dir = gDirUtilp->getCacheDir(true); - - if (gDirUtilp->fileExists(old_cache_dir)) - { - LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; - - // Migrate inventory cache to avoid pain to inventory database after mass update - S32 file_count = 0; - std::string file_name; - std::string mask = "*.*"; - - LLDirIterator iter(old_cache_dir, mask); - while (iter.next(file_name)) - { - if (file_name == "." || file_name == "..") continue; - std::string source_path = gDirUtilp->add(old_cache_dir, file_name); - std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); - if (!LLFile::rename(source_path, dest_path)) - { - file_count++; - } - } - LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; - - // Nuke the old cache - gDirUtilp->setCacheDir(old_cache_dir); - purgeCache(); - gDirUtilp->setCacheDir(new_cache_dir); + // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from + // /library/application support/SecondLife/cache This should clear/delete the old dir. + + // As of 1.23 the Windows cache moved from + // C:\Documents and Settings\James\Application Support\SecondLife\cache + // to + // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife + // + // The Windows Vista equivalent is from + // C:\Users\James\AppData\Roaming\SecondLife\cache + // to + // C:\Users\James\AppData\Local\SecondLife + // + // Note the absence of \cache on the second path. James. + + // Only do this once per fresh install of this version. + if (gSavedSettings.getBOOL("MigrateCacheDirectory")) + { + gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); + + std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); + std::string new_cache_dir = gDirUtilp->getCacheDir(true); + + if (gDirUtilp->fileExists(old_cache_dir)) + { + LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; + + // Migrate inventory cache to avoid pain to inventory database after mass update + S32 file_count = 0; + std::string file_name; + std::string mask = "*.*"; + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) + { + if (file_name == "." || file_name == "..") continue; + std::string source_path = gDirUtilp->add(old_cache_dir, file_name); + std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); + if (!LLFile::rename(source_path, dest_path)) + { + file_count++; + } + } + LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; + + // Nuke the old cache + gDirUtilp->setCacheDir(old_cache_dir); + purgeCache(); + gDirUtilp->setCacheDir(new_cache_dir); #if LL_DARWIN - // Clean up Mac files not deleted by removing *.* - std::string ds_store = old_cache_dir + "/.DS_Store"; - if (gDirUtilp->fileExists(ds_store)) - { - LLFile::remove(ds_store); - } + // Clean up Mac files not deleted by removing *.* + std::string ds_store = old_cache_dir + "/.DS_Store"; + if (gDirUtilp->fileExists(ds_store)) + { + LLFile::remove(ds_store); + } #endif - if (LLFile::rmdir(old_cache_dir) != 0) - { - LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; - } - } - } + if (LLFile::rmdir(old_cache_dir) != 0) + { + LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; + } + } + } #endif // LL_WINDOWS || LL_DARWIN } //static U32 LLAppViewer::getTextureCacheVersion() { - // Viewer texture cache version, change if the texture cache format changes. - // 2021-03-10 Bumping up by one to help obviate texture cache issues with - // Simple Cache Viewer - see SL-14985 for more information - //const U32 TEXTURE_CACHE_VERSION = 8; - const U32 TEXTURE_CACHE_VERSION = 9; + // Viewer texture cache version, change if the texture cache format changes. + // 2021-03-10 Bumping up by one to help obviate texture cache issues with + // Simple Cache Viewer - see SL-14985 for more information + //const U32 TEXTURE_CACHE_VERSION = 8; + const U32 TEXTURE_CACHE_VERSION = 9; - return TEXTURE_CACHE_VERSION ; + return TEXTURE_CACHE_VERSION ; } //static @@ -4211,92 +4211,92 @@ U32 LLAppViewer::getDiskCacheVersion() //static U32 LLAppViewer::getObjectCacheVersion() { - // Viewer object cache version, change if object update - // format changes. JC - const U32 INDRA_OBJECT_CACHE_VERSION = 17; + // Viewer object cache version, change if object update + // format changes. JC + const U32 INDRA_OBJECT_CACHE_VERSION = 17; - return INDRA_OBJECT_CACHE_VERSION; + return INDRA_OBJECT_CACHE_VERSION; } bool LLAppViewer::initCache() { - mPurgeCache = false; - BOOL read_only = mSecondInstance ? TRUE : FALSE; - LLAppViewer::getTextureCache()->setReadOnly(read_only) ; - LLVOCache::initParamSingleton(read_only); + mPurgeCache = false; + BOOL read_only = mSecondInstance ? TRUE : FALSE; + LLAppViewer::getTextureCache()->setReadOnly(read_only) ; + LLVOCache::initParamSingleton(read_only); - // initialize the new disk cache using saved settings - const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); + // initialize the new disk cache using saved settings + const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); - const U32 MB = 1024 * 1024; + const U32 MB = 1024 * 1024; const uintmax_t MIN_CACHE_SIZE = 256 * MB; - const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; + const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB; const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); const F64 texture_cache_percent = 100.0 - disk_cache_percent; - // note that the maximum size of this cache is defined as a percentage of the - // total cache size - the 'CacheSize' pref - for all caches. + // note that the maximum size of this cache is defined as a percentage of the + // total cache size - the 'CacheSize' pref - for all caches. const uintmax_t disk_cache_size = uintmax_t(cache_total_size * disk_cache_percent / 100); - const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); + const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); - bool texture_cache_mismatch = false; + bool texture_cache_mismatch = false; bool remove_vfs_files = false; - if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) - { - texture_cache_mismatch = true; - if(!read_only) - { - gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); + if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) + { + texture_cache_mismatch = true; + if(!read_only) + { + gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); //texture cache version was bumped up in Simple Cache Viewer, and at this point old vfs files are not needed - remove_vfs_files = true; - } - } - - if(!read_only) - { - // Purge cache if user requested it - if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || - gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) - { - LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); - mPurgeCache = true; - // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad - texture_cache_mismatch = true; - } - - // We have moved the location of the cache directory over time. - migrateCacheDirectory(); - - // Setup and verify the cache location - std::string cache_location = gSavedSettings.getString("CacheLocation"); - std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); - if (new_cache_location != cache_location) - { - LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; - gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); - purgeCache(); // purge old cache - gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); - gSavedSettings.setString("CacheLocation", new_cache_location); - gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); - } - } - - if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) - { - LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; - gSavedSettings.setString("CacheLocation", ""); - gSavedSettings.setString("CacheLocationTopFolder", ""); - } - - const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); - LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); - - if (!read_only) - { + remove_vfs_files = true; + } + } + + if(!read_only) + { + // Purge cache if user requested it + if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || + gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) + { + LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); + mPurgeCache = true; + // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad + texture_cache_mismatch = true; + } + + // We have moved the location of the cache directory over time. + migrateCacheDirectory(); + + // Setup and verify the cache location + std::string cache_location = gSavedSettings.getString("CacheLocation"); + std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); + if (new_cache_location != cache_location) + { + LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; + gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); + purgeCache(); // purge old cache + gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); + gSavedSettings.setString("CacheLocation", new_cache_location); + gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); + } + } + + if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) + { + LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; + gSavedSettings.setString("CacheLocation", ""); + gSavedSettings.setString("CacheLocationTopFolder", ""); + } + + const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); + LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); + + if (!read_only) + { if (gSavedSettings.getS32("DiskCacheVersion") != LLAppViewer::getDiskCacheVersion()) { LLDiskCache::getInstance()->clearCache(); @@ -4308,166 +4308,166 @@ bool LLAppViewer::initCache() { LLDiskCache::getInstance()->removeOldVFSFiles(); } - + if (mPurgeCache) - { - LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); - purgeCache(); - - // clear the new C++ file system based cache - LLDiskCache::getInstance()->clearCache(); - } - else - { - // purge excessive files from the new file system based cache - LLDiskCache::getInstance()->purge(); - } - } - LLAppViewer::getPurgeDiskCacheThread()->start(); - - LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); - - // Init the texture cache + { + LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); + purgeCache(); + + // clear the new C++ file system based cache + LLDiskCache::getInstance()->clearCache(); + } + else + { + // purge excessive files from the new file system based cache + LLDiskCache::getInstance()->purge(); + } + } + LLAppViewer::getPurgeDiskCacheThread()->start(); + + LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); + + // Init the texture cache // Allocate the remaining percent which is not allocated to the disk cache const S64 texture_cache_size = S64(cache_total_size * texture_cache_percent / 100); LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); - LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); + LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); return true; } void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb) { - gMainloopWork.post(cb); + gMainloopWork.post(cb); } void LLAppViewer::loadKeyBindings() { - std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); - if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) - { - // Failed to load custom bindings, try default ones - key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); - if (!gViewerInput.loadBindingsXML(key_bindings_file)) - { + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) + { + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; - } - } + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; + } + } LLUrlRegistry::instance().setKeybindingHandler(&gViewerInput); } void LLAppViewer::purgeCache() { - LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; - LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); - LLViewerShaderMgr::instance()->clearShaderCache(); - std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); - if (LLFile::isdir(browser_cache)) - { - // cef does not support clear_cache and clear_cookies, so clear what we can manually. - gDirUtilp->deleteDirAndContents(browser_cache); - } - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*"); + LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; + LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); + LLViewerShaderMgr::instance()->clearShaderCache(); + std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); + if (LLFile::isdir(browser_cache)) + { + // cef does not support clear_cache and clear_cookies, so clear what we can manually. + gDirUtilp->deleteDirAndContents(browser_cache); + } + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*"); } //purge cache immediately, do not wait until the next login. void LLAppViewer::purgeCacheImmediate() { - LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; - LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); + LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; + LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); } std::string LLAppViewer::getSecondLifeTitle() const { - return LLTrans::getString("APP_NAME"); + return LLTrans::getString("APP_NAME"); } std::string LLAppViewer::getWindowTitle() const { - return gWindowTitle; + return gWindowTitle; } // Callback from a dialog indicating user was logged out. bool finish_disconnect(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (1 == option) - { + if (1 == option) + { LLAppViewer::instance()->forceQuit(); - } - return false; + } + return false; } // Callback from an early disconnect dialog, force an exit bool finish_forced_disconnect(const LLSD& notification, const LLSD& response) { - LLAppViewer::instance()->forceQuit(); - return false; + LLAppViewer::instance()->forceQuit(); + return false; } void LLAppViewer::forceDisconnect(const std::string& mesg) { - if (gDoDisconnect) - { - // Already popped up one of these dialogs, don't - // do this again. - return; - } - - // *TODO: Translate the message if possible - std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; - if ( big_reason.size() == 0 ) - { - big_reason = mesg; - } - - LLSD args; - gDoDisconnect = TRUE; - - if (LLStartUp::getStartupState() < STATE_STARTED) - { - // Tell users what happened - args["ERROR_MESSAGE"] = big_reason; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); - } - else - { - args["MESSAGE"] = big_reason; - LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); - } + if (gDoDisconnect) + { + // Already popped up one of these dialogs, don't + // do this again. + return; + } + + // *TODO: Translate the message if possible + std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; + if ( big_reason.size() == 0 ) + { + big_reason = mesg; + } + + LLSD args; + gDoDisconnect = TRUE; + + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // Tell users what happened + args["ERROR_MESSAGE"] = big_reason; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); + } + else + { + args["MESSAGE"] = big_reason; + LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); + } } void LLAppViewer::badNetworkHandler() { - // Dump the packet - gMessageSystem->dumpPacketToLog(); - - // Flush all of our caches on exit in the case of disconnect due to - // invalid packets. - - mPurgeCacheOnExit = TRUE; - - std::ostringstream message; - message << - "The viewer has detected mangled network data indicative\n" - "of a bad upstream network connection or an incomplete\n" - "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" - " \n" - "Try uninstalling and reinstalling to see if this resolves \n" - "the issue. \n" - " \n" - "If the problem continues, see the Tech Support FAQ at: \n" - "www.secondlife.com/support"; - forceDisconnect(message.str()); - - LLApp::instance()->writeMiniDump(); + // Dump the packet + gMessageSystem->dumpPacketToLog(); + + // Flush all of our caches on exit in the case of disconnect due to + // invalid packets. + + mPurgeCacheOnExit = TRUE; + + std::ostringstream message; + message << + "The viewer has detected mangled network data indicative\n" + "of a bad upstream network connection or an incomplete\n" + "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" + " \n" + "Try uninstalling and reinstalling to see if this resolves \n" + "the issue. \n" + " \n" + "If the problem continues, see the Tech Support FAQ at: \n" + "www.secondlife.com/support"; + forceDisconnect(message.str()); + + LLApp::instance()->writeMiniDump(); } // This routine may get called more than once during the shutdown process. @@ -4475,93 +4475,93 @@ void LLAppViewer::badNetworkHandler() // is destroyed. void LLAppViewer::saveFinalSnapshot() { - if (!mSavedFinalSnapshot) - { - gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); - gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); - gViewerWindow->setCursor(UI_CURSOR_WAIT); - gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch - gSavedSettings.setBOOL("ShowParcelOwners", FALSE); - idle(); - - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenLastFilename(); - // use full pixel dimensions of viewer window (not post-scale dimensions) - gViewerWindow->saveSnapshot(snap_filename, - gViewerWindow->getWindowWidthRaw(), - gViewerWindow->getWindowHeightRaw(), - FALSE, - gSavedSettings.getBOOL("RenderHUDInSnapshot"), - TRUE, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - mSavedFinalSnapshot = TRUE; - - if (gAgent.isInHomeRegion()) - { - LLVector3d home; - if (gAgent.getHomePosGlobal(&home) && dist_vec(home, gAgent.getPositionGlobal()) < 10) - { - // We are at home position or close to it, see if we need to create home screenshot - // Notes: - // 1. It might be beneficial to also replace home if file is too old - // 2. This is far from best way/place to update screenshot since location might be not fully loaded, - // but we don't have many options - std::string snap_home = gDirUtilp->getLindenUserDir(); - snap_home += gDirUtilp->getDirDelimiter(); - snap_home += LLStartUp::getScreenHomeFilename(); - if (!gDirUtilp->fileExists(snap_home)) - { - // We are at home position yet no home image exist, fix it - LLFile::copy(snap_filename, snap_home); - } - } - } - } + if (!mSavedFinalSnapshot) + { + gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); + gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); + gViewerWindow->setCursor(UI_CURSOR_WAIT); + gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch + gSavedSettings.setBOOL("ShowParcelOwners", FALSE); + idle(); + + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenLastFilename(); + // use full pixel dimensions of viewer window (not post-scale dimensions) + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + TRUE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + mSavedFinalSnapshot = TRUE; + + if (gAgent.isInHomeRegion()) + { + LLVector3d home; + if (gAgent.getHomePosGlobal(&home) && dist_vec(home, gAgent.getPositionGlobal()) < 10) + { + // We are at home position or close to it, see if we need to create home screenshot + // Notes: + // 1. It might be beneficial to also replace home if file is too old + // 2. This is far from best way/place to update screenshot since location might be not fully loaded, + // but we don't have many options + std::string snap_home = gDirUtilp->getLindenUserDir(); + snap_home += gDirUtilp->getDirDelimiter(); + snap_home += LLStartUp::getScreenHomeFilename(); + if (!gDirUtilp->fileExists(snap_home)) + { + // We are at home position yet no home image exist, fix it + LLFile::copy(snap_filename, snap_home); + } + } + } + } } void LLAppViewer::loadNameCache() { - // display names cache - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - LL_INFOS("AvNameCache") << filename << LL_ENDL; - llifstream name_cache_stream(filename.c_str()); - if(name_cache_stream.is_open()) - { - if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) + // display names cache + std::string filename = + gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + LL_INFOS("AvNameCache") << filename << LL_ENDL; + llifstream name_cache_stream(filename.c_str()); + if(name_cache_stream.is_open()) + { + if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) { LL_WARNS("AppInit") << "removing invalid '" << filename << "'" << LL_ENDL; name_cache_stream.close(); LLFile::remove(filename); } - } + } - if (!gCacheName) return; + if (!gCacheName) return; - std::string name_cache; - name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); - llifstream cache_file(name_cache.c_str()); - if(cache_file.is_open()) - { - if(gCacheName->importFile(cache_file)) return; - } + std::string name_cache; + name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); + llifstream cache_file(name_cache.c_str()); + if(cache_file.is_open()) + { + if(gCacheName->importFile(cache_file)) return; + } } void LLAppViewer::saveNameCache() { - // display names cache - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - llofstream name_cache_stream(filename.c_str()); - if(name_cache_stream.is_open()) - { - LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); + // display names cache + std::string filename = + gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + llofstream name_cache_stream(filename.c_str()); + if(name_cache_stream.is_open()) + { + LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); } // real names cache - if (gCacheName) + if (gCacheName) { std::string name_cache; name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); @@ -4570,24 +4570,24 @@ void LLAppViewer::saveNameCache() { gCacheName->exportFile(cache_file); } - } + } } -/*! @brief This class is an LLFrameTimer that can be created with - an elapsed time that starts counting up from the given value - rather than 0.0. +/*! @brief This class is an LLFrameTimer that can be created with + an elapsed time that starts counting up from the given value + rather than 0.0. - Otherwise it behaves the same way as LLFrameTimer. + Otherwise it behaves the same way as LLFrameTimer. */ class LLFrameStatsTimer : public LLFrameTimer { public: - LLFrameStatsTimer(F64 elapsed_already = 0.0) - : LLFrameTimer() - { - mStartTime -= elapsed_already; - } + LLFrameStatsTimer(F64 elapsed_already = 0.0) + : LLFrameTimer() + { + mStartTime -= elapsed_already; + } }; static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio"); @@ -4612,118 +4612,118 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); /////////////////////////////////////////////////////// void LLAppViewer::idle() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - pingMainloopTimeout("Main:Idle"); - - // Update frame timers - static LLTimer idle_timer; - - LLFrameTimer::updateFrameTime(); - LLFrameTimer::updateFrameCount(); - LLPerfStats::updateClass(); - - // LLApp::stepFrame() performs the above three calls plus mRunner.run(). - // Not sure why we don't call stepFrame() here, except that LLRunner seems - // completely redundant with LLEventTimer. - LLNotificationsUI::LLToast::updateClass(); - LLSmoothInterpolation::updateInterpolants(); - LLMortician::updateClass(); - LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() - LLDirPickerThread::clearDead(); - F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); - - LLGLTFMaterialList::flushUpdates(); - - // Service the WorkQueue we use for replies from worker threads. - // Use function statics for the timeslice setting so we only have to fetch - // and convert MainWorkTime once. - static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); - static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); - // MainWorkTime is specified in fractional milliseconds, but std::chrono - // uses integer representations. What if we want less than a microsecond? - // Use nanoseconds. We're very sure we will never need to specify a - // MainWorkTime that would be larger than we could express in - // std::chrono::nanoseconds. - static std::chrono::nanoseconds MainWorkTimeNanoSec{ - std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; - gMainloopWork.runFor(MainWorkTimeNanoSec); - - // Cap out-of-control frame times - // Too low because in menus, swapping, debugger, etc. - // Too high because idle called with no objects in view, etc. - const F32 MIN_FRAME_RATE = 1.f; - const F32 MAX_FRAME_RATE = 200.f; - - F32 frame_rate_clamped = 1.f / dt_raw; - frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); - gFrameDTClamped = 1.f / frame_rate_clamped; - - // Global frame timer - // Smoothly weight toward current frame - gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; - - F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); - if (qas > 0.f) - { - if (gRenderStartTime.getElapsedTimeF32() > qas) - { - LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; - LLAppViewer::instance()->forceQuit(); - } - } - - // Must wait until both have avatar object and mute list, so poll - // here. - LLIMProcessing::requestOfflineMessages(); - - /////////////////////////////////// - // - // Special case idle if still starting up - // - if (LLStartUp::getStartupState() < STATE_STARTED) - { - // Skip rest if idle startup returns false (essentially, no world yet) - gGLActive = TRUE; - if (!idle_startup()) - { - gGLActive = FALSE; - return; - } - gGLActive = FALSE; - } - - - F32 yaw = 0.f; // radians - - if (!gDisconnected) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); - // Update spaceserver timeinfo - LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); - - - ////////////////////////////////////// - // - // Update simulator agent state - // - - if (gSavedSettings.getBOOL("RotateRight")) - { - gAgent.moveYaw(-1.f); - } - - { + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; + pingMainloopTimeout("Main:Idle"); + + // Update frame timers + static LLTimer idle_timer; + + LLFrameTimer::updateFrameTime(); + LLFrameTimer::updateFrameCount(); + LLPerfStats::updateClass(); + + // LLApp::stepFrame() performs the above three calls plus mRunner.run(). + // Not sure why we don't call stepFrame() here, except that LLRunner seems + // completely redundant with LLEventTimer. + LLNotificationsUI::LLToast::updateClass(); + LLSmoothInterpolation::updateInterpolants(); + LLMortician::updateClass(); + LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() + LLDirPickerThread::clearDead(); + F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); + + LLGLTFMaterialList::flushUpdates(); + + // Service the WorkQueue we use for replies from worker threads. + // Use function statics for the timeslice setting so we only have to fetch + // and convert MainWorkTime once. + static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); + static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); + // MainWorkTime is specified in fractional milliseconds, but std::chrono + // uses integer representations. What if we want less than a microsecond? + // Use nanoseconds. We're very sure we will never need to specify a + // MainWorkTime that would be larger than we could express in + // std::chrono::nanoseconds. + static std::chrono::nanoseconds MainWorkTimeNanoSec{ + std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; + gMainloopWork.runFor(MainWorkTimeNanoSec); + + // Cap out-of-control frame times + // Too low because in menus, swapping, debugger, etc. + // Too high because idle called with no objects in view, etc. + const F32 MIN_FRAME_RATE = 1.f; + const F32 MAX_FRAME_RATE = 200.f; + + F32 frame_rate_clamped = 1.f / dt_raw; + frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); + gFrameDTClamped = 1.f / frame_rate_clamped; + + // Global frame timer + // Smoothly weight toward current frame + gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; + + F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); + if (qas > 0.f) + { + if (gRenderStartTime.getElapsedTimeF32() > qas) + { + LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; + LLAppViewer::instance()->forceQuit(); + } + } + + // Must wait until both have avatar object and mute list, so poll + // here. + LLIMProcessing::requestOfflineMessages(); + + /////////////////////////////////// + // + // Special case idle if still starting up + // + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // Skip rest if idle startup returns false (essentially, no world yet) + gGLActive = TRUE; + if (!idle_startup()) + { + gGLActive = FALSE; + return; + } + gGLActive = FALSE; + } + + + F32 yaw = 0.f; // radians + + if (!gDisconnected) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); + // Update spaceserver timeinfo + LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); + + + ////////////////////////////////////// + // + // Update simulator agent state + // + + if (gSavedSettings.getBOOL("RotateRight")) + { + gAgent.moveYaw(-1.f); + } + + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Autopilot"); - // Handle automatic walking towards points - gAgentPilot.updateTarget(); - gAgent.autoPilot(&yaw); - } + // Handle automatic walking towards points + gAgentPilot.updateTarget(); + gAgent.autoPilot(&yaw); + } - static LLFrameTimer agent_update_timer; + static LLFrameTimer agent_update_timer; - // When appropriate, update agent location to the simulator. - F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); - F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; + // When appropriate, update agent location to the simulator. + F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); + F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; bool timed_out = agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND); BOOL force_send = // if there is something to send @@ -4734,111 +4734,111 @@ void LLAppViewer::idle() || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND)); // timing out doesn't warranty that an update will be sent, // just that it will be checked. - if (force_send || timed_out) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // Send avatar and camera info - mLastAgentControlFlags = gAgent.getControlFlags(); - mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; - send_agent_update(force_send); - agent_update_timer.reset(); - } - } - - ////////////////////////////////////// - // - // Manage statistics - // - // - { - // Initialize the viewer_stats_timer with an already elapsed time - // of SEND_STATS_PERIOD so that the initial stats report will - // be sent immediately. - static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); - - // Update session stats every large chunk of time - // *FIX: (?) SAMANTHA - if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) - { - LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; - bool include_preferences = false; - send_viewer_stats(include_preferences); - viewer_stats_timer.reset(); - } - - // Print the object debugging stats - static LLFrameTimer object_debug_timer; - if (object_debug_timer.getElapsedTimeF32() > 5.f) - { - object_debug_timer.reset(); - if (gObjectList.mNumDeadObjectUpdates) - { - LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; - gObjectList.mNumDeadObjectUpdates = 0; - } - if (gObjectList.mNumUnknownUpdates) - { - LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; - gObjectList.mNumUnknownUpdates = 0; - } - - } - } - - if (!gDisconnected) - { + if (force_send || timed_out) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + // Send avatar and camera info + mLastAgentControlFlags = gAgent.getControlFlags(); + mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; + send_agent_update(force_send); + agent_update_timer.reset(); + } + } + + ////////////////////////////////////// + // + // Manage statistics + // + // + { + // Initialize the viewer_stats_timer with an already elapsed time + // of SEND_STATS_PERIOD so that the initial stats report will + // be sent immediately. + static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); + + // Update session stats every large chunk of time + // *FIX: (?) SAMANTHA + if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) + { + LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; + bool include_preferences = false; + send_viewer_stats(include_preferences); + viewer_stats_timer.reset(); + } + + // Print the object debugging stats + static LLFrameTimer object_debug_timer; + if (object_debug_timer.getElapsedTimeF32() > 5.f) + { + object_debug_timer.reset(); + if (gObjectList.mNumDeadObjectUpdates) + { + LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; + gObjectList.mNumDeadObjectUpdates = 0; + } + if (gObjectList.mNumUnknownUpdates) + { + LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; + gObjectList.mNumUnknownUpdates = 0; + } + + } + } + + if (!gDisconnected) + { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Network"); - //////////////////////////////////////////////// - // - // Network processing - // - // NOTE: Starting at this point, we may still have pointers to "dead" objects - // floating throughout the various object lists. - // - idleNameCache(); - idleNetwork(); + //////////////////////////////////////////////// + // + // Network processing + // + // NOTE: Starting at this point, we may still have pointers to "dead" objects + // floating throughout the various object lists. + // + idleNameCache(); + idleNetwork(); - // Check for away from keyboard, kick idle agents. - idle_afk_check(); + // Check for away from keyboard, kick idle agents. + idle_afk_check(); - // Update statistics for this frame - update_statistics(); - } + // Update statistics for this frame + update_statistics(); + } - //////////////////////////////////////// - // - // Handle the regular UI idle callbacks as well as - // hover callbacks - // + //////////////////////////////////////// + // + // Handle the regular UI idle callbacks as well as + // hover callbacks + // #ifdef LL_DARWIN - if (!mQuitRequested) //MAINT-4243 + if (!mQuitRequested) //MAINT-4243 #endif - { -// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); + { +// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); - // Do event notifications if necessary. Yes, we may want to move this elsewhere. - gEventNotifier.update(); + // Do event notifications if necessary. Yes, we may want to move this elsewhere. + gEventNotifier.update(); - gIdleCallbacks.callFunctions(); - gInventory.idleNotifyObservers(); - LLAvatarTracker::instance().idleNotifyObservers(); - } + gIdleCallbacks.callFunctions(); + gInventory.idleNotifyObservers(); + LLAvatarTracker::instance().idleNotifyObservers(); + } - // Metrics logging (LLViewerAssetStats, etc.) - { - static LLTimer report_interval; + // Metrics logging (LLViewerAssetStats, etc.) + { + static LLTimer report_interval; - // *TODO: Add configuration controls for this - F32 seconds = report_interval.getElapsedTimeF32(); - if (seconds >= app_metrics_interval) - { - metricsSend(! gDisconnected); - report_interval.reset(); - } - } + // *TODO: Add configuration controls for this + F32 seconds = report_interval.getElapsedTimeF32(); + if (seconds >= app_metrics_interval) + { + metricsSend(! gDisconnected); + report_interval.reset(); + } + } // Update layonts, handle mouse events, tooltips, e t c @@ -4847,335 +4847,335 @@ void LLAppViewer::idle() // opening chat. gViewerWindow->updateUI(); - if (gDisconnected) + if (gDisconnected) { - return; + return; } - if (gTeleportDisplay) + if (gTeleportDisplay) { - return; + return; } - /////////////////////////////////////// - // Agent and camera movement - // - LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); + /////////////////////////////////////// + // Agent and camera movement + // + LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); - { - // After agent and camera moved, figure out if we need to - // deselect objects. - LLSelectMgr::getInstance()->deselectAllIfTooFar(); + { + // After agent and camera moved, figure out if we need to + // deselect objects. + LLSelectMgr::getInstance()->deselectAllIfTooFar(); - } + } - { - // Handle pending gesture processing - LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); - LLGestureMgr::instance().update(); + { + // Handle pending gesture processing + LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); + LLGestureMgr::instance().update(); - gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); - } + gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); + } - { - LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); + { + LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); if (!(logoutRequestSent() && hasSavedFinalSnapshot())) - { - gObjectList.update(gAgent); - } - } - - ////////////////////////////////////// - // - // Deletes objects... - // Has to be done after doing idleUpdates (which can kill objects) - // - - { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP); - { - gObjectList.cleanDeadObjects(); - } - { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); - LLDrawable::cleanupDeadDrawables(); - } - } - - // - // After this point, in theory we should never see a dead object - // in the various object/drawable lists. - // - - ////////////////////////////////////// - // - // Update/send HUD effects - // - // At this point, HUD effects may clean up some references to - // dead objects. - // - - { - LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); - LLSelectMgr::getInstance()->updateEffects(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDManager::getInstance()->sendEffects(); - } - - //////////////////////////////////////// - // - // Unpack layer data that we've received - // - - { - LL_RECORD_BLOCK_TIME(FTM_NETWORK); - gVLManager.unpackData(); - } - - ///////////////////////// - // - // Update surfaces, and surface textures as well. - // - - LLWorld::getInstance()->updateVisibilities(); - { - const F32 max_region_update_time = .001f; // 1ms - LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); - LLWorld::getInstance()->updateRegions(max_region_update_time); - } - - ///////////////////////// - // - // Update weather effects - // - - // Update wind vector - LLVector3 wind_position_region; - static LLVector3 average_wind; - - LLViewerRegion *regionp; - regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position - if (regionp) - { - gWindVec = regionp->mWind.getVelocity(wind_position_region); - - // Compute average wind and use to drive motion of water - - average_wind = regionp->mWind.getAverage(); - gSky.setWind(average_wind); - //LLVOWater::setWind(average_wind); - } - else - { - gWindVec.setVec(0.0f, 0.0f, 0.0f); - } - - ////////////////////////////////////// - // - // Sort and cull in the new renderer are moved to pipeline.cpp - // Here, particles are updated and drawables are moved. - // - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); - gPipeline.updateMove(); - } - - LLWorld::getInstance()->updateParticles(); - - if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) - { - gAgentPilot.moveCamera(); - } - else if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - LLViewerJoystick::getInstance()->moveFlycam(); - } - else - { - if (LLToolMgr::getInstance()->inBuildMode()) - { - LLViewerJoystick::getInstance()->moveObjects(); - } - - gAgentCamera.updateCamera(); - } - - // update media focus - LLViewerMediaFocus::getInstance()->update(); - - // Update marketplace - LLMarketplaceInventoryImporter::update(); - LLMarketplaceInventoryNotifications::update(); - - // objects and camera should be in sync, do LOD calculations now - { - LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); - gObjectList.updateApparentAngles(gAgent); - } - - // Update AV render info - LLAvatarRenderInfoAccountant::getInstance()->idle(); - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); - - if (gAudiop) - { - audio_update_volume(false); - audio_update_listener(); - audio_update_wind(false); - - // this line actually commits the changes we've made to source positions, etc. - gAudiop->idle(); - } - } - - // Handle shutdown process, for example, - // wait for floaters to close, send quit message, - // forcibly quit if it has taken too long - if (mQuitRequested) - { - gGLActive = TRUE; - idleShutdown(); - } + { + gObjectList.update(gAgent); + } + } + + ////////////////////////////////////// + // + // Deletes objects... + // Has to be done after doing idleUpdates (which can kill objects) + // + + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP); + { + gObjectList.cleanDeadObjects(); + } + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); + LLDrawable::cleanupDeadDrawables(); + } + } + + // + // After this point, in theory we should never see a dead object + // in the various object/drawable lists. + // + + ////////////////////////////////////// + // + // Update/send HUD effects + // + // At this point, HUD effects may clean up some references to + // dead objects. + // + + { + LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); + LLSelectMgr::getInstance()->updateEffects(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDManager::getInstance()->sendEffects(); + } + + //////////////////////////////////////// + // + // Unpack layer data that we've received + // + + { + LL_RECORD_BLOCK_TIME(FTM_NETWORK); + gVLManager.unpackData(); + } + + ///////////////////////// + // + // Update surfaces, and surface textures as well. + // + + LLWorld::getInstance()->updateVisibilities(); + { + const F32 max_region_update_time = .001f; // 1ms + LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); + LLWorld::getInstance()->updateRegions(max_region_update_time); + } + + ///////////////////////// + // + // Update weather effects + // + + // Update wind vector + LLVector3 wind_position_region; + static LLVector3 average_wind; + + LLViewerRegion *regionp; + regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position + if (regionp) + { + gWindVec = regionp->mWind.getVelocity(wind_position_region); + + // Compute average wind and use to drive motion of water + + average_wind = regionp->mWind.getAverage(); + gSky.setWind(average_wind); + //LLVOWater::setWind(average_wind); + } + else + { + gWindVec.setVec(0.0f, 0.0f, 0.0f); + } + + ////////////////////////////////////// + // + // Sort and cull in the new renderer are moved to pipeline.cpp + // Here, particles are updated and drawables are moved. + // + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); + gPipeline.updateMove(); + } + + LLWorld::getInstance()->updateParticles(); + + if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) + { + gAgentPilot.moveCamera(); + } + else if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + LLViewerJoystick::getInstance()->moveFlycam(); + } + else + { + if (LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveObjects(); + } + + gAgentCamera.updateCamera(); + } + + // update media focus + LLViewerMediaFocus::getInstance()->update(); + + // Update marketplace + LLMarketplaceInventoryImporter::update(); + LLMarketplaceInventoryNotifications::update(); + + // objects and camera should be in sync, do LOD calculations now + { + LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); + gObjectList.updateApparentAngles(gAgent); + } + + // Update AV render info + LLAvatarRenderInfoAccountant::getInstance()->idle(); + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); + + if (gAudiop) + { + audio_update_volume(false); + audio_update_listener(); + audio_update_wind(false); + + // this line actually commits the changes we've made to source positions, etc. + gAudiop->idle(); + } + } + + // Handle shutdown process, for example, + // wait for floaters to close, send quit message, + // forcibly quit if it has taken too long + if (mQuitRequested) + { + gGLActive = TRUE; + idleShutdown(); + } } void LLAppViewer::idleShutdown() { - // Wait for all modal alerts to get resolved - if (LLModalDialog::activeCount() > 0) - { - return; - } - - // close IM interface - if(gIMMgr) - { - gIMMgr->disconnectAllSessions(); - } - - // Wait for all floaters to get resolved - if (gFloaterView - && !gFloaterView->allChildrenClosed()) - { - return; - } - - - - - // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup() - // *TODO: ugly - static bool saved_teleport_history = false; - if (!saved_teleport_history) - { - saved_teleport_history = true; - LLTeleportHistory::getInstance()->dump(); - LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this - return; - } - - static bool saved_snapshot = false; - if (!saved_snapshot) - { - saved_snapshot = true; - saveFinalSnapshot(); - return; - } - - const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f; - - S32 pending_uploads = gAssetStorage->getNumPendingUploads(); - if (pending_uploads > 0 - && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME - && !logoutRequestSent()) - { - static S32 total_uploads = 0; - // Sometimes total upload count can change during logout. - total_uploads = llmax(total_uploads, pending_uploads); - gViewerWindow->setShowProgress(TRUE); - S32 finished_uploads = total_uploads - pending_uploads; - F32 percent = 100.f * finished_uploads / total_uploads; - gViewerWindow->setProgressPercent(percent); - gViewerWindow->setProgressString(LLTrans::getString("SavingSettings")); - return; - } - - if (gPendingMetricsUploads > 0 - && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME - && !logoutRequestSent()) - { + // Wait for all modal alerts to get resolved + if (LLModalDialog::activeCount() > 0) + { + return; + } + + // close IM interface + if(gIMMgr) + { + gIMMgr->disconnectAllSessions(); + } + + // Wait for all floaters to get resolved + if (gFloaterView + && !gFloaterView->allChildrenClosed()) + { + return; + } + + + + + // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup() + // *TODO: ugly + static bool saved_teleport_history = false; + if (!saved_teleport_history) + { + saved_teleport_history = true; + LLTeleportHistory::getInstance()->dump(); + LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this + return; + } + + static bool saved_snapshot = false; + if (!saved_snapshot) + { + saved_snapshot = true; + saveFinalSnapshot(); + return; + } + + const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f; + + S32 pending_uploads = gAssetStorage->getNumPendingUploads(); + if (pending_uploads > 0 + && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME + && !logoutRequestSent()) + { + static S32 total_uploads = 0; + // Sometimes total upload count can change during logout. + total_uploads = llmax(total_uploads, pending_uploads); + gViewerWindow->setShowProgress(TRUE); + S32 finished_uploads = total_uploads - pending_uploads; + F32 percent = 100.f * finished_uploads / total_uploads; + gViewerWindow->setProgressPercent(percent); + gViewerWindow->setProgressString(LLTrans::getString("SavingSettings")); + return; + } + + if (gPendingMetricsUploads > 0 + && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME + && !logoutRequestSent()) + { gViewerWindow->setShowProgress(TRUE); gViewerWindow->setProgressPercent(100.f); gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); - return; - } - - // All floaters are closed. Tell server we want to quit. - if( !logoutRequestSent() ) - { - sendLogoutRequest(); - - // Wait for a LogoutReply message - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressPercent(100.f); - gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); - return; - } - - // Make sure that we quit if we haven't received a reply from the server. - if( logoutRequestSent() - && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime ) - { - forceQuit(); - return; - } + return; + } + + // All floaters are closed. Tell server we want to quit. + if( !logoutRequestSent() ) + { + sendLogoutRequest(); + + // Wait for a LogoutReply message + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressPercent(100.f); + gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); + return; + } + + // Make sure that we quit if we haven't received a reply from the server. + if( logoutRequestSent() + && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime ) + { + forceQuit(); + return; + } } void LLAppViewer::sendLogoutRequest() { - if(!mLogoutRequestSent && gMessageSystem) - { - //Set internal status variables and marker files before actually starting the logout process - gLogoutInProgress = TRUE; - if (!mSecondInstance) - { - mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); - - mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB); - if (mLogoutMarkerFile.getFileHandle()) - { - LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL; - recordMarkerVersion(mLogoutMarkerFile); - } - else - { - LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "Did not logout marker file because this is a second instance" << LL_ENDL; - } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_LogoutRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - - gLogoutTimer.reset(); - gLogoutMaxTime = LOGOUT_REQUEST_TIME; - mLogoutRequestSent = TRUE; - - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->leaveChannel(); - } - } + if(!mLogoutRequestSent && gMessageSystem) + { + //Set internal status variables and marker files before actually starting the logout process + gLogoutInProgress = TRUE; + if (!mSecondInstance) + { + mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); + + mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB); + if (mLogoutMarkerFile.getFileHandle()) + { + LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL; + recordMarkerVersion(mLogoutMarkerFile); + } + else + { + LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Did not logout marker file because this is a second instance" << LL_ENDL; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LogoutRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + + gLogoutTimer.reset(); + gLogoutMaxTime = LOGOUT_REQUEST_TIME; + mLogoutRequestSent = TRUE; + + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->leaveChannel(); + } + } } void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) @@ -5221,19 +5221,19 @@ void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) void LLAppViewer::idleNameCache() { - // Neither old nor new name cache can function before agent has a region - LLViewerRegion* region = gAgent.getRegion(); + // Neither old nor new name cache can function before agent has a region + LLViewerRegion* region = gAgent.getRegion(); if (!region) { return; } - // deal with any queued name requests and replies. - gCacheName->processPending(); + // deal with any queued name requests and replies. + gCacheName->processPending(); - // Can't run the new cache until we have the list of capabilities - // for the agent region, and can therefore decide whether to use - // display names or fall back to the old name system. + // Can't run the new cache until we have the list of capabilities + // for the agent region, and can therefore decide whether to use + // display names or fall back to the old name system. if (!region->capabilitiesReceived()) { return; @@ -5263,141 +5263,141 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ void LLAppViewer::idleNetwork() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - pingMainloopTimeout("idleNetwork"); - - gObjectList.mNumNewObjects = 0; - S32 total_decoded = 0; - - if (!gSavedSettings.getBOOL("SpeedTest")) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode - - LLTimer check_message_timer; - // Read all available packets from network - const S64 frame_count = gFrameCount; // U32->S64 - F32 total_time = 0.0f; - - { - LockMessageChecker lmc(gMessageSystem); - while (lmc.checkAllMessages(frame_count, gServicePump)) - { - if (gDoDisconnect) - { - // We're disconnecting, don't process any more messages from the server - // We're usually disconnecting due to either network corruption or a - // server going down, so this is OK. - break; - } - - total_decoded++; - gPacketsIn++; - - if (total_decoded > MESSAGE_MAX_PER_FRAME) - { - break; - } + pingMainloopTimeout("idleNetwork"); + + gObjectList.mNumNewObjects = 0; + S32 total_decoded = 0; + + if (!gSavedSettings.getBOOL("SpeedTest")) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode + + LLTimer check_message_timer; + // Read all available packets from network + const S64 frame_count = gFrameCount; // U32->S64 + F32 total_time = 0.0f; + + { + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(frame_count, gServicePump)) + { + if (gDoDisconnect) + { + // We're disconnecting, don't process any more messages from the server + // We're usually disconnecting due to either network corruption or a + // server going down, so this is OK. + break; + } + + total_decoded++; + gPacketsIn++; + + if (total_decoded > MESSAGE_MAX_PER_FRAME) + { + break; + } #ifdef TIME_THROTTLE_MESSAGES - // Prevent slow packets from completely destroying the frame rate. - // This usually happens due to clumps of avatars taking huge amount - // of network processing time (which needs to be fixed, but this is - // a good limit anyway). - total_time = check_message_timer.getElapsedTimeF32(); - if (total_time >= CheckMessagesMaxTime) - break; + // Prevent slow packets from completely destroying the frame rate. + // This usually happens due to clumps of avatars taking huge amount + // of network processing time (which needs to be fixed, but this is + // a good limit anyway). + total_time = check_message_timer.getElapsedTimeF32(); + if (total_time >= CheckMessagesMaxTime) + break; #endif - } + } - // Handle per-frame message system processing. - lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); - } + // Handle per-frame message system processing. + lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); + } #ifdef TIME_THROTTLE_MESSAGES - if (total_time >= CheckMessagesMaxTime) - { - // Increase CheckMessagesMaxTime so that we will eventually catch up - CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames - } - else - { - // Reset CheckMessagesMaxTime to default value - CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; - } + if (total_time >= CheckMessagesMaxTime) + { + // Increase CheckMessagesMaxTime so that we will eventually catch up + CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames + } + else + { + // Reset CheckMessagesMaxTime to default value + CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; + } #endif - // we want to clear the control after sending out all necessary agent updates - gAgent.resetControlFlags(); - - // Decode enqueued messages... - S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded; - - if( remaining_possible_decodes <= 0 ) - { - LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; - } - - if (gPrintMessagesThisFrame) - { - LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; - gPrintMessagesThisFrame = FALSE; - } - } - add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); - - // Retransmit unacknowledged packets. - gXferManager->retransmitUnackedPackets(); - gAssetStorage->checkForTimeouts(); - gViewerThrottle.updateDynamicThrottle(); - - // Check that the circuit between the viewer and the agent's current - // region is still alive - LLViewerRegion *agent_region = gAgent.getRegion(); - if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) - { - LLUUID this_region_id = agent_region->getRegionID(); - bool this_region_alive = agent_region->isAlive(); - if ((mAgentRegionLastAlive && !this_region_alive) // newly dead - && (mAgentRegionLastID == this_region_id)) // same region - { - forceDisconnect(LLTrans::getString("AgentLostConnection")); - } - mAgentRegionLastID = this_region_id; - mAgentRegionLastAlive = this_region_alive; - } + // we want to clear the control after sending out all necessary agent updates + gAgent.resetControlFlags(); + + // Decode enqueued messages... + S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded; + + if( remaining_possible_decodes <= 0 ) + { + LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; + } + + if (gPrintMessagesThisFrame) + { + LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; + gPrintMessagesThisFrame = FALSE; + } + } + add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); + + // Retransmit unacknowledged packets. + gXferManager->retransmitUnackedPackets(); + gAssetStorage->checkForTimeouts(); + gViewerThrottle.updateDynamicThrottle(); + + // Check that the circuit between the viewer and the agent's current + // region is still alive + LLViewerRegion *agent_region = gAgent.getRegion(); + if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) + { + LLUUID this_region_id = agent_region->getRegionID(); + bool this_region_alive = agent_region->isAlive(); + if ((mAgentRegionLastAlive && !this_region_alive) // newly dead + && (mAgentRegionLastID == this_region_id)) // same region + { + forceDisconnect(LLTrans::getString("AgentLostConnection")); + } + mAgentRegionLastID = this_region_id; + mAgentRegionLastAlive = this_region_alive; + } } void LLAppViewer::disconnectViewer() { - if (gDisconnected) - { - return; - } - // - // Cleanup after quitting. - // - // Save snapshot for next time, if we made it through initialization - - LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; - - // Dump our frame statistics - - // Remember if we were flying - gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); - - // Un-minimize all windows so they don't get saved minimized - if (gFloaterView) - { - gFloaterView->restoreAll(); - } - - if (LLSelectMgr::instanceExists()) - { - LLSelectMgr::getInstance()->deselectAll(); - } - - // save inventory if appropriate + if (gDisconnected) + { + return; + } + // + // Cleanup after quitting. + // + // Save snapshot for next time, if we made it through initialization + + LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; + + // Dump our frame statistics + + // Remember if we were flying + gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); + + // Un-minimize all windows so they don't get saved minimized + if (gFloaterView) + { + gFloaterView->restoreAll(); + } + + if (LLSelectMgr::instanceExists()) + { + LLSelectMgr::getInstance()->deselectAll(); + } + + // save inventory if appropriate if (gInventory.isInventoryUsable() && gAgent.getID().notNull()) // Shouldn't be null at this stage { @@ -5412,44 +5412,44 @@ void LLAppViewer::disconnectViewer() } } - saveNameCache(); - if (LLExperienceCache::instanceExists()) - { - // TODO: LLExperienceCache::cleanup() logic should be moved to - // cleanupSingleton(). - LLExperienceCache::instance().cleanup(); - } + saveNameCache(); + if (LLExperienceCache::instanceExists()) + { + // TODO: LLExperienceCache::cleanup() logic should be moved to + // cleanupSingleton(). + LLExperienceCache::instance().cleanup(); + } - // close inventory interface, close all windows - LLSidepanelInventory::cleanup(); + // close inventory interface, close all windows + LLSidepanelInventory::cleanup(); - gAgentWearables.cleanup(); - gAgentCamera.cleanup(); - // Also writes cached agent settings to gSavedSettings - gAgent.cleanup(); + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + // Also writes cached agent settings to gSavedSettings + gAgent.cleanup(); - // This is where we used to call gObjectList.destroy() and then delete gWorldp. - // Now we just ask the LLWorld singleton to cleanly shut down. - if(LLWorld::instanceExists()) - { - LLWorld::getInstance()->resetClass(); - } - LLVOCache::deleteSingleton(); + // This is where we used to call gObjectList.destroy() and then delete gWorldp. + // Now we just ask the LLWorld singleton to cleanly shut down. + if(LLWorld::instanceExists()) + { + LLWorld::getInstance()->resetClass(); + } + LLVOCache::deleteSingleton(); - // call all self-registered classes - LLDestroyClassList::instance().fireCallbacks(); + // call all self-registered classes + LLDestroyClassList::instance().fireCallbacks(); - cleanup_xfer_manager(); - gDisconnected = TRUE; + cleanup_xfer_manager(); + gDisconnected = TRUE; - // Pass the connection state to LLUrlEntryParcel not to attempt - // parcel info requests while disconnected. - LLUrlEntryParcel::setDisconnected(gDisconnected); + // Pass the connection state to LLUrlEntryParcel not to attempt + // parcel info requests while disconnected. + LLUrlEntryParcel::setDisconnected(gDisconnected); } void LLAppViewer::forceErrorLLError() { - LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; + LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; } void LLAppViewer::forceErrorLLErrorMsg() @@ -5462,7 +5462,7 @@ void LLAppViewer::forceErrorLLErrorMsg() void LLAppViewer::forceErrorBreakpoint() { - LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; #ifdef LL_WINDOWS DebugBreak(); #else @@ -5473,7 +5473,7 @@ void LLAppViewer::forceErrorBreakpoint() void LLAppViewer::forceErrorBadMemoryAccess() { - LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; S32* crash = NULL; *crash = 0xDEADBEEF; return; @@ -5481,7 +5481,7 @@ void LLAppViewer::forceErrorBadMemoryAccess() void LLAppViewer::forceErrorInfiniteLoop() { - LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; // Loop is intentionally complicated to fool basic loop detection LLTimer timer_total; LLTimer timer_expiry; @@ -5500,7 +5500,7 @@ void LLAppViewer::forceErrorInfiniteLoop() void LLAppViewer::forceErrorSoftwareException() { - LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; LLTHROW(LLException("User selected Force Software Exception")); } @@ -5513,8 +5513,8 @@ void LLAppViewer::forceErrorOSSpecificException() void LLAppViewer::forceErrorDriverCrash() { - LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; - glDeleteTextures(1, NULL); + LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; + glDeleteTextures(1, NULL); } void LLAppViewer::forceErrorCoroutineCrash() @@ -5546,120 +5546,120 @@ void LLAppViewer::forceErrorThreadCrash() void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) { - if(!mMainloopTimeout) - { - mMainloopTimeout = new LLWatchdogTimeout(); - resumeMainloopTimeout(state, secs); - } + if(!mMainloopTimeout) + { + mMainloopTimeout = new LLWatchdogTimeout(); + resumeMainloopTimeout(state, secs); + } } void LLAppViewer::destroyMainloopTimeout() { - if(mMainloopTimeout) - { - delete mMainloopTimeout; - mMainloopTimeout = NULL; - } + if(mMainloopTimeout) + { + delete mMainloopTimeout; + mMainloopTimeout = NULL; + } } void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) { - if(mMainloopTimeout) - { - if(secs < 0.0f) - { - static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); - secs = mainloop_timeout; - } - - mMainloopTimeout->setTimeout(secs); - mMainloopTimeout->start(state); - } + if(mMainloopTimeout) + { + if(secs < 0.0f) + { + static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; + } + + mMainloopTimeout->setTimeout(secs); + mMainloopTimeout->start(state); + } } void LLAppViewer::pauseMainloopTimeout() { - if(mMainloopTimeout) - { - mMainloopTimeout->stop(); - } + if(mMainloopTimeout) + { + mMainloopTimeout->stop(); + } } void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) { LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - if(mMainloopTimeout) - { - if(secs < 0.0f) - { - static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); - secs = mainloop_timeout; - } - - mMainloopTimeout->setTimeout(secs); - mMainloopTimeout->ping(state); - } + if(mMainloopTimeout) + { + if(secs < 0.0f) + { + static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; + } + + mMainloopTimeout->setTimeout(secs); + mMainloopTimeout->ping(state); + } } void LLAppViewer::handleLoginComplete() { - gLoggedInTime.start(); - initMainloopTimeout("Mainloop Init"); - - // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if ( parcel && parcel->getMusicURL()[0]) - { - gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); - } - if ( parcel && parcel->getMediaURL()[0]) - { - gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); - } - - gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); - gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); - gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); - gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - - if(gAgent.getRegion()) - { - gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); - gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); - } - - if(LLAppViewer::instance()->mMainloopTimeout) - { - gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); - } - - mOnLoginCompleted(); - - writeDebugInfo(); - - // we logged in successfully, so save settings on logout - LL_INFOS() << "Login successful, per account settings will be saved on log out." << LL_ENDL; - mSavePerAccountSettings=true; + gLoggedInTime.start(); + initMainloopTimeout("Mainloop Init"); + + // Store some data to DebugInfo in case of a freeze. + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if ( parcel && parcel->getMusicURL()[0]) + { + gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); + } + if ( parcel && parcel->getMediaURL()[0]) + { + gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); + } + + gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); + + if(gAgent.getRegion()) + { + gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); + gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); + } + + if(LLAppViewer::instance()->mMainloopTimeout) + { + gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); + } + + mOnLoginCompleted(); + + writeDebugInfo(); + + // we logged in successfully, so save settings on logout + LL_INFOS() << "Login successful, per account settings will be saved on log out." << LL_ENDL; + mSavePerAccountSettings=true; } //virtual void LLAppViewer::setMasterSystemAudioMute(bool mute) { - gSavedSettings.setBOOL("MuteAudio", mute); + gSavedSettings.setBOOL("MuteAudio", mute); } //virtual bool LLAppViewer::getMasterSystemAudioMute() { - return gSavedSettings.getBOOL("MuteAudio"); + return gSavedSettings.getBOOL("MuteAudio"); } //---------------------------------------------------------------------------- @@ -5675,10 +5675,10 @@ bool LLAppViewer::getMasterSystemAudioMute() */ void LLAppViewer::metricsUpdateRegion(U64 region_handle) { - if (0 != region_handle) - { - LLViewerAssetStatsFF::set_region(region_handle); - } + if (0 != region_handle) + { + LLViewerAssetStatsFF::set_region(region_handle); + } } /** @@ -5687,35 +5687,35 @@ void LLAppViewer::metricsUpdateRegion(U64 region_handle) */ void LLAppViewer::metricsSend(bool enable_reporting) { - if (! gViewerAssetStats) - return; + if (! gViewerAssetStats) + return; - if (LLAppViewer::sTextureFetch) - { - LLViewerRegion * regionp = gAgent.getRegion(); + if (LLAppViewer::sTextureFetch) + { + LLViewerRegion * regionp = gAgent.getRegion(); - if (enable_reporting && regionp) - { - std::string caps_url = regionp->getCapability("ViewerMetrics"); + if (enable_reporting && regionp) + { + std::string caps_url = regionp->getCapability("ViewerMetrics"); LLSD sd = gViewerAssetStats->asLLSD(true); - // Send a report request into 'thread1' to get the rest of the data - // and provide some additional parameters while here. - LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, - gAgentSessionID, - gAgentID, - sd); - } - else - { - LLAppViewer::sTextureFetch->commandDataBreak(); - } - } - - // Reset even if we can't report. Rather than gather up a huge chunk of - // data, we'll keep to our sampling interval and retain the data - // resolution in time. - gViewerAssetStats->restart(); + // Send a report request into 'thread1' to get the rest of the data + // and provide some additional parameters while here. + LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, + gAgentSessionID, + gAgentID, + sd); + } + else + { + LLAppViewer::sTextureFetch->commandDataBreak(); + } + } + + // Reset even if we can't report. Rather than gather up a huge chunk of + // data, we'll keep to our sampling interval and retain the data + // resolution in time. + gViewerAssetStats->restart(); } diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 93a0ef0e82..b4ced668d0 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldonotdisturbnotificationstorage.cpp * @brief Implementation of lldonotdisturbnotificationstorage * @author Stinson@lindenlab.com @@ -68,7 +68,7 @@ bool LLDoNotDisturbNotificationStorageTimer::tick() } LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage() - : LLNotificationStorage("") + : LLNotificationStorage("") , mDirty(false) { nameToPayloadParameterMap[toastName] = "SESSION_ID"; @@ -88,7 +88,7 @@ void LLDoNotDisturbNotificationStorage::reset() void LLDoNotDisturbNotificationStorage::initialize() { reset(); - getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1)); + getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1)); } bool LLDoNotDisturbNotificationStorage::getDirty() @@ -105,27 +105,27 @@ void LLDoNotDisturbNotificationStorage::saveNotifications() { LL_PROFILE_ZONE_SCOPED; - LLNotificationChannelPtr channelPtr = getCommunicationChannel(); - const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get()); - llassert(commChannel != NULL); + LLNotificationChannelPtr channelPtr = getCommunicationChannel(); + const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get()); + llassert(commChannel != NULL); - LLSD output = LLSD::emptyMap(); - LLSD& data = output["data"]; - data = LLSD::emptyArray(); + LLSD output = LLSD::emptyMap(); + LLSD& data = output["data"]; + data = LLSD::emptyArray(); - for (LLCommunicationChannel::history_list_t::const_iterator historyIter = commChannel->beginHistory(); - historyIter != commChannel->endHistory(); ++historyIter) - { - LLNotificationPtr notificationPtr = historyIter->second; + for (LLCommunicationChannel::history_list_t::const_iterator historyIter = commChannel->beginHistory(); + historyIter != commChannel->endHistory(); ++historyIter) + { + LLNotificationPtr notificationPtr = historyIter->second; - if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && - !notificationPtr->isExpired() && !notificationPtr->isPersistent()) - { - data.append(notificationPtr->asLLSD(true)); - } - } + if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && + !notificationPtr->isExpired() && !notificationPtr->isPersistent()) + { + data.append(notificationPtr->asLLSD(true)); + } + } - writeNotifications(output); + writeNotifications(output); resetDirty(); } @@ -134,114 +134,114 @@ static LLTrace::BlockTimerStatHandle FTM_LOAD_DND_NOTIFICATIONS("Load DND Notifi void LLDoNotDisturbNotificationStorage::loadNotifications() { - LL_RECORD_BLOCK_TIME(FTM_LOAD_DND_NOTIFICATIONS); - - LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL; - - LLSD input; - if (!readNotifications(input) ||input.isUndefined()) - { - return; - } - - LLSD& data = input["data"]; - if (data.isUndefined()) - { - return; - } - - LLNotifications& instance = LLNotifications::instance(); + LL_RECORD_BLOCK_TIME(FTM_LOAD_DND_NOTIFICATIONS); + + LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL; + + LLSD input; + if (!readNotifications(input) ||input.isUndefined()) + { + return; + } + + LLSD& data = input["data"]; + if (data.isUndefined()) + { + return; + } + + LLNotifications& instance = LLNotifications::instance(); bool imToastExists = false; - bool group_ad_hoc_toast_exists = false; - S32 toastSessionType; + bool group_ad_hoc_toast_exists = false; + S32 toastSessionType; bool offerExists = false; - - for (LLSD::array_const_iterator notification_it = data.beginArray(); - notification_it != data.endArray(); - ++notification_it) - { - LLSD notification_params = *notification_it; + + for (LLSD::array_const_iterator notification_it = data.beginArray(); + notification_it != data.endArray(); + ++notification_it) + { + LLSD notification_params = *notification_it; const LLUUID& notificationID = notification_params["id"]; std::string notificationName = notification_params["name"]; LLNotificationPtr notification = instance.find(notificationID); if(notificationName == toastName) { - toastSessionType = notification_params["payload"]["SESSION_TYPE"]; - if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION) - { - imToastExists = true; - } - //Don't add group/ad-hoc messages to the notification system because - //this means the group/ad-hoc session has to be re-created - else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION - || toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION) - { - //Just allows opening the conversation log for group/ad-hoc messages upon startup - group_ad_hoc_toast_exists = true; - continue; - } + toastSessionType = notification_params["payload"]["SESSION_TYPE"]; + if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION) + { + imToastExists = true; + } + //Don't add group/ad-hoc messages to the notification system because + //this means the group/ad-hoc session has to be re-created + else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION + || toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION) + { + //Just allows opening the conversation log for group/ad-hoc messages upon startup + group_ad_hoc_toast_exists = true; + continue; + } } else if(notificationName == offerName) { offerExists = true; } - - //Notification already exists due to persistent storage adding it first into the notification system - if(notification) - { - notification->setDND(true); - instance.update(instance.find(notificationID)); - } - //New notification needs to be added - else - { - notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true)); - LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]); - if (responder == NULL) - { - LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '" - << notification->getType() << "'" << LL_ENDL; - } - else - { - LLNotificationResponderPtr responderPtr(responder); - notification->setResponseFunctor(responderPtr); - } - - instance.add(notification); - } - - } + + //Notification already exists due to persistent storage adding it first into the notification system + if(notification) + { + notification->setDND(true); + instance.update(instance.find(notificationID)); + } + //New notification needs to be added + else + { + notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true)); + LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]); + if (responder == NULL) + { + LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '" + << notification->getType() << "'" << LL_ENDL; + } + else + { + LLNotificationResponderPtr responderPtr(responder); + notification->setResponseFunctor(responderPtr); + } + + instance.add(notification); + } + + } bool isConversationLoggingAllowed = gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0; - if(group_ad_hoc_toast_exists && isConversationLoggingAllowed) - { - LLFloaterReg::showInstance("conversation"); - } + if(group_ad_hoc_toast_exists && isConversationLoggingAllowed) + { + LLFloaterReg::showInstance("conversation"); + } if(imToastExists || group_ad_hoc_toast_exists || offerExists) { - make_ui_sound_deferred("UISndNewIncomingIMSession"); + make_ui_sound_deferred("UISndNewIncomingIMSession"); } //writes out empty .xml file (since LLCommunicationChannel::mHistory is empty) - saveNotifications(); + saveNotifications(); - LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL; + LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL; } void LLDoNotDisturbNotificationStorage::updateNotifications() { - LLNotificationChannelPtr channelPtr = getCommunicationChannel(); - LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get()); - llassert(commChannel != NULL); + LLNotificationChannelPtr channelPtr = getCommunicationChannel(); + LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get()); + llassert(commChannel != NULL); LLNotifications& instance = LLNotifications::instance(); bool imToastExists = false; bool offerExists = false; - + for (LLCommunicationChannel::history_list_t::const_iterator it = commChannel->beginHistory(); it != commChannel->endHistory(); ++it) @@ -274,16 +274,16 @@ void LLDoNotDisturbNotificationStorage::updateNotifications() //When exit DND mode, write empty notifications file if(commChannel->getHistorySize()) { - commChannel->clearHistory(); - saveNotifications(); + commChannel->clearHistory(); + saveNotifications(); } } LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChannel() const { - LLNotificationChannelPtr channelPtr = LLNotifications::getInstance()->getChannel("Communication"); - llassert(channelPtr); - return channelPtr; + LLNotificationChannelPtr channelPtr = LLNotifications::getInstance()->getChannel("Communication"); + llassert(channelPtr); + return channelPtr; } void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, const LLUUID& id) @@ -301,7 +301,7 @@ void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, co //Find notification with the matching session id for (it = commChannel->beginHistory(); - it != commChannel->endHistory(); + it != commChannel->endHistory(); ++it) { notification = it->second; @@ -336,10 +336,10 @@ void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, co bool LLDoNotDisturbNotificationStorage::onChannelChanged(const LLSD& pPayload) { - if (pPayload["sigtype"].asString() != "load") - { + if (pPayload["sigtype"].asString() != "load") + { mDirty = true; - } + } - return false; + return false; } diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index 2d39b5efed..0dc2515e02 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -1,4 +1,4 @@ -/** +/** * @file lldonotdisturbnotificationstorage.h * @brief Header file for lldonotdisturbnotificationstorage * @author Stinson@lindenlab.com @@ -47,18 +47,18 @@ public: class LLDoNotDisturbNotificationStorage : public LLParamSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage { - LLSINGLETON(LLDoNotDisturbNotificationStorage); - ~LLDoNotDisturbNotificationStorage(); + LLSINGLETON(LLDoNotDisturbNotificationStorage); + ~LLDoNotDisturbNotificationStorage(); - LOG_CLASS(LLDoNotDisturbNotificationStorage); + LOG_CLASS(LLDoNotDisturbNotificationStorage); public: static const char * toastName; static const char * offerName; bool getDirty(); void resetDirty(); - void saveNotifications(); - void loadNotifications(); + void saveNotifications(); + void loadNotifications(); void updateNotifications(); void removeNotification(const char * name, const LLUUID& id); void reset(); @@ -71,8 +71,8 @@ private: bool mDirty; LLDoNotDisturbNotificationStorageTimer mTimer; - LLNotificationChannelPtr getCommunicationChannel() const; - bool onChannelChanged(const LLSD& pPayload); + LLNotificationChannelPtr getCommunicationChannel() const; + bool onChannelChanged(const LLSD& pPayload); std::map<std::string, std::string> nameToPayloadParameterMap; }; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 68952c96c5..e654caf1b2 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ #include "llframetimer.h" #include "lltrans.h" #include "llviewercontrol.h" -#include "llwindow.h" // beforeDialog() +#include "llwindow.h" // beforeDialog() #if LL_SDL #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers @@ -76,149 +76,149 @@ LLFilePicker LLFilePicker::sInstance; // Implementation // LLFilePicker::LLFilePicker() - : mCurrentFile(0), - mLocked(false) + : mCurrentFile(0), + mLocked(false) { - reset(); + reset(); #if LL_WINDOWS - mOFN.lStructSize = sizeof(OPENFILENAMEW); - mOFN.hwndOwner = NULL; // Set later - mOFN.hInstance = NULL; - mOFN.lpstrCustomFilter = NULL; - mOFN.nMaxCustFilter = 0; - mOFN.lpstrFile = NULL; // set in open and close - mOFN.nMaxFile = LL_MAX_PATH; - mOFN.lpstrFileTitle = NULL; - mOFN.nMaxFileTitle = 0; - mOFN.lpstrInitialDir = NULL; - mOFN.lpstrTitle = NULL; - mOFN.Flags = 0; // set in open and close - mOFN.nFileOffset = 0; - mOFN.nFileExtension = 0; - mOFN.lpstrDefExt = NULL; - mOFN.lCustData = 0L; - mOFN.lpfnHook = NULL; - mOFN.lpTemplateName = NULL; - mFilesW[0] = '\0'; + mOFN.lStructSize = sizeof(OPENFILENAMEW); + mOFN.hwndOwner = NULL; // Set later + mOFN.hInstance = NULL; + mOFN.lpstrCustomFilter = NULL; + mOFN.nMaxCustFilter = 0; + mOFN.lpstrFile = NULL; // set in open and close + mOFN.nMaxFile = LL_MAX_PATH; + mOFN.lpstrFileTitle = NULL; + mOFN.nMaxFileTitle = 0; + mOFN.lpstrInitialDir = NULL; + mOFN.lpstrTitle = NULL; + mOFN.Flags = 0; // set in open and close + mOFN.nFileOffset = 0; + mOFN.nFileExtension = 0; + mOFN.lpstrDefExt = NULL; + mOFN.lCustData = 0L; + mOFN.lpfnHook = NULL; + mOFN.lpTemplateName = NULL; + mFilesW[0] = '\0'; #elif LL_DARWIN - mPickOptions = 0; + mPickOptions = 0; #endif } LLFilePicker::~LLFilePicker() { - // nothing + // nothing } -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLFilePicker::check_local_file_access_enabled() { - // if local file browsing is turned off, return without opening dialog - bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled"); - if ( ! local_file_system_browsing_enabled ) - { - mFiles.clear(); - return false; - } - - return true; + // if local file browsing is turned off, return without opening dialog + bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled"); + if ( ! local_file_system_browsing_enabled ) + { + mFiles.clear(); + return false; + } + + return true; } const std::string LLFilePicker::getFirstFile() { - mCurrentFile = 0; - return getNextFile(); + mCurrentFile = 0; + return getNextFile(); } const std::string LLFilePicker::getNextFile() { - if (mCurrentFile >= getFileCount()) - { - mLocked = false; - return std::string(); - } - else - { - return mFiles[mCurrentFile++]; - } + if (mCurrentFile >= getFileCount()) + { + mLocked = false; + return std::string(); + } + else + { + return mFiles[mCurrentFile++]; + } } const std::string LLFilePicker::getCurFile() { - if (mCurrentFile >= getFileCount()) - { - mLocked = false; - return std::string(); - } - else - { - return mFiles[mCurrentFile]; - } + if (mCurrentFile >= getFileCount()) + { + mLocked = false; + return std::string(); + } + else + { + return mFiles[mCurrentFile]; + } } void LLFilePicker::reset() { - mLocked = false; - mFiles.clear(); - mCurrentFile = 0; + mLocked = false; + mFiles.clear(); + mCurrentFile = 0; } #if LL_WINDOWS BOOL LLFilePicker::setupFilter(ELoadFilter filter) { - BOOL res = TRUE; - switch (filter) - { + BOOL res = TRUE; + switch (filter) + { case FFLOAD_ALL: case FFLOAD_EXE: - mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ - SOUND_FILTER \ - IMAGE_FILTER \ - ANIM_FILTER \ - MATERIAL_FILTER \ - L"\0"; - break; - case FFLOAD_WAV: - mOFN.lpstrFilter = SOUND_FILTER \ - L"\0"; - break; - case FFLOAD_IMAGE: - mOFN.lpstrFilter = IMAGE_FILTER \ - L"\0"; - break; - case FFLOAD_ANIM: - mOFN.lpstrFilter = ANIM_FILTER \ - L"\0"; - break; - case FFLOAD_GLTF: - mOFN.lpstrFilter = GLTF_FILTER \ - L"\0"; - break; - case FFLOAD_COLLADA: - mOFN.lpstrFilter = COLLADA_FILTER \ - L"\0"; - break; - case FFLOAD_XML: - mOFN.lpstrFilter = XML_FILTER \ - L"\0"; - break; - case FFLOAD_SLOBJECT: - mOFN.lpstrFilter = SLOBJECT_FILTER \ - L"\0"; - break; - case FFLOAD_RAW: - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFLOAD_MODEL: - mOFN.lpstrFilter = MODEL_FILTER \ - L"\0"; - break; + mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ + SOUND_FILTER \ + IMAGE_FILTER \ + ANIM_FILTER \ + MATERIAL_FILTER \ + L"\0"; + break; + case FFLOAD_WAV: + mOFN.lpstrFilter = SOUND_FILTER \ + L"\0"; + break; + case FFLOAD_IMAGE: + mOFN.lpstrFilter = IMAGE_FILTER \ + L"\0"; + break; + case FFLOAD_ANIM: + mOFN.lpstrFilter = ANIM_FILTER \ + L"\0"; + break; + case FFLOAD_GLTF: + mOFN.lpstrFilter = GLTF_FILTER \ + L"\0"; + break; + case FFLOAD_COLLADA: + mOFN.lpstrFilter = COLLADA_FILTER \ + L"\0"; + break; + case FFLOAD_XML: + mOFN.lpstrFilter = XML_FILTER \ + L"\0"; + break; + case FFLOAD_SLOBJECT: + mOFN.lpstrFilter = SLOBJECT_FILTER \ + L"\0"; + break; + case FFLOAD_RAW: + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFLOAD_MODEL: + mOFN.lpstrFilter = MODEL_FILTER \ + L"\0"; + break; case FFLOAD_MATERIAL: mOFN.lpstrFilter = MATERIAL_FILTER \ L"\0"; @@ -229,74 +229,74 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) IMAGE_FILTER \ L"\0"; break; - case FFLOAD_SCRIPT: - mOFN.lpstrFilter = SCRIPT_FILTER \ - L"\0"; - break; - case FFLOAD_DICTIONARY: - mOFN.lpstrFilter = DICTIONARY_FILTER \ - L"\0"; - break; + case FFLOAD_SCRIPT: + mOFN.lpstrFilter = SCRIPT_FILTER \ + L"\0"; + break; + case FFLOAD_DICTIONARY: + mOFN.lpstrFilter = DICTIONARY_FILTER \ + L"\0"; + break; case FFLOAD_LUA: mOFN.lpstrFilter = LUA_FILTER \ L"\0"; break; - default: - res = FALSE; - break; - } - return res; + default: + res = FALSE; + break; + } + return res; } BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; - mOFN.nFilterIndex = 1; - - setupFilter(filter); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - reset(); - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - - if (blocking) - { - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - } - - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + mOFN.lpstrFile = mFilesW; + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; + mOFN.nFilterIndex = 1; + + setupFilter(filter); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + reset(); + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + + return success; } BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, @@ -310,79 +310,79 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nFilterIndex = 1; - mOFN.nMaxFile = FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | - OFN_EXPLORER | OFN_ALLOWMULTISELECT; - - setupFilter(filter); - - reset(); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); // pauses until ok or cancel. - if( success ) - { - // The getopenfilename api doesn't tell us if we got more than - // one file, so we have to test manually by checking string - // lengths. - if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - else - { - mLocked = true; - WCHAR* tptrw = mFilesW; - std::string dirname; - while(1) - { - if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' - break; - if (*tptrw == 0) - tptrw++; // shouldn't happen? - std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); - if (dirname.empty()) - dirname = filename + "\\"; - else - mFiles.push_back(dirname + filename); - tptrw += wcslen(tptrw); - } - } - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + mOFN.lpstrFile = mFilesW; + mOFN.nFilterIndex = 1; + mOFN.nMaxFile = FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | + OFN_EXPLORER | OFN_ALLOWMULTISELECT; + + setupFilter(filter); + + reset(); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); // pauses until ok or cancel. + if( success ) + { + // The getopenfilename api doesn't tell us if we got more than + // one file, so we have to test manually by checking string + // lengths. + if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + else + { + mLocked = true; + WCHAR* tptrw = mFilesW; + std::string dirname; + while(1) + { + if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' + break; + if (*tptrw == 0) + tptrw++; // shouldn't happen? + std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); + if (dirname.empty()) + dirname = filename + "\\"; + else + mFiles.push_back(dirname + filename); + tptrw += wcslen(tptrw); + } + } + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, @@ -396,222 +396,222 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - mOFN.lpstrFile = mFilesW; - if (!filename.empty()) - { - llutf16string tstring = utf8str_to_utf16str(filename); - wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ - else - { - mFilesW[0] = '\0'; - } - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - - switch( filter ) - { - case FFSAVE_ALL: - mOFN.lpstrDefExt = NULL; - mOFN.lpstrFilter = - L"All Files (*.*)\0*.*\0" \ - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ - L"\0"; - break; - case FFSAVE_WAV: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"wav"; - mOFN.lpstrFilter = - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"\0"; - break; - case FFSAVE_TGA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"tga"; - mOFN.lpstrFilter = - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - case FFSAVE_BMP: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"bmp"; - mOFN.lpstrFilter = - L"Bitmap Images (*.bmp)\0*.bmp\0" \ - L"\0"; - break; - case FFSAVE_PNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"\0"; - break; - case FFSAVE_TGAPNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - //PNG by default - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - - case FFSAVE_JPEG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"jpg"; - mOFN.lpstrFilter = - L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ - L"\0"; - break; - case FFSAVE_AVI: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"avi"; - mOFN.lpstrFilter = - L"AVI Movie File (*.avi)\0*.avi\0" \ - L"\0"; - break; - case FFSAVE_ANIM: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"xaf"; - mOFN.lpstrFilter = - L"XAF Anim File (*.xaf)\0*.xaf\0" \ - L"\0"; - break; - case FFSAVE_GLTF: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"glb"; - mOFN.lpstrFilter = - L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ - L"\0"; - break; - case FFSAVE_XML: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - - mOFN.lpstrDefExt = L"xml"; - mOFN.lpstrFilter = - L"XML File (*.xml)\0*.xml\0" \ - L"\0"; - break; - case FFSAVE_COLLADA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"collada"; - mOFN.lpstrFilter = - L"COLLADA File (*.collada)\0*.collada\0" \ - L"\0"; - break; - case FFSAVE_RAW: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"raw"; - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFSAVE_J2C: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"j2c"; - mOFN.lpstrFilter = - L"Compressed Images (*.j2c)\0*.j2c\0" \ - L"\0"; - break; - case FFSAVE_SCRIPT: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"txt"; - mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; - break; - default: - return FALSE; - } - - - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; - - reset(); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - { - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - try - { - success = GetSaveFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - } - catch (...) - { - LOG_UNHANDLED_EXCEPTION(""); - } - gKeyboard->resetKeys(); - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + mOFN.lpstrFile = mFilesW; + if (!filename.empty()) + { + llutf16string tstring = utf8str_to_utf16str(filename); + wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ + else + { + mFilesW[0] = '\0'; + } + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + + switch( filter ) + { + case FFSAVE_ALL: + mOFN.lpstrDefExt = NULL; + mOFN.lpstrFilter = + L"All Files (*.*)\0*.*\0" \ + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ + L"\0"; + break; + case FFSAVE_WAV: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"wav"; + mOFN.lpstrFilter = + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"\0"; + break; + case FFSAVE_TGA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"tga"; + mOFN.lpstrFilter = + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + case FFSAVE_BMP: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"bmp"; + mOFN.lpstrFilter = + L"Bitmap Images (*.bmp)\0*.bmp\0" \ + L"\0"; + break; + case FFSAVE_PNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"\0"; + break; + case FFSAVE_TGAPNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + //PNG by default + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + + case FFSAVE_JPEG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"jpg"; + mOFN.lpstrFilter = + L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ + L"\0"; + break; + case FFSAVE_AVI: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"avi"; + mOFN.lpstrFilter = + L"AVI Movie File (*.avi)\0*.avi\0" \ + L"\0"; + break; + case FFSAVE_ANIM: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"xaf"; + mOFN.lpstrFilter = + L"XAF Anim File (*.xaf)\0*.xaf\0" \ + L"\0"; + break; + case FFSAVE_GLTF: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"glb"; + mOFN.lpstrFilter = + L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ + L"\0"; + break; + case FFSAVE_XML: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + + mOFN.lpstrDefExt = L"xml"; + mOFN.lpstrFilter = + L"XML File (*.xml)\0*.xml\0" \ + L"\0"; + break; + case FFSAVE_COLLADA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"collada"; + mOFN.lpstrFilter = + L"COLLADA File (*.collada)\0*.collada\0" \ + L"\0"; + break; + case FFSAVE_RAW: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"raw"; + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFSAVE_J2C: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"j2c"; + mOFN.lpstrFilter = + L"Compressed Images (*.j2c)\0*.j2c\0" \ + L"\0"; + break; + case FFSAVE_SCRIPT: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"txt"; + mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; + break; + default: + return FALSE; + } + + + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; + + reset(); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + { + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + try + { + success = GetSaveFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(""); + } + gKeyboard->resetKeys(); + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -690,25 +690,25 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF LL_WARNS() << "Unsupported format." << LL_ENDL; } - return allowedv; + return allowedv; } -bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) +bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) { - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return false; - } - - gViewerWindow->getWindow()->beforeDialog(); - + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } + + gViewerWindow->getWindow()->beforeDialog(); + std::unique_ptr<std::vector<std::string>> allowed_types = navOpenFilterProc(filter); - + std::unique_ptr<std::vector<std::string>> filev = doLoadDialog(allowed_types.get(), mPickOptions); - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); if (filev && filev->size() > 0) @@ -716,8 +716,8 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) mFiles.insert(mFiles.end(), filev->begin(), filev->end()); return true; } - - return false; + + return false; } bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, @@ -729,14 +729,14 @@ bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, { return false; } - + std::unique_ptr<std::vector<std::string>> allowed_types=navOpenFilterProc(filter); - + doLoadDialogModeless(allowed_types.get(), mPickOptions, callback, userdata); - + return true; } @@ -790,13 +790,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "\?\?\?\?"; extension = "glb"; break; - + case LLFilePicker::FFSAVE_XML: type = "\?\?\?\?"; creator = "\?\?\?\?"; extension = "xml"; break; - + case LLFilePicker::FFSAVE_RAW: type = "\?\?\?\?"; creator = "\?\?\?\?"; @@ -808,13 +808,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "prvw"; extension = "j2c"; break; - + case LLFilePicker::FFSAVE_SCRIPT: type = "LSL "; creator = "\?\?\?\?"; extension = "lsl"; break; - + case LLFilePicker::FFSAVE_ALL: default: type = "\?\?\?\?"; @@ -824,34 +824,34 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, } } -bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) { - // Setup the type, creator, and extension - std::string extension, type, creator; - + // Setup the type, creator, and extension + std::string extension, type, creator; + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; - - gViewerWindow->getWindow()->beforeDialog(); - // Run the dialog - std::unique_ptr<std::string> filev = doSaveDialog(&namestring, + gViewerWindow->getWindow()->beforeDialog(); + + // Run the dialog + std::unique_ptr<std::string> filev = doSaveDialog(&namestring, &type, &creator, &extension, mPickOptions); - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); - if ( filev && !filev->empty() ) - { + if ( filev && !filev->empty() ) + { mFiles.push_back(*filev); - return true; + return true; } - - return false; + + return false; } bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, @@ -861,9 +861,9 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; @@ -880,57 +880,57 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; + if( mLocked ) + return FALSE; - BOOL success = FALSE; + BOOL success = FALSE; - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); - reset(); - mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - - if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. + + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY ); mPickOptions &= ~F_FILE; } - if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful - { + if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful + { mPickOptions |= F_NAV_SUPPORT; - } - - if (blocking) // always true for linux/mac - { - // Modal, so pause agent - send_agent_pause(); - } - - - success = doNavChooseDialog(filter); - - if (success) - { - if (!getFileCount()) - success = false; - } - - if (blocking) - { - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - } - - return success; + } + + if (blocking) // always true for linux/mac + { + // Modal, so pause agent + send_agent_pause(); + } + + + success = doNavChooseDialog(filter); + + if (success) + { + if (!getFileCount()) + success = false; + } + + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + + return success; } @@ -948,10 +948,10 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { @@ -969,47 +969,47 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - + if( mLocked ) + return FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + BOOL success = FALSE; - reset(); - + reset(); + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; - if (blocking) // always true for linux/mac - { - // Modal, so pause agent - send_agent_pause(); - } - - success = doNavChooseDialog(filter); - - if (blocking) - { - send_agent_resume(); - } - - if (success) - { - if (!getFileCount()) - success = false; - if (getFileCount() > 1) - mLocked = true; - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if (blocking) // always true for linux/mac + { + // Modal, so pause agent + send_agent_pause(); + } + + success = doNavChooseDialog(filter); + + if (blocking) + { + send_agent_resume(); + } + + if (success) + { + if (!getFileCount()) + success = false; + if (getFileCount() > 1) + mLocked = true; + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } @@ -1027,7 +1027,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, } reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1038,42 +1038,42 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { - if( mLocked ) - return false; - BOOL success = false; + if( mLocked ) + return false; + BOOL success = false; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return false; - } + reset(); - reset(); - mPickOptions &= ~F_MULTIPLE; - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } success = doNavSaveDialog(filter, filename); if (success) - { - if (!getFileCount()) - success = false; - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + { + if (!getFileCount()) + success = false; + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -1083,7 +1083,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, { if( mLocked ) return false; - + // if local file browsing is turned off, return without opening dialog if ( check_local_file_access_enabled() == false ) { @@ -1091,7 +1091,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; return doNavSaveDialogModeless(filter, filename, callback, userdata); @@ -1105,414 +1105,414 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, // static void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) { - // We need to run g_filename_to_utf8 in the user's locale - std::string saved_locale(setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, ""); - - LLFilePicker* picker = (LLFilePicker*) user_data; - GError *error = NULL; - gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, - -1, NULL, NULL, &error); - if (error) - { - // *FIXME. - // This condition should really be notified to the user, e.g. - // through a message box. Just logging it is inappropriate. - - // g_filename_display_name is ideal, but >= glib 2.6, so: - // a hand-rolled hacky makeASCII which disallows control chars - std::string display_name; - for (const gchar *str = (const gchar *)data; *str; str++) - { - display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); - } - LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; - } - - if (filename_utf8) - { - picker->mFiles.push_back(std::string(filename_utf8)); - LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; - g_free(filename_utf8); - } - - setlocale(LC_ALL, saved_locale.c_str()); + // We need to run g_filename_to_utf8 in the user's locale + std::string saved_locale(setlocale(LC_ALL, NULL)); + setlocale(LC_ALL, ""); + + LLFilePicker* picker = (LLFilePicker*) user_data; + GError *error = NULL; + gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, + -1, NULL, NULL, &error); + if (error) + { + // *FIXME. + // This condition should really be notified to the user, e.g. + // through a message box. Just logging it is inappropriate. + + // g_filename_display_name is ideal, but >= glib 2.6, so: + // a hand-rolled hacky makeASCII which disallows control chars + std::string display_name; + for (const gchar *str = (const gchar *)data; *str; str++) + { + display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); + } + LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; + } + + if (filename_utf8) + { + picker->mFiles.push_back(std::string(filename_utf8)); + LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; + g_free(filename_utf8); + } + + setlocale(LC_ALL, saved_locale.c_str()); } // static void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) { - LLFilePicker* picker = (LLFilePicker*)user_data; - - LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); - g_slist_foreach(file_list, (GFunc)g_free, NULL); - g_slist_free (file_list); - } - - // let's save the extension of the last added file(considering current filter) - GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); - if(gfilter) - { - std::string filter = gtk_file_filter_get_name(gfilter); - - if(filter == LLTrans::getString("png_image_files")) - { - picker->mCurrentExtension = ".png"; - } - else if(filter == LLTrans::getString("targa_image_files")) - { - picker->mCurrentExtension = ".tga"; - } - } - - // set the default path for this usage context. - const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); - if (cur_folder != NULL) - { - picker->mContextToPathMap[picker->mCurContextName] = cur_folder; - } - - gtk_widget_destroy(widget); - gtk_main_quit(); + LLFilePicker* picker = (LLFilePicker*)user_data; + + LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; + + if (response == GTK_RESPONSE_ACCEPT) + { + GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); + g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); + g_slist_foreach(file_list, (GFunc)g_free, NULL); + g_slist_free (file_list); + } + + // let's save the extension of the last added file(considering current filter) + GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); + if(gfilter) + { + std::string filter = gtk_file_filter_get_name(gfilter); + + if(filter == LLTrans::getString("png_image_files")) + { + picker->mCurrentExtension = ".png"; + } + else if(filter == LLTrans::getString("targa_image_files")) + { + picker->mCurrentExtension = ".tga"; + } + } + + // set the default path for this usage context. + const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); + if (cur_folder != NULL) + { + picker->mContextToPathMap[picker->mCurContextName] = cur_folder; + } + + gtk_widget_destroy(widget); + gtk_main_quit(); } GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) { #ifndef LL_MESA_HEADLESS - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - GtkFileChooserAction pickertype = - is_save? - (is_folder? - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : - GTK_FILE_CHOOSER_ACTION_SAVE) : - (is_folder? - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : - GTK_FILE_CHOOSER_ACTION_OPEN); - - win = gtk_file_chooser_dialog_new(NULL, NULL, - pickertype, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - is_folder ? - GTK_STOCK_APPLY : - (is_save ? - GTK_STOCK_SAVE : - GTK_STOCK_OPEN), - GTK_RESPONSE_ACCEPT, - (gchar *)NULL); - mCurContextName = context; - - // get the default path for this usage context if it's been - // seen before. - std::map<std::string,std::string>::iterator - this_path = mContextToPathMap.find(context); - if (this_path != mContextToPathMap.end()) - { - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(win), - this_path->second.c_str()); - } + if (LLWindowSDL::ll_try_gtk_init()) + { + GtkWidget *win = NULL; + GtkFileChooserAction pickertype = + is_save? + (is_folder? + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : + GTK_FILE_CHOOSER_ACTION_SAVE) : + (is_folder? + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : + GTK_FILE_CHOOSER_ACTION_OPEN); + + win = gtk_file_chooser_dialog_new(NULL, NULL, + pickertype, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + is_folder ? + GTK_STOCK_APPLY : + (is_save ? + GTK_STOCK_SAVE : + GTK_STOCK_OPEN), + GTK_RESPONSE_ACCEPT, + (gchar *)NULL); + mCurContextName = context; + + // get the default path for this usage context if it's been + // seen before. + std::map<std::string,std::string>::iterator + this_path = mContextToPathMap.find(context); + if (this_path != mContextToPathMap.end()) + { + gtk_file_chooser_set_current_folder + (GTK_FILE_CHOOSER(win), + this_path->second.c_str()); + } # if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK raw X11 window, which should try - // to keep it on top etc. - Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); - if (None != XWindowID) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } - else - { - LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; - } + // Make GTK tell the window manager to associate this + // dialog with our non-GTK raw X11 window, which should try + // to keep it on top etc. + Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); + if (None != XWindowID) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, + gdkwin); + } + else + { + LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; + } # endif //LL_X11 - g_signal_connect (GTK_FILE_CHOOSER(win), - "response", - G_CALLBACK(LLFilePicker::chooser_responder), - this); + g_signal_connect (GTK_FILE_CHOOSER(win), + "response", + G_CALLBACK(LLFilePicker::chooser_responder), + this); - gtk_window_set_modal(GTK_WINDOW(win), TRUE); + gtk_window_set_modal(GTK_WINDOW(win), TRUE); - /* GTK 2.6: if (is_folder) - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), - TRUE); */ + /* GTK 2.6: if (is_folder) + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), + TRUE); */ - return GTK_WINDOW(win); - } - else - { - return NULL; - } + return GTK_WINDOW(win); + } + else + { + return NULL; + } #else - return NULL; + return NULL; #endif //LL_MESA_HEADLESS } static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, - GtkWindow *picker, - std::string filtername) -{ - gtk_file_filter_set_name(gfilter, filtername.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter); - GtkFileFilter *allfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(allfilter, "*"); - gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); + GtkWindow *picker, + std::string filtername) +{ + gtk_file_filter_set_name(gfilter, filtername.c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter); + GtkFileFilter *allfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(allfilter, "*"); + gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); } static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, - std::string pattern, - std::string filtername) + std::string pattern, + std::string filtername) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, pattern.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, pattern.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, - std::string mime, - std::string filtername) + std::string mime, + std::string filtername) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_mime_type(gfilter, mime.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_mime_type(gfilter, mime.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", - LLTrans::getString("sound_files") + " (*.wav)"); + return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", + LLTrans::getString("sound_files") + " (*.wav)"); } static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.bvh"); - gtk_file_filter_add_pattern(gfilter, "*.anim"); - std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.bvh"); + gtk_file_filter_add_pattern(gfilter, "*.anim"); + std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", - LLTrans::getString("xml_files") + " (*.xml)"); + return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", + LLTrans::getString("xml_files") + " (*.xml)"); } static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", - LLTrans::getString("scene_files") + " (*.dae)"); + return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", + LLTrans::getString("scene_files") + " (*.dae)"); } static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.tga"); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); + std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } - + static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("script_files") + " (*.lsl)"); + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, + LLTrans::getString("script_files") + " (*.lsl)"); } static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, + LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); } static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter_tga = gtk_file_filter_new(); - GtkFileFilter *gfilter_png = gtk_file_filter_new(); - - gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); - gtk_file_filter_add_mime_type(gfilter_png, "image/png"); - std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; - gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); - gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); - - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_png); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_tga); - return caption; + GtkFileFilter *gfilter_tga = gtk_file_filter_new(); + GtkFileFilter *gfilter_png = gtk_file_filter_new(); + + gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); + gtk_file_filter_add_mime_type(gfilter_png, "image/png"); + std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; + gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); + gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); + + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter_png); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter_tga); + return caption; } BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(true, false, "savefile"); - - if (picker) - { - std::string suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) - { - case FFSAVE_WAV: - caption += add_wav_filter_to_gtkchooser(picker); - suggest_ext = ".wav"; - break; - case FFSAVE_TGA: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); - suggest_ext = ".tga"; - break; - case FFSAVE_BMP: - caption += add_simple_mime_filter_to_gtkchooser - (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); - suggest_ext = ".bmp"; - break; - case FFSAVE_PNG: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); - suggest_ext = ".png"; - break; - case FFSAVE_TGAPNG: - caption += add_save_texture_filter_to_gtkchooser(picker); - suggest_ext = ".png"; - break; - case FFSAVE_AVI: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "video/x-msvideo", - LLTrans::getString("avi_movie_file") + " (*.avi)"); - suggest_ext = ".avi"; - break; - case FFSAVE_ANIM: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); - suggest_ext = ".xaf"; - break; - case FFSAVE_XML: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); - suggest_ext = ".xml"; - break; - case FFSAVE_RAW: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); - suggest_ext = ".raw"; - break; - case FFSAVE_J2C: - // *TODO: Should this be 'image/j2c' ? - caption += add_simple_mime_filter_to_gtkchooser - (picker, "images/jp2", - LLTrans::getString("compressed_image_files") + " (*.j2c)"); - suggest_ext = ".j2c"; - break; - case FFSAVE_SCRIPT: - caption += add_script_filter_to_gtkchooser(picker); - suggest_ext = ".lsl"; - break; - default:; - break; - } - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - if (filename.empty()) - { - suggest_name += suggest_ext; - - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), - suggest_name.c_str()); - } - else - { - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), filename.c_str()); - } - - gtk_widget_show_all(GTK_WIDGET(picker)); - - gtk_main(); - - rtn = (getFileCount() == 1); - - if(rtn && filter == FFSAVE_TGAPNG) - { - std::string selected_file = mFiles.back(); - mFiles.pop_back(); - mFiles.push_back(selected_file + mCurrentExtension); - } - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + gViewerWindow->getWindow()->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(true, false, "savefile"); + + if (picker) + { + std::string suggest_name = "untitled"; + std::string suggest_ext = ""; + std::string caption = LLTrans::getString("save_file_verb") + " "; + switch (filter) + { + case FFSAVE_WAV: + caption += add_wav_filter_to_gtkchooser(picker); + suggest_ext = ".wav"; + break; + case FFSAVE_TGA: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); + suggest_ext = ".tga"; + break; + case FFSAVE_BMP: + caption += add_simple_mime_filter_to_gtkchooser + (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); + suggest_ext = ".bmp"; + break; + case FFSAVE_PNG: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); + suggest_ext = ".png"; + break; + case FFSAVE_TGAPNG: + caption += add_save_texture_filter_to_gtkchooser(picker); + suggest_ext = ".png"; + break; + case FFSAVE_AVI: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "video/x-msvideo", + LLTrans::getString("avi_movie_file") + " (*.avi)"); + suggest_ext = ".avi"; + break; + case FFSAVE_ANIM: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); + suggest_ext = ".xaf"; + break; + case FFSAVE_XML: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); + suggest_ext = ".xml"; + break; + case FFSAVE_RAW: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); + suggest_ext = ".raw"; + break; + case FFSAVE_J2C: + // *TODO: Should this be 'image/j2c' ? + caption += add_simple_mime_filter_to_gtkchooser + (picker, "images/jp2", + LLTrans::getString("compressed_image_files") + " (*.j2c)"); + suggest_ext = ".j2c"; + break; + case FFSAVE_SCRIPT: + caption += add_script_filter_to_gtkchooser(picker); + suggest_ext = ".lsl"; + break; + default:; + break; + } + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + if (filename.empty()) + { + suggest_name += suggest_ext; + + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), + suggest_name.c_str()); + } + else + { + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), filename.c_str()); + } + + gtk_widget_show_all(GTK_WIDGET(picker)); + + gtk_main(); + + rtn = (getFileCount() == 1); + + if(rtn && filter == FFSAVE_TGAPNG) + { + std::string selected_file = mFiles.back(); + mFiles.pop_back(); + mFiles.push_back(selected_file + mCurrentExtension); + } + } + + gViewerWindow->getWindow()->afterDialog(); + + return rtn; } BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - std::string caption = LLTrans::getString("load_file_verb") + " "; - std::string filtername = ""; - switch (filter) - { - case FFLOAD_WAV: - filtername = add_wav_filter_to_gtkchooser(picker); - break; - case FFLOAD_ANIM: - filtername = add_anim_filter_to_gtkchooser(picker); - break; - case FFLOAD_XML: - filtername = add_xml_filter_to_gtkchooser(picker); - break; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + gViewerWindow->getWindow()->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(false, false, "openfile"); + + if (picker) + { + std::string caption = LLTrans::getString("load_file_verb") + " "; + std::string filtername = ""; + switch (filter) + { + case FFLOAD_WAV: + filtername = add_wav_filter_to_gtkchooser(picker); + break; + case FFLOAD_ANIM: + filtername = add_anim_filter_to_gtkchooser(picker); + break; + case FFLOAD_XML: + filtername = add_xml_filter_to_gtkchooser(picker); + break; case FFLOAD_GLTF: filtername = dead_code_should_blow_up_here(picker); break; @@ -1520,64 +1520,64 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) filtername = add_collada_filter_to_gtkchooser(picker); break; case FFLOAD_IMAGE: - filtername = add_imageload_filter_to_gtkchooser(picker); - break; - case FFLOAD_SCRIPT: - filtername = add_script_filter_to_gtkchooser(picker); - break; - case FFLOAD_DICTIONARY: - filtername = add_dictionary_filter_to_gtkchooser(picker); - break; - default:; - break; - } - - caption += filtername; - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + filtername = add_imageload_filter_to_gtkchooser(picker); + break; + case FFLOAD_SCRIPT: + filtername = add_script_filter_to_gtkchooser(picker); + break; + case FFLOAD_DICTIONARY: + filtername = add_dictionary_filter_to_gtkchooser(picker); + break; + default:; + break; + } + + caption += filtername; + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + + rtn = (getFileCount() == 1); + } + + gViewerWindow->getWindow()->afterDialog(); + + return rtn; } BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - BOOL rtn = FALSE; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + gViewerWindow->getWindow()->beforeDialog(); - gViewerWindow->getWindow()->beforeDialog(); + reset(); - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); + GtkWindow* picker = buildFilePicker(false, false, "openfile"); - if (picker) - { - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), - TRUE); + if (picker) + { + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), + TRUE); - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); + gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - rtn = !mFiles.empty(); - } + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + rtn = !mFiles.empty(); + } - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); - return rtn; + return rtn; } # else // LL_GTK @@ -1587,23 +1587,23 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - - LL_INFOS() << "getSaveFile suggested filename is [" << filename - << "]" << LL_ENDL; - if (!filename.empty()) - { - mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); - return TRUE; - } - return FALSE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + + LL_INFOS() << "getSaveFile suggested filename is [" << filename + << "]" << LL_ENDL; + if (!filename.empty()) + { + mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); + return TRUE; + } + return FALSE; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -1617,27 +1617,27 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - - // HACK: Static filenames for 'open' until we implement filepicker - std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; - switch (filter) - { - case FFLOAD_WAV: filename += ".wav"; break; - case FFLOAD_IMAGE: filename += ".tga"; break; - case FFLOAD_ANIM: filename += ".bvh"; break; - default: break; - } - mFiles.push_back(filename); - LL_INFOS() << "getOpenFile: Will try to open file: " << filename << LL_ENDL; - return TRUE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + + // HACK: Static filenames for 'open' until we implement filepicker + std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; + switch (filter) + { + case FFLOAD_WAV: filename += ".wav"; break; + case FFLOAD_IMAGE: filename += ".tga"; break; + case FFLOAD_ANIM: filename += ".bvh"; break; + default: break; + } + mFiles.push_back(filename); + LL_INFOS() << "getOpenFile: Will try to open file: " << filename << LL_ENDL; + return TRUE; } BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, @@ -1650,15 +1650,15 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - return FALSE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + return FALSE; } BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, @@ -1675,20 +1675,20 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) { - reset(); - return FALSE; + reset(); + return FALSE; } BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) { - reset(); - return FALSE; + reset(); + return FALSE; } BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - reset(); - return FALSE; + reset(); + return FALSE; } #endif // LL_LINUX diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index f00f076d1c..c4380dcd19 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.h * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,119 +64,119 @@ extern "C" { class LLFilePicker { #ifdef LL_GTK - friend class LLDirPicker; - friend void chooser_responder(GtkWidget *, gint, gpointer); + friend class LLDirPicker; + friend void chooser_responder(GtkWidget *, gint, gpointer); #endif // LL_GTK public: - // calling this before main() is undefined - static LLFilePicker& instance( void ) { return sInstance; } - - enum ELoadFilter - { - FFLOAD_ALL = 1, - FFLOAD_WAV = 2, - FFLOAD_IMAGE = 3, - FFLOAD_ANIM = 4, - FFLOAD_GLTF = 5, - FFLOAD_XML = 6, - FFLOAD_SLOBJECT = 7, - FFLOAD_RAW = 8, - FFLOAD_MODEL = 9, - FFLOAD_COLLADA = 10, - FFLOAD_SCRIPT = 11, - FFLOAD_DICTIONARY = 12, + // calling this before main() is undefined + static LLFilePicker& instance( void ) { return sInstance; } + + enum ELoadFilter + { + FFLOAD_ALL = 1, + FFLOAD_WAV = 2, + FFLOAD_IMAGE = 3, + FFLOAD_ANIM = 4, + FFLOAD_GLTF = 5, + FFLOAD_XML = 6, + FFLOAD_SLOBJECT = 7, + FFLOAD_RAW = 8, + FFLOAD_MODEL = 9, + FFLOAD_COLLADA = 10, + FFLOAD_SCRIPT = 11, + FFLOAD_DICTIONARY = 12, FFLOAD_DIRECTORY = 13, // To call from lldirpicker. FFLOAD_EXE = 14, // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin FFLOAD_MATERIAL = 15, FFLOAD_MATERIAL_TEXTURE = 16, FFLOAD_LUA = 17, - }; - - enum ESaveFilter - { - FFSAVE_ALL = 1, - FFSAVE_WAV = 3, - FFSAVE_TGA = 4, - FFSAVE_BMP = 5, - FFSAVE_AVI = 6, - FFSAVE_ANIM = 7, - FFSAVE_GLTF = 8, - FFSAVE_XML = 9, - FFSAVE_COLLADA = 10, - FFSAVE_RAW = 11, - FFSAVE_J2C = 12, - FFSAVE_PNG = 13, - FFSAVE_JPEG = 14, - FFSAVE_SCRIPT = 15, - FFSAVE_TGAPNG = 16 - }; - - // open the dialog. This is a modal operation - BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); + }; + + enum ESaveFilter + { + FFSAVE_ALL = 1, + FFSAVE_WAV = 3, + FFSAVE_TGA = 4, + FFSAVE_BMP = 5, + FFSAVE_AVI = 6, + FFSAVE_ANIM = 7, + FFSAVE_GLTF = 8, + FFSAVE_XML = 9, + FFSAVE_COLLADA = 10, + FFSAVE_RAW = 11, + FFSAVE_J2C = 12, + FFSAVE_PNG = 13, + FFSAVE_JPEG = 14, + FFSAVE_SCRIPT = 15, + FFSAVE_TGAPNG = 16 + }; + + // open the dialog. This is a modal operation + BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); BOOL getSaveFileModeless(ESaveFilter filter, const std::string& filename, void (*callback)(bool, std::string&, void*), void *userdata); - BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); // Todo: implement getOpenFileModeless and getMultipleOpenFilesModeless // for windows and use directly instead of ugly LLFilePickerThread BOOL getOpenFileModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata); // MAC only. - BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); BOOL getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata ); // MAC only - // Get the filename(s) found. getFirstFile() sets the pointer to - // the start of the structure and allows the start of iteration. - const std::string getFirstFile(); + // Get the filename(s) found. getFirstFile() sets the pointer to + // the start of the structure and allows the start of iteration. + const std::string getFirstFile(); + + // getNextFile() increments the internal representation and + // returns the next file specified by the user. Returns NULL when + // no more files are left. Further calls to getNextFile() are + // undefined. + const std::string getNextFile(); - // getNextFile() increments the internal representation and - // returns the next file specified by the user. Returns NULL when - // no more files are left. Further calls to getNextFile() are - // undefined. - const std::string getNextFile(); + // This utility function extracts the current file name without + // doing any incrementing. + const std::string getCurFile(); - // This utility function extracts the current file name without - // doing any incrementing. - const std::string getCurFile(); + // Returns the index of the current file. + S32 getCurFileNum() const { return mCurrentFile; } - // Returns the index of the current file. - S32 getCurFileNum() const { return mCurrentFile; } + S32 getFileCount() const { return (S32)mFiles.size(); } - S32 getFileCount() const { return (S32)mFiles.size(); } + // see lldir.h : getBaseFileName and getDirName to extract base or directory names - // see lldir.h : getBaseFileName and getDirName to extract base or directory names - - // clear any lists of buffers or whatever, and make sure the file - // picker isn't locked. - void reset(); + // clear any lists of buffers or whatever, and make sure the file + // picker isn't locked. + void reset(); private: - enum - { - SINGLE_FILENAME_BUFFER_SIZE = 1024, - //FILENAME_BUFFER_SIZE = 65536 - FILENAME_BUFFER_SIZE = 65000 - }; - - // utility function to check if access to local file system via file browser - // is enabled and if not, tidy up and indicate we're not allowed to do this. - bool check_local_file_access_enabled(); - + enum + { + SINGLE_FILENAME_BUFFER_SIZE = 1024, + //FILENAME_BUFFER_SIZE = 65536 + FILENAME_BUFFER_SIZE = 65000 + }; + + // utility function to check if access to local file system via file browser + // is enabled and if not, tidy up and indicate we're not allowed to do this. + bool check_local_file_access_enabled(); + #if LL_WINDOWS - OPENFILENAMEW mOFN; // for open and save dialogs - WCHAR mFilesW[FILENAME_BUFFER_SIZE]; + OPENFILENAMEW mOFN; // for open and save dialogs + WCHAR mFilesW[FILENAME_BUFFER_SIZE]; - BOOL setupFilter(ELoadFilter filter); + BOOL setupFilter(ELoadFilter filter); #endif #if LL_DARWIN S32 mPickOptions; - std::vector<std::string> mFileVector; - - bool doNavChooseDialog(ELoadFilter filter); - bool doNavChooseDialogModeless(ELoadFilter filter, + std::vector<std::string> mFileVector; + + bool doNavChooseDialog(ELoadFilter filter); + bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector<std::string>&, void*), void *userdata); - bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); + bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); std::unique_ptr<std::vector<std::string>> navOpenFilterProc(ELoadFilter filter); bool doNavSaveDialogModeless(ESaveFilter filter, const std::string& filename, @@ -185,31 +185,31 @@ private: #endif #if LL_GTK - static void add_to_selectedfiles(gpointer data, gpointer user_data); - static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); - // we remember the last path that was accessed for a particular usage - std::map <std::string, std::string> mContextToPathMap; - std::string mCurContextName; - // we also remember the extension of the last added file. - std::string mCurrentExtension; + static void add_to_selectedfiles(gpointer data, gpointer user_data); + static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); + // we remember the last path that was accessed for a particular usage + std::map <std::string, std::string> mContextToPathMap; + std::string mCurContextName; + // we also remember the extension of the last added file. + std::string mCurrentExtension; #endif - std::vector<std::string> mFiles; - S32 mCurrentFile; - bool mLocked; + std::vector<std::string> mFiles; + S32 mCurrentFile; + bool mLocked; + + static LLFilePicker sInstance; - static LLFilePicker sInstance; - protected: #if LL_GTK GtkWindow* buildFilePicker(bool is_save, bool is_folder, - std::string context = "generic"); + std::string context = "generic"); #endif public: - // don't call these directly please. - LLFilePicker(); - ~LLFilePicker(); + // don't call these directly please. + LLFilePicker(); + ~LLFilePicker(); }; #endif diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 0bc3c241fa..956ab0d7bc 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2017&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2017, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,14 +38,14 @@ #include "llviewercontrol.h" LLFloaterLinkReplace::LLFloaterLinkReplace(const LLSD& key) - : LLFloater(key), - LLEventTimer(gSavedSettings.getF32("LinkReplaceBatchPauseTime")), - mRemainingItems(0), - mSourceUUID(LLUUID::null), - mTargetUUID(LLUUID::null), - mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize")) + : LLFloater(key), + LLEventTimer(gSavedSettings.getF32("LinkReplaceBatchPauseTime")), + mRemainingItems(0), + mSourceUUID(LLUUID::null), + mTargetUUID(LLUUID::null), + mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize")) { - stop(); + stop(); } LLFloaterLinkReplace::~LLFloaterLinkReplace() @@ -54,322 +54,322 @@ LLFloaterLinkReplace::~LLFloaterLinkReplace() BOOL LLFloaterLinkReplace::postBuild() { - mStartBtn = getChild<LLButton>("btn_start"); - mStartBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::onStartClicked, this)); + mStartBtn = getChild<LLButton>("btn_start"); + mStartBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::onStartClicked, this)); - mRefreshBtn = getChild<LLButton>("btn_refresh"); - mRefreshBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::checkEnableStart, this)); + mRefreshBtn = getChild<LLButton>("btn_refresh"); + mRefreshBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::checkEnableStart, this)); - mSourceEditor = getChild<LLInventoryLinkReplaceDropTarget>("source_uuid_editor"); - mTargetEditor = getChild<LLInventoryLinkReplaceDropTarget>("target_uuid_editor"); + mSourceEditor = getChild<LLInventoryLinkReplaceDropTarget>("source_uuid_editor"); + mTargetEditor = getChild<LLInventoryLinkReplaceDropTarget>("target_uuid_editor"); - mSourceEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onSourceItemDrop, this, _1)); - mTargetEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onTargetItemDrop, this, _1)); + mSourceEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onSourceItemDrop, this, _1)); + mTargetEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onTargetItemDrop, this, _1)); - mStatusText = getChild<LLTextBox>("status_text"); + mStatusText = getChild<LLTextBox>("status_text"); - return TRUE; + return TRUE; } void LLFloaterLinkReplace::onOpen(const LLSD& key) { - if (key.asUUID().notNull()) - { - LLUUID item_id = key.asUUID(); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - mSourceEditor->setItem(item); - onSourceItemDrop(item->getLinkedUUID()); - } - else - { - checkEnableStart(); - } + if (key.asUUID().notNull()) + { + LLUUID item_id = key.asUUID(); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + mSourceEditor->setItem(item); + onSourceItemDrop(item->getLinkedUUID()); + } + else + { + checkEnableStart(); + } } void LLFloaterLinkReplace::onSourceItemDrop(const LLUUID& source_item_id) { - mSourceUUID = source_item_id; - checkEnableStart(); + mSourceUUID = source_item_id; + checkEnableStart(); } void LLFloaterLinkReplace::onTargetItemDrop(const LLUUID& target_item_id) { - mTargetUUID = target_item_id; - checkEnableStart(); + mTargetUUID = target_item_id; + checkEnableStart(); } void LLFloaterLinkReplace::updateFoundLinks() { - LLInventoryModel::item_array_t items; - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - items, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - mRemainingItems = (U32)items.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsFound", args)); + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + items, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + mRemainingItems = (U32)items.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsFound", args)); } void LLFloaterLinkReplace::checkEnableStart() { - if (mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID == mTargetUUID) - { - mStatusText->setText(getString("ItemsIdentical")); - } - else if (mSourceUUID.notNull()) - { - updateFoundLinks(); - } - - mStartBtn->setEnabled(mRemainingItems > 0 && mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID != mTargetUUID); + if (mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID == mTargetUUID) + { + mStatusText->setText(getString("ItemsIdentical")); + } + else if (mSourceUUID.notNull()) + { + updateFoundLinks(); + } + + mStartBtn->setEnabled(mRemainingItems > 0 && mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID != mTargetUUID); } void LLFloaterLinkReplace::onStartClicked() { - LL_INFOS() << "Starting inventory link replace" << LL_ENDL; - - if (mSourceUUID.isNull() || mTargetUUID.isNull()) - { - LL_WARNS() << "Cannot replace. Either source or target UUID is null." << LL_ENDL; - return; - } - - if (mSourceUUID == mTargetUUID) - { - LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; - return; - } - - const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); - LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); - const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); - LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); - - - LLNotification::Params params("ConfirmReplaceLink"); - params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); - if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) - { - if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) - { - LLNotifications::instance().forceResponse(params, 0); - } - else - { - LLSD args; - args["TYPE"] = LLWearableType::getInstance()->getTypeName(source_item->getWearableType()); - params.substitutions(args); - LLNotifications::instance().add(params); - } - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } + LL_INFOS() << "Starting inventory link replace" << LL_ENDL; + + if (mSourceUUID.isNull() || mTargetUUID.isNull()) + { + LL_WARNS() << "Cannot replace. Either source or target UUID is null." << LL_ENDL; + return; + } + + if (mSourceUUID == mTargetUUID) + { + LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; + return; + } + + const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); + LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); + const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); + LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); + + + LLNotification::Params params("ConfirmReplaceLink"); + params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); + if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) + { + if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) + { + LLNotifications::instance().forceResponse(params, 0); + } + else + { + LLSD args; + args["TYPE"] = LLWearableType::getInstance()->getTypeName(source_item->getWearableType()); + params.substitutions(args); + LLNotifications::instance().add(params); + } + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } } void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, const LLSD& response) { - if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) - { - - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - mRemainingInventoryItems, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; - - if (mRemainingInventoryItems.size() > 0) - { - LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - if (target_item) - { - mRemainingItems = (U32)mRemainingInventoryItems.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - - mStartBtn->setEnabled(FALSE); - mRefreshBtn->setEnabled(FALSE); - - start(); - tick(); - } - else - { - mStatusText->setText(getString("TargetNotFound")); - LL_WARNS() << "Link replace target not found." << LL_ENDL; - } - } - } + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + mRemainingInventoryItems, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; + + if (mRemainingInventoryItems.size() > 0) + { + LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + if (target_item) + { + mRemainingItems = (U32)mRemainingInventoryItems.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + + mStartBtn->setEnabled(FALSE); + mRefreshBtn->setEnabled(FALSE); + + start(); + tick(); + } + else + { + mStatusText->setText(getString("TargetNotFound")); + LL_WARNS() << "Link replace target not found." << LL_ENDL; + } + } + } } // static void LLFloaterLinkReplace::linkCreatedCallback(LLHandle<LLFloaterLinkReplace> floater_handle, const LLUUID& old_item_id, const LLUUID& target_item_id, - bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id) + bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id) { - LL_DEBUGS() << "Inventory link replace:" << LL_NEWLINE - << " - old_item_id = " << old_item_id.asString() << LL_NEWLINE - << " - target_item_id = " << target_item_id.asString() << LL_NEWLINE - << " - order update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE - << " - description update = " << (needs_description_update ? "true" : "false") << LL_NEWLINE - << " - outfit_folder_id = " << outfit_folder_id.asString() << LL_ENDL; - - // If we are replacing an object, bodypart or gesture link within an outfit folder, - // we need to change the actual description of the link itself. LLAppearanceMgr *should* - // have created COF links that will be used to save the outfit with an empty description. - // Since link_inventory_array() will set the description of the linked item for the link - // itself, this will lead to a dirty outfit state when the outfit with the replaced - // link is worn. So we have to correct this. - if (needs_description_update && outfit_folder_id.notNull()) - { - LLInventoryModel::item_array_t items; - LLInventoryModel::cat_array_t cats; - LLLinkedItemIDMatches is_target_link(target_item_id); - gInventory.collectDescendentsIf(outfit_folder_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_target_link); - - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - LLPointer<LLViewerInventoryItem> item = *it; - - if ((item->getType() == LLAssetType::AT_BODYPART || - item->getType() == LLAssetType::AT_OBJECT || - item->getType() == LLAssetType::AT_GESTURE) - && !item->getActualDescription().empty()) - { - LL_DEBUGS() << "Updating description for " << item->getName() << LL_ENDL; - - LLSD updates; - updates["desc"] = ""; - update_inventory_item(item->getUUID(), updates, LLPointer<LLInventoryCallback>(NULL)); - } - } - } - - LLUUID outfit_update_folder = LLUUID::null; - if (needs_wearable_ordering_update && outfit_folder_id.notNull()) - { - // If a wearable item was involved in the link replace operation and replaced - // a link in an outfit folder, we need to update the clothing ordering information - // *after* the original link has been removed. LLAppearanceMgr abuses the actual link - // description to store the clothing ordering information it. We will have to update - // the clothing ordering information or the outfit will be in dirty state when worn. - outfit_update_folder = outfit_folder_id; - } - - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::itemRemovedCallback, floater_handle, outfit_update_folder)); - remove_inventory_object(old_item_id, cb); + LL_DEBUGS() << "Inventory link replace:" << LL_NEWLINE + << " - old_item_id = " << old_item_id.asString() << LL_NEWLINE + << " - target_item_id = " << target_item_id.asString() << LL_NEWLINE + << " - order update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE + << " - description update = " << (needs_description_update ? "true" : "false") << LL_NEWLINE + << " - outfit_folder_id = " << outfit_folder_id.asString() << LL_ENDL; + + // If we are replacing an object, bodypart or gesture link within an outfit folder, + // we need to change the actual description of the link itself. LLAppearanceMgr *should* + // have created COF links that will be used to save the outfit with an empty description. + // Since link_inventory_array() will set the description of the linked item for the link + // itself, this will lead to a dirty outfit state when the outfit with the replaced + // link is worn. So we have to correct this. + if (needs_description_update && outfit_folder_id.notNull()) + { + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + LLLinkedItemIDMatches is_target_link(target_item_id); + gInventory.collectDescendentsIf(outfit_folder_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_target_link); + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + LLPointer<LLViewerInventoryItem> item = *it; + + if ((item->getType() == LLAssetType::AT_BODYPART || + item->getType() == LLAssetType::AT_OBJECT || + item->getType() == LLAssetType::AT_GESTURE) + && !item->getActualDescription().empty()) + { + LL_DEBUGS() << "Updating description for " << item->getName() << LL_ENDL; + + LLSD updates; + updates["desc"] = ""; + update_inventory_item(item->getUUID(), updates, LLPointer<LLInventoryCallback>(NULL)); + } + } + } + + LLUUID outfit_update_folder = LLUUID::null; + if (needs_wearable_ordering_update && outfit_folder_id.notNull()) + { + // If a wearable item was involved in the link replace operation and replaced + // a link in an outfit folder, we need to update the clothing ordering information + // *after* the original link has been removed. LLAppearanceMgr abuses the actual link + // description to store the clothing ordering information it. We will have to update + // the clothing ordering information or the outfit will be in dirty state when worn. + outfit_update_folder = outfit_folder_id; + } + + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::itemRemovedCallback, floater_handle, outfit_update_folder)); + remove_inventory_object(old_item_id, cb); } // static void LLFloaterLinkReplace::itemRemovedCallback(LLHandle<LLFloaterLinkReplace> floater_handle, const LLUUID& outfit_folder_id) { - if (outfit_folder_id.notNull()) - { - LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(outfit_folder_id); - } - - if (!floater_handle.isDead()) - { - floater_handle.get()->decreaseOpenItemCount(); - } + if (outfit_folder_id.notNull()) + { + LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(outfit_folder_id); + } + + if (!floater_handle.isDead()) + { + floater_handle.get()->decreaseOpenItemCount(); + } } void LLFloaterLinkReplace::decreaseOpenItemCount() { - mRemainingItems--; - - if (mRemainingItems == 0) - { - mStatusText->setText(getString("ReplaceFinished")); - mStartBtn->setEnabled(TRUE); - mRefreshBtn->setEnabled(TRUE); - stop(); - LL_INFOS() << "Inventory link replace finished." << LL_ENDL; - } - else - { - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - LL_DEBUGS() << "Inventory link replace: " << mRemainingItems << " links remaining..." << LL_ENDL; - } + mRemainingItems--; + + if (mRemainingItems == 0) + { + mStatusText->setText(getString("ReplaceFinished")); + mStartBtn->setEnabled(TRUE); + mRefreshBtn->setEnabled(TRUE); + stop(); + LL_INFOS() << "Inventory link replace finished." << LL_ENDL; + } + else + { + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + LL_DEBUGS() << "Inventory link replace: " << mRemainingItems << " links remaining..." << LL_ENDL; + } } bool LLFloaterLinkReplace::tick() { - LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; + LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; - LLInventoryModel::item_array_t current_batch; + LLInventoryModel::item_array_t current_batch; - for (U32 i = 0; i < mBatchSize; ++i) - { - if (!mRemainingInventoryItems.size()) - { - stop(); - break; - } + for (U32 i = 0; i < mBatchSize; ++i) + { + if (!mRemainingInventoryItems.size()) + { + stop(); + break; + } - current_batch.push_back(mRemainingInventoryItems.back()); - mRemainingInventoryItems.pop_back(); - } - processBatch(current_batch); + current_batch.push_back(mRemainingInventoryItems.back()); + mRemainingInventoryItems.pop_back(); + } + processBatch(current_batch); - return FALSE; + return FALSE; } void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) { - const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - LLPointer<LLInventoryItem> source_item = *it; - - if (source_item->getParentUUID() != cof_folder_id) - { - bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); - // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced - bool needs_wearable_ordering_update = (is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING) || target_item->getType() == LLAssetType::AT_CLOTHING; - // Other items in the COF need a description update (description of the actual link item must be empty) - bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; - - LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE - << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE - << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; - - LLInventoryObject::const_object_list_t obj_array; - obj_array.push_back(LLConstPointer<LLInventoryObject>(target_item)); - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::linkCreatedCallback, - getDerivedHandle<LLFloaterLinkReplace>(), - source_item->getUUID(), - target_item->getUUID(), - needs_wearable_ordering_update, - needs_description_update, - (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) )); - link_inventory_array(source_item->getParentUUID(), obj_array, cb); - } - else - { - decreaseOpenItemCount(); - } - } + const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + LLPointer<LLInventoryItem> source_item = *it; + + if (source_item->getParentUUID() != cof_folder_id) + { + bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); + // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced + bool needs_wearable_ordering_update = (is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING) || target_item->getType() == LLAssetType::AT_CLOTHING; + // Other items in the COF need a description update (description of the actual link item must be empty) + bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; + + LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE + << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE + << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; + + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(LLConstPointer<LLInventoryObject>(target_item)); + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::linkCreatedCallback, + getDerivedHandle<LLFloaterLinkReplace>(), + source_item->getUUID(), + target_item->getUUID(), + needs_wearable_ordering_update, + needs_description_update, + (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) )); + link_inventory_array(source_item->getParentUUID(), obj_array, cb); + } + else + { + decreaseOpenItemCount(); + } + } } @@ -379,51 +379,51 @@ void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) static LLDefaultChildRegistry::Register<LLInventoryLinkReplaceDropTarget> r("inventory_link_replace_drop_target"); BOOL LLInventoryLinkReplaceDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - LLInventoryItem* item = (LLInventoryItem*)cargo_data; - - if (cargo_type >= DAD_TEXTURE && cargo_type <= DAD_LINK && - item && item->getActualType() != LLAssetType::AT_LINK_FOLDER && item->getType() != LLAssetType::AT_CATEGORY && - ( - LLAssetType::lookupCanLink(item->getType()) || - (item->getType() == LLAssetType::AT_LINK && !gInventory.getObject(item->getLinkedUUID())) // Broken Link! - )) - { - if (drop) - { - setItem(item); - if (!mDADSignal.empty()) - { - mDADSignal(mItemID); - } - } - else - { - *accept = ACCEPT_YES_SINGLE; - } - } - else - { - *accept = ACCEPT_NO; - } - - return TRUE; + LLInventoryItem* item = (LLInventoryItem*)cargo_data; + + if (cargo_type >= DAD_TEXTURE && cargo_type <= DAD_LINK && + item && item->getActualType() != LLAssetType::AT_LINK_FOLDER && item->getType() != LLAssetType::AT_CATEGORY && + ( + LLAssetType::lookupCanLink(item->getType()) || + (item->getType() == LLAssetType::AT_LINK && !gInventory.getObject(item->getLinkedUUID())) // Broken Link! + )) + { + if (drop) + { + setItem(item); + if (!mDADSignal.empty()) + { + mDADSignal(mItemID); + } + } + else + { + *accept = ACCEPT_YES_SINGLE; + } + } + else + { + *accept = ACCEPT_NO; + } + + return TRUE; } void LLInventoryLinkReplaceDropTarget::setItem(LLInventoryItem* item) { - if (item) - { - mItemID = item->getLinkedUUID(); - setText(item->getName()); - } - else - { - mItemID.setNull(); - setText(LLStringExplicit("")); - } + if (item) + { + mItemID = item->getLinkedUUID(); + setText(item->getName()); + } + else + { + mItemID.setNull(); + setText(LLStringExplicit("")); + } } diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index a11e025a71..e2fff20735 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2017&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2017, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,84 +40,84 @@ class LLTextBox; class LLInventoryLinkReplaceDropTarget : public LLLineEditor { public: - struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> - { - Params() - {} - }; - - LLInventoryLinkReplaceDropTarget(const Params& p) - : LLLineEditor(p) {} - ~LLInventoryLinkReplaceDropTarget() {} - - typedef boost::signals2::signal<void(const LLUUID& id)> item_dad_callback_t; - boost::signals2::connection setDADCallback(const item_dad_callback_t::slot_type& cb) - { - return mDADSignal.connect(cb); - } - - virtual BOOL postBuild() - { - setEnabled(FALSE); - return LLLineEditor::postBuild(); - } - - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - LLUUID getItemID() const { return mItemID; } - void setItem(LLInventoryItem* item); + struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> + { + Params() + {} + }; + + LLInventoryLinkReplaceDropTarget(const Params& p) + : LLLineEditor(p) {} + ~LLInventoryLinkReplaceDropTarget() {} + + typedef boost::signals2::signal<void(const LLUUID& id)> item_dad_callback_t; + boost::signals2::connection setDADCallback(const item_dad_callback_t::slot_type& cb) + { + return mDADSignal.connect(cb); + } + + virtual BOOL postBuild() + { + setEnabled(FALSE); + return LLLineEditor::postBuild(); + } + + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + LLUUID getItemID() const { return mItemID; } + void setItem(LLInventoryItem* item); private: - LLUUID mItemID; + LLUUID mItemID; - item_dad_callback_t mDADSignal; + item_dad_callback_t mDADSignal; }; class LLFloaterLinkReplace : public LLFloater, LLEventTimer { - LOG_CLASS(LLFloaterLinkReplace); + LOG_CLASS(LLFloaterLinkReplace); public: - LLFloaterLinkReplace(const LLSD& key); - virtual ~LLFloaterLinkReplace(); + LLFloaterLinkReplace(const LLSD& key); + virtual ~LLFloaterLinkReplace(); - BOOL postBuild() override; - void onOpen(const LLSD& key) override; + BOOL postBuild() override; + void onOpen(const LLSD& key) override; - bool tick() override; + bool tick() override; private: - void checkEnableStart(); - void onStartClicked(); - void onStartClickedResponse(const LLSD& notification, const LLSD& response); - void decreaseOpenItemCount(); - void updateFoundLinks(); - void processBatch(LLInventoryModel::item_array_t items); - - static void linkCreatedCallback(LLHandle<LLFloaterLinkReplace> floater_handle, const LLUUID& old_item_id, const LLUUID& target_item_id, - bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id); - static void itemRemovedCallback(LLHandle<LLFloaterLinkReplace> floater_handle, const LLUUID& outfit_folder_id); - - void onSourceItemDrop(const LLUUID& source_item_id); - void onTargetItemDrop(const LLUUID& target_item_id); - - LLInventoryLinkReplaceDropTarget* mSourceEditor; - LLInventoryLinkReplaceDropTarget* mTargetEditor; - LLButton* mStartBtn; - LLButton* mRefreshBtn; - LLTextBox* mStatusText; - - LLUUID mSourceUUID; - LLUUID mTargetUUID; - U32 mRemainingItems; - U32 mBatchSize; - - LLInventoryModel::item_array_t mRemainingInventoryItems; + void checkEnableStart(); + void onStartClicked(); + void onStartClickedResponse(const LLSD& notification, const LLSD& response); + void decreaseOpenItemCount(); + void updateFoundLinks(); + void processBatch(LLInventoryModel::item_array_t items); + + static void linkCreatedCallback(LLHandle<LLFloaterLinkReplace> floater_handle, const LLUUID& old_item_id, const LLUUID& target_item_id, + bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id); + static void itemRemovedCallback(LLHandle<LLFloaterLinkReplace> floater_handle, const LLUUID& outfit_folder_id); + + void onSourceItemDrop(const LLUUID& source_item_id); + void onTargetItemDrop(const LLUUID& target_item_id); + + LLInventoryLinkReplaceDropTarget* mSourceEditor; + LLInventoryLinkReplaceDropTarget* mTargetEditor; + LLButton* mStartBtn; + LLButton* mRefreshBtn; + LLTextBox* mStatusText; + + LLUUID mSourceUUID; + LLUUID mTargetUUID; + U32 mRemainingItems; + U32 mBatchSize; + + LLInventoryModel::item_array_t mRemainingInventoryItems; }; #endif // LL_FLOATERLINKREPLACE_H diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 6fd11dd1c7..60571d6247 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llfloaterluadebug.cpp * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -72,7 +72,7 @@ BOOL LLFloaterLUADebug::postBuild() return TRUE; } -LLFloaterLUADebug::~LLFloaterLUADebug() +LLFloaterLUADebug::~LLFloaterLUADebug() {} void LLFloaterLUADebug::onExecuteClicked() @@ -80,7 +80,7 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); - cleanLuaState(); + cleanLuaState(); LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) { completion(count, result); @@ -94,17 +94,17 @@ void LLFloaterLUADebug::onBtnBrowse() void LLFloaterLUADebug::onBtnRun() { - std::vector<std::string> filenames; - std::string filepath = mScriptPath->getText(); - if (!filepath.empty()) - { - filenames.push_back(filepath); - runSelectedScript(filenames); - } + std::vector<std::string> filenames; + std::string filepath = mScriptPath->getText(); + if (!filepath.empty()) + { + filenames.push_back(filepath); + runSelectedScript(filenames); + } } void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames) -{ +{ mResultOutput->setValue(""); std::string filepath = filenames[0]; @@ -145,9 +145,9 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) } } -void LLFloaterLUADebug::cleanLuaState() -{ - if(getChild<LLCheckBoxCtrl>("clean_lua_state")->get()) +void LLFloaterLUADebug::cleanLuaState() +{ + if(getChild<LLCheckBoxCtrl>("clean_lua_state")->get()) { //Reinit to clean lua_State mState.initLuaState(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index d9f7f0a171..7e3f35e0fc 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterpreference.cpp * @brief Global preferences with and without persistence. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -159,14 +159,14 @@ struct LabelTable : public LLInitParam::Block<LabelTable> }; -// global functions +// global functions // helper functions for getting/freeing the web browser media // if creating/destroying these is too slow, we'll need to create // a static member and update all our static callbacks -void handleNameTagOptionChanged(const LLSD& newvalue); -void handleDisplayNamesOptionChanged(const LLSD& newvalue); +void handleNameTagOptionChanged(const LLSD& newvalue); +void handleDisplayNamesOptionChanged(const LLSD& newvalue); bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response); bool callback_clear_cache(const LLSD& notification, const LLSD& response); @@ -177,79 +177,79 @@ void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); bool callback_clear_cache(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - // flag client texture cache for clearing next time the client runs - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); - LLNotificationsUtil::add("CacheWillClear"); - } + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + // flag client texture cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotificationsUtil::add("CacheWillClear"); + } - return false; + return false; } bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - // clean web - LLViewerMedia::getInstance()->clearAllCaches(); - LLViewerMedia::getInstance()->clearAllCookies(); - - // clean nav bar history - LLNavigationBar::getInstance()->clearHistoryCache(); - - // flag client texture cache for clearing next time the client runs - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); - LLNotificationsUtil::add("CacheWillClear"); - - LLSearchHistory::getInstance()->clearHistory(); - LLSearchHistory::getInstance()->save(); - LLSearchComboBox* search_ctrl = LLNavigationBar::getInstance()->getChild<LLSearchComboBox>("search_combo_box"); - search_ctrl->clearHistory(); - - LLTeleportHistoryStorage::getInstance()->purgeItems(); - LLTeleportHistoryStorage::getInstance()->save(); - } - - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + // clean web + LLViewerMedia::getInstance()->clearAllCaches(); + LLViewerMedia::getInstance()->clearAllCookies(); + + // clean nav bar history + LLNavigationBar::getInstance()->clearHistoryCache(); + + // flag client texture cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotificationsUtil::add("CacheWillClear"); + + LLSearchHistory::getInstance()->clearHistory(); + LLSearchHistory::getInstance()->save(); + LLSearchComboBox* search_ctrl = LLNavigationBar::getInstance()->getChild<LLSearchComboBox>("search_combo_box"); + search_ctrl->clearHistory(); + + LLTeleportHistoryStorage::getInstance()->purgeItems(); + LLTeleportHistoryStorage::getInstance()->save(); + } + + return false; } void handleNameTagOptionChanged(const LLSD& newvalue) { - LLAvatarNameCache::getInstance()->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); - LLVOAvatar::invalidateNameTags(); + LLAvatarNameCache::getInstance()->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + LLVOAvatar::invalidateNameTags(); } void handleDisplayNamesOptionChanged(const LLSD& newvalue) { - LLAvatarNameCache::getInstance()->setUseDisplayNames(newvalue.asBoolean()); - LLVOAvatar::invalidateNameTags(); + LLAvatarNameCache::getInstance()->setUseDisplayNames(newvalue.asBoolean()); + LLVOAvatar::invalidateNameTags(); } void handleAppearanceCameraMovementChanged(const LLSD& newvalue) { - if(!newvalue.asBoolean() && gAgentCamera.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR) - { - gAgentCamera.changeCameraToDefault(); - gAgentCamera.resetView(); - } + if(!newvalue.asBoolean() && gAgentCamera.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR) + { + gAgentCamera.changeCameraToDefault(); + gAgentCamera.resetView(); + } } void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { - numerator = 0; - denominator = 0; - for (F32 test_denominator = 1.f; test_denominator < 30.f; test_denominator += 1.f) - { - if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f) - { - numerator = ll_round(decimal_val * test_denominator); - denominator = ll_round(test_denominator); - break; - } - } + numerator = 0; + denominator = 0; + for (F32 test_denominator = 1.f; test_denominator < 30.f; test_denominator += 1.f) + { + if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f) + { + numerator = ll_round(decimal_val * test_denominator); + denominator = ll_round(test_denominator); + break; + } + } } // handle secondlife:///app/worldmap/{NAME}/{COORDS} URLs @@ -295,89 +295,89 @@ LLKeybindingHandler gKeybindHandler; std::string LLFloaterPreference::sSkin = ""; LLFloaterPreference::LLFloaterPreference(const LLSD& key) - : LLFloater(key), - mGotPersonalInfo(false), - mLanguageChanged(false), - mAvatarDataInitialized(false), - mSearchDataDirty(true) -{ - LLConversationLog::instance().addObserver(this); - - //Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); - - static bool registered_dialog = false; - if (!registered_dialog) - { - LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>); - registered_dialog = true; - } - - mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this, _2)); - mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this, _2)); - - mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); - mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); - mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); - mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); - mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); - mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); - mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); - mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); - mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); - mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); - mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); - mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); - mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); - mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); + : LLFloater(key), + mGotPersonalInfo(false), + mLanguageChanged(false), + mAvatarDataInitialized(false), + mSearchDataDirty(true) +{ + LLConversationLog::instance().addObserver(this); + + //Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); + + static bool registered_dialog = false; + if (!registered_dialog) + { + LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>); + registered_dialog = true; + } + + mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this, _2)); + mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this, _2)); + + mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); + mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); + mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); + mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); + mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); + mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); + mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); + mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); + mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); + mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); + mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); + mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); + mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); + mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreference::onRenderOptionEnable, this)); - mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); - mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this)); - mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); - mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); - mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); - mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); - mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); - mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); - mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); - mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); - mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); - mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); - - sSkin = gSavedSettings.getString("SkinCurrent"); - - mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); - - gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); - gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); - gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); - - gSavedSettings.getControl("AppearanceCameraMovement")->getCommitSignal()->connect(boost::bind(&handleAppearanceCameraMovementChanged, _2)); + mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); + mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this)); + mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); + mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2)); + mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); + mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); + mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); + mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); + mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); + mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); + mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); + mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); + mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); + + sSkin = gSavedSettings.getString("SkinCurrent"); + + mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); + + gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); + gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); + gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); + + gSavedSettings.getControl("AppearanceCameraMovement")->getCommitSignal()->connect(boost::bind(&handleAppearanceCameraMovementChanged, _2)); gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::onAtmosShaderChange, this)); - LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); + LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); - mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); - mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); - mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering + mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); + mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); + mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering } void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type ) { - if ( APT_PROPERTIES == type ) - { - const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData ); - if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) - { + if ( APT_PROPERTIES == type ) + { + const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData ); + if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) + { mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH); mAvatarDataInitialized = true; getChild<LLUICtrl>("online_searchresults")->setValue(mAllowPublish); - } - } + } + } } void LLFloaterPreference::saveAvatarProperties( void ) @@ -430,247 +430,247 @@ void LLFloaterPreference::saveAvatarPropertiesCoro(const std::string cap_url, bo BOOL LLFloaterPreference::postBuild() { - gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); + gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); - gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged)); + gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged)); - gSavedSettings.getControl("ChatBubbleOpacity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onNameTagOpacityChange, this, _2)); + gSavedSettings.getControl("ChatBubbleOpacity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onNameTagOpacityChange, this, _2)); - gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeMaturity, this)); + gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeMaturity, this)); - gSavedPerAccountSettings.getControl("ModelUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeModelFolder, this)); + gSavedPerAccountSettings.getControl("ModelUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeModelFolder, this)); gSavedPerAccountSettings.getControl("PBRUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangePBRFolder, this)); - gSavedPerAccountSettings.getControl("TextureUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeTextureFolder, this)); - gSavedPerAccountSettings.getControl("SoundUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeSoundFolder, this)); - gSavedPerAccountSettings.getControl("AnimationUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeAnimationFolder, this)); - - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); - if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) - tabcontainer->selectFirstTab(); - - getChild<LLUICtrl>("cache_location")->setEnabled(FALSE); // make it read-only but selectable (STORM-227) - std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); - setCacheLocation(cache_location); - - getChild<LLUICtrl>("log_path_string")->setEnabled(FALSE); // make it read-only but selectable - - getChild<LLComboBox>("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); - - getChild<LLComboBox>("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); - getChild<LLComboBox>("NonFriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NonFriendIMOptions")); - getChild<LLComboBox>("ConferenceIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ConferenceIMOptions")); - getChild<LLComboBox>("GroupChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"GroupChatOptions")); - getChild<LLComboBox>("NearbyChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NearbyChatOptions")); - getChild<LLComboBox>("ObjectIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ObjectIMOptions")); - - // if floater is opened before login set default localized do not disturb message - if (LLStartUp::getStartupState() < STATE_STARTED) - { - gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); - } - - // set 'enable' property for 'Clear log...' button - changed(); - - LLLogChat::getInstance()->setSaveHistorySignal(boost::bind(&LLFloaterPreference::onLogChatHistorySaved, this)); - - LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov"); - fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); - fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); - - // Hook up and init for filtering - mFilterEdit = getChild<LLSearchEditor>("search_prefs_edit"); - mFilterEdit->setKeystrokeCallback(boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); - - // Load and assign label for 'default language' - std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "default_languages.xml"); - std::map<std::string, std::string> labels; - if (loadFromFilename(user_filename, labels)) - { - std::string system_lang = gSavedSettings.getString("SystemLanguage"); - std::map<std::string, std::string>::iterator iter = labels.find(system_lang); - if (iter != labels.end()) - { - getChild<LLComboBox>("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true); - } - else - { - LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL; - getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); - } - } - else - { - LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL; - getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); - } - - return TRUE; + gSavedPerAccountSettings.getControl("TextureUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeTextureFolder, this)); + gSavedPerAccountSettings.getControl("SoundUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeSoundFolder, this)); + gSavedPerAccountSettings.getControl("AnimationUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeAnimationFolder, this)); + + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) + tabcontainer->selectFirstTab(); + + getChild<LLUICtrl>("cache_location")->setEnabled(FALSE); // make it read-only but selectable (STORM-227) + std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); + setCacheLocation(cache_location); + + getChild<LLUICtrl>("log_path_string")->setEnabled(FALSE); // make it read-only but selectable + + getChild<LLComboBox>("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); + + getChild<LLComboBox>("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); + getChild<LLComboBox>("NonFriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NonFriendIMOptions")); + getChild<LLComboBox>("ConferenceIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ConferenceIMOptions")); + getChild<LLComboBox>("GroupChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"GroupChatOptions")); + getChild<LLComboBox>("NearbyChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NearbyChatOptions")); + getChild<LLComboBox>("ObjectIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ObjectIMOptions")); + + // if floater is opened before login set default localized do not disturb message + if (LLStartUp::getStartupState() < STATE_STARTED) + { + gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); + } + + // set 'enable' property for 'Clear log...' button + changed(); + + LLLogChat::getInstance()->setSaveHistorySignal(boost::bind(&LLFloaterPreference::onLogChatHistorySaved, this)); + + LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov"); + fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); + fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); + + // Hook up and init for filtering + mFilterEdit = getChild<LLSearchEditor>("search_prefs_edit"); + mFilterEdit->setKeystrokeCallback(boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); + + // Load and assign label for 'default language' + std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "default_languages.xml"); + std::map<std::string, std::string> labels; + if (loadFromFilename(user_filename, labels)) + { + std::string system_lang = gSavedSettings.getString("SystemLanguage"); + std::map<std::string, std::string>::iterator iter = labels.find(system_lang); + if (iter != labels.end()) + { + getChild<LLComboBox>("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true); + } + else + { + LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL; + getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + } + } + else + { + LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL; + getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + } + + return TRUE; } void LLFloaterPreference::updateDeleteTranscriptsButton() { - std::vector<std::string> list_of_transcriptions_file_names; - LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names); - getChild<LLButton>("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0); + std::vector<std::string> list_of_transcriptions_file_names; + LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names); + getChild<LLButton>("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0); } void LLFloaterPreference::onDoNotDisturbResponseChanged() { - // set "DoNotDisturbResponseChanged" TRUE if user edited message differs from default, FALSE otherwise - bool response_changed_flag = - LLTrans::getString("DoNotDisturbModeResponseDefault") - != getChild<LLUICtrl>("do_not_disturb_response")->getValue().asString(); + // set "DoNotDisturbResponseChanged" TRUE if user edited message differs from default, FALSE otherwise + bool response_changed_flag = + LLTrans::getString("DoNotDisturbModeResponseDefault") + != getChild<LLUICtrl>("do_not_disturb_response")->getValue().asString(); - gSavedPerAccountSettings.setBOOL("DoNotDisturbResponseChanged", response_changed_flag ); + gSavedPerAccountSettings.setBOOL("DoNotDisturbResponseChanged", response_changed_flag ); } LLFloaterPreference::~LLFloaterPreference() { - LLConversationLog::instance().removeObserver(this); + LLConversationLog::instance().removeObserver(this); mComplexityChangedSignal.disconnect(); } void LLFloaterPreference::draw() { - BOOL has_first_selected = (getChildRef<LLScrollListCtrl>("disabled_popups").getFirstSelected()!=NULL); - gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected); - - has_first_selected = (getChildRef<LLScrollListCtrl>("enabled_popups").getFirstSelected()!=NULL); - gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected); - - LLFloater::draw(); + BOOL has_first_selected = (getChildRef<LLScrollListCtrl>("disabled_popups").getFirstSelected()!=NULL); + gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected); + + has_first_selected = (getChildRef<LLScrollListCtrl>("enabled_popups").getFirstSelected()!=NULL); + gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected); + + LLFloater::draw(); } void LLFloaterPreference::saveSettings() { - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); - child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - child_list_t::const_iterator end = tabcontainer->getChildList()->end(); - for ( ; iter != end; ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); - if (panel) - panel->saveSettings(); - } + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + child_list_t::const_iterator end = tabcontainer->getChildList()->end(); + for ( ; iter != end; ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); + if (panel) + panel->saveSettings(); + } saveIgnoredNotifications(); -} +} void LLFloaterPreference::apply() { - LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); - - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); - if (sSkin != gSavedSettings.getString("SkinCurrent")) - { - LLNotificationsUtil::add("ChangeSkin"); - refreshSkin(this); - } - // Call apply() on all panels that derive from LLPanelPreference - for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - iter != tabcontainer->getChildList()->end(); ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); - if (panel) - panel->apply(); - } - - gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor - - LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov"); - fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); - fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); - - std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); - setCacheLocation(cache_location); - - LLViewerMedia::getInstance()->setCookiesEnabled(getChild<LLUICtrl>("cookies_enabled")->getValue()); - - if (hasChild("web_proxy_enabled", TRUE) &&hasChild("web_proxy_editor", TRUE) && hasChild("web_proxy_port", TRUE)) - { - bool proxy_enable = getChild<LLUICtrl>("web_proxy_enabled")->getValue(); - std::string proxy_address = getChild<LLUICtrl>("web_proxy_editor")->getValue(); - int proxy_port = getChild<LLUICtrl>("web_proxy_port")->getValue(); - LLViewerMedia::getInstance()->setProxyConfig(proxy_enable, proxy_address, proxy_port); - } - - if (mGotPersonalInfo) - { - bool new_hide_online = getChild<LLUICtrl>("online_visibility")->getValue().asBoolean(); - - if (new_hide_online != mOriginalHideOnlineStatus) - { - // This hack is because we are representing several different - // possible strings with a single checkbox. Since most users - // can only select between 2 values, we represent it as a - // checkbox. This breaks down a little bit for liaisons, but - // works out in the end. - if (new_hide_online != mOriginalHideOnlineStatus) - { - if (new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN; - else mDirectoryVisibility = VISIBILITY_DEFAULT; - //Update showonline value, otherwise multiple applys won't work - mOriginalHideOnlineStatus = new_hide_online; - } - gAgent.sendAgentUpdateUserInfo(mDirectoryVisibility); - } - } - - saveAvatarProperties(); + LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); + + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + if (sSkin != gSavedSettings.getString("SkinCurrent")) + { + LLNotificationsUtil::add("ChangeSkin"); + refreshSkin(this); + } + // Call apply() on all panels that derive from LLPanelPreference + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); + if (panel) + panel->apply(); + } + + gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor + + LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov"); + fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); + fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); + + std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); + setCacheLocation(cache_location); + + LLViewerMedia::getInstance()->setCookiesEnabled(getChild<LLUICtrl>("cookies_enabled")->getValue()); + + if (hasChild("web_proxy_enabled", TRUE) &&hasChild("web_proxy_editor", TRUE) && hasChild("web_proxy_port", TRUE)) + { + bool proxy_enable = getChild<LLUICtrl>("web_proxy_enabled")->getValue(); + std::string proxy_address = getChild<LLUICtrl>("web_proxy_editor")->getValue(); + int proxy_port = getChild<LLUICtrl>("web_proxy_port")->getValue(); + LLViewerMedia::getInstance()->setProxyConfig(proxy_enable, proxy_address, proxy_port); + } + + if (mGotPersonalInfo) + { + bool new_hide_online = getChild<LLUICtrl>("online_visibility")->getValue().asBoolean(); + + if (new_hide_online != mOriginalHideOnlineStatus) + { + // This hack is because we are representing several different + // possible strings with a single checkbox. Since most users + // can only select between 2 values, we represent it as a + // checkbox. This breaks down a little bit for liaisons, but + // works out in the end. + if (new_hide_online != mOriginalHideOnlineStatus) + { + if (new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN; + else mDirectoryVisibility = VISIBILITY_DEFAULT; + //Update showonline value, otherwise multiple applys won't work + mOriginalHideOnlineStatus = new_hide_online; + } + gAgent.sendAgentUpdateUserInfo(mDirectoryVisibility); + } + } + + saveAvatarProperties(); } void LLFloaterPreference::cancel() { - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); - // Call cancel() on all panels that derive from LLPanelPreference - for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - iter != tabcontainer->getChildList()->end(); ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); - if (panel) - panel->cancel(); - } - // hide joystick pref floater - LLFloaterReg::hideInstance("pref_joystick"); - - // hide translation settings floater - LLFloaterReg::hideInstance("prefs_translation"); - - // hide autoreplace settings floater - LLFloaterReg::hideInstance("prefs_autoreplace"); - - // hide spellchecker settings folder - LLFloaterReg::hideInstance("prefs_spellchecker"); - - // hide advanced graphics floater - LLFloaterReg::hideInstance("prefs_graphics_advanced"); - - // reverts any changes to current skin - gSavedSettings.setString("SkinCurrent", sSkin); - - updateClickActionViews(); - - LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy"); - if (advanced_proxy_settings) - { - advanced_proxy_settings->cancel(); - } - //Need to reload the navmesh if the pathing console is up - LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); - if ( !pathfindingConsoleHandle.isDead() ) - { - LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); - pPathfindingConsole->onRegionBoundaryCross(); - } - - if (!mSavedGraphicsPreset.empty()) - { - gSavedSettings.setString("PresetGraphicActive", mSavedGraphicsPreset); - LLPresetsManager::getInstance()->triggerChangeSignal(); - } + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + // Call cancel() on all panels that derive from LLPanelPreference + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); + if (panel) + panel->cancel(); + } + // hide joystick pref floater + LLFloaterReg::hideInstance("pref_joystick"); + + // hide translation settings floater + LLFloaterReg::hideInstance("prefs_translation"); + + // hide autoreplace settings floater + LLFloaterReg::hideInstance("prefs_autoreplace"); + + // hide spellchecker settings folder + LLFloaterReg::hideInstance("prefs_spellchecker"); + + // hide advanced graphics floater + LLFloaterReg::hideInstance("prefs_graphics_advanced"); + + // reverts any changes to current skin + gSavedSettings.setString("SkinCurrent", sSkin); + + updateClickActionViews(); + + LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy"); + if (advanced_proxy_settings) + { + advanced_proxy_settings->cancel(); + } + //Need to reload the navmesh if the pathing console is up + LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if ( !pathfindingConsoleHandle.isDead() ) + { + LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); + pPathfindingConsole->onRegionBoundaryCross(); + } + + if (!mSavedGraphicsPreset.empty()) + { + gSavedSettings.setString("PresetGraphicActive", mSavedGraphicsPreset); + LLPresetsManager::getInstance()->triggerChangeSignal(); + } restoreIgnoredNotifications(); } @@ -678,157 +678,157 @@ void LLFloaterPreference::cancel() void LLFloaterPreference::onOpen(const LLSD& key) { - // this variable and if that follows it are used to properly handle do not disturb mode response message - static bool initialized = FALSE; - // if user is logged in and we haven't initialized do not disturb mode response yet, do it - if (!initialized && LLStartUp::getStartupState() == STATE_STARTED) - { - // Special approach is used for do not disturb response localization, because "DoNotDisturbModeResponse" is - // in non-localizable xml, and also because it may be changed by user and in this case it shouldn't be localized. - // To keep track of whether do not disturb response is default or changed by user additional setting DoNotDisturbResponseChanged - // was added into per account settings. - - // initialization should happen once,so setting variable to TRUE - initialized = TRUE; - // this connection is needed to properly set "DoNotDisturbResponseChanged" setting when user makes changes in - // do not disturb response message. - gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->getSignal()->connect(boost::bind(&LLFloaterPreference::onDoNotDisturbResponseChanged, this)); - } - gAgent.sendAgentUserInfoRequest(); - - /////////////////////////// From LLPanelGeneral ////////////////////////// - // if we have no agent, we can't let them choose anything - // if we have an agent, then we only let them choose if they have a choice - bool can_choose_maturity = - gAgent.getID().notNull() && - (gAgent.isMature() || gAgent.isGodlike()); - - LLComboBox* maturity_combo = getChild<LLComboBox>("maturity_desired_combobox"); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() ); - if (can_choose_maturity) - { - // if they're not adult or a god, they shouldn't see the adult selection, so delete it - if (!gAgent.isAdult() && !gAgent.isGodlikeWithoutAdminMenuFakery()) - { - // we're going to remove the adult entry from the combo - LLScrollListCtrl* maturity_list = maturity_combo->findChild<LLScrollListCtrl>("ComboBox"); - if (maturity_list) - { - maturity_list->deleteItems(LLSD(SIM_ACCESS_ADULT)); - } - } - getChildView("maturity_desired_combobox")->setEnabled( true); - getChildView("maturity_desired_textbox")->setVisible( false); - } - else - { - getChild<LLUICtrl>("maturity_desired_textbox")->setValue(maturity_combo->getSelectedItemLabel()); - getChildView("maturity_desired_combobox")->setEnabled( false); - } - - // Forget previous language changes. - mLanguageChanged = false; - - // Display selected maturity icons. - onChangeMaturity(); - - onChangeModelFolder(); + // this variable and if that follows it are used to properly handle do not disturb mode response message + static bool initialized = FALSE; + // if user is logged in and we haven't initialized do not disturb mode response yet, do it + if (!initialized && LLStartUp::getStartupState() == STATE_STARTED) + { + // Special approach is used for do not disturb response localization, because "DoNotDisturbModeResponse" is + // in non-localizable xml, and also because it may be changed by user and in this case it shouldn't be localized. + // To keep track of whether do not disturb response is default or changed by user additional setting DoNotDisturbResponseChanged + // was added into per account settings. + + // initialization should happen once,so setting variable to TRUE + initialized = TRUE; + // this connection is needed to properly set "DoNotDisturbResponseChanged" setting when user makes changes in + // do not disturb response message. + gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->getSignal()->connect(boost::bind(&LLFloaterPreference::onDoNotDisturbResponseChanged, this)); + } + gAgent.sendAgentUserInfoRequest(); + + /////////////////////////// From LLPanelGeneral ////////////////////////// + // if we have no agent, we can't let them choose anything + // if we have an agent, then we only let them choose if they have a choice + bool can_choose_maturity = + gAgent.getID().notNull() && + (gAgent.isMature() || gAgent.isGodlike()); + + LLComboBox* maturity_combo = getChild<LLComboBox>("maturity_desired_combobox"); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() ); + if (can_choose_maturity) + { + // if they're not adult or a god, they shouldn't see the adult selection, so delete it + if (!gAgent.isAdult() && !gAgent.isGodlikeWithoutAdminMenuFakery()) + { + // we're going to remove the adult entry from the combo + LLScrollListCtrl* maturity_list = maturity_combo->findChild<LLScrollListCtrl>("ComboBox"); + if (maturity_list) + { + maturity_list->deleteItems(LLSD(SIM_ACCESS_ADULT)); + } + } + getChildView("maturity_desired_combobox")->setEnabled( true); + getChildView("maturity_desired_textbox")->setVisible( false); + } + else + { + getChild<LLUICtrl>("maturity_desired_textbox")->setValue(maturity_combo->getSelectedItemLabel()); + getChildView("maturity_desired_combobox")->setEnabled( false); + } + + // Forget previous language changes. + mLanguageChanged = false; + + // Display selected maturity icons. + onChangeMaturity(); + + onChangeModelFolder(); onChangePBRFolder(); - onChangeTextureFolder(); - onChangeSoundFolder(); - onChangeAnimationFolder(); - - // Load (double-)click to walk/teleport settings. - updateClickActionViews(); - - // Enabled/disabled popups, might have been changed by user actions - // while preferences floater was closed. - buildPopupLists(); - - - //get the options that were checked - onNotificationsChange("FriendIMOptions"); - onNotificationsChange("NonFriendIMOptions"); - onNotificationsChange("ConferenceIMOptions"); - onNotificationsChange("GroupChatOptions"); - onNotificationsChange("NearbyChatOptions"); - onNotificationsChange("ObjectIMOptions"); - - LLPanelLogin::setAlwaysRefresh(true); - refresh(); - - // Make sure the current state of prefs are saved away when - // when the floater is opened. That will make cancel do its - // job - saveSettings(); - - // Make sure there is a default preference file - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_GRAPHIC); - - bool started = (LLStartUp::getStartupState() == STATE_STARTED); - - LLButton* load_btn = findChild<LLButton>("PrefLoadButton"); - LLButton* save_btn = findChild<LLButton>("PrefSaveButton"); - LLButton* delete_btn = findChild<LLButton>("PrefDeleteButton"); - LLButton* exceptions_btn = findChild<LLButton>("RenderExceptionsButton"); + onChangeTextureFolder(); + onChangeSoundFolder(); + onChangeAnimationFolder(); + + // Load (double-)click to walk/teleport settings. + updateClickActionViews(); + + // Enabled/disabled popups, might have been changed by user actions + // while preferences floater was closed. + buildPopupLists(); + + + //get the options that were checked + onNotificationsChange("FriendIMOptions"); + onNotificationsChange("NonFriendIMOptions"); + onNotificationsChange("ConferenceIMOptions"); + onNotificationsChange("GroupChatOptions"); + onNotificationsChange("NearbyChatOptions"); + onNotificationsChange("ObjectIMOptions"); + + LLPanelLogin::setAlwaysRefresh(true); + refresh(); + + // Make sure the current state of prefs are saved away when + // when the floater is opened. That will make cancel do its + // job + saveSettings(); + + // Make sure there is a default preference file + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_GRAPHIC); + + bool started = (LLStartUp::getStartupState() == STATE_STARTED); + + LLButton* load_btn = findChild<LLButton>("PrefLoadButton"); + LLButton* save_btn = findChild<LLButton>("PrefSaveButton"); + LLButton* delete_btn = findChild<LLButton>("PrefDeleteButton"); + LLButton* exceptions_btn = findChild<LLButton>("RenderExceptionsButton"); LLButton* auto_adjustments_btn = findChild<LLButton>("AutoAdjustmentsButton"); - if (load_btn && save_btn && delete_btn && exceptions_btn && auto_adjustments_btn) - { - load_btn->setEnabled(started); - save_btn->setEnabled(started); - delete_btn->setEnabled(started); - exceptions_btn->setEnabled(started); + if (load_btn && save_btn && delete_btn && exceptions_btn && auto_adjustments_btn) + { + load_btn->setEnabled(started); + save_btn->setEnabled(started); + delete_btn->setEnabled(started); + exceptions_btn->setEnabled(started); auto_adjustments_btn->setEnabled(started); - } + } collectSearchableItems(); - if (!mFilterEdit->getText().empty()) - { - mFilterEdit->setText(LLStringExplicit("")); - onUpdateFilterTerm(true); - } + if (!mFilterEdit->getText().empty()) + { + mFilterEdit->setText(LLStringExplicit("")); + onUpdateFilterTerm(true); + } } void LLFloaterPreference::onRenderOptionEnable() { - refreshEnabledGraphics(); + refreshEnabledGraphics(); } void LLFloaterPreference::onAvatarImpostorsEnable() { - refreshEnabledGraphics(); + refreshEnabledGraphics(); } //static void LLFloaterPreference::initDoNotDisturbResponse() - { - if (!gSavedPerAccountSettings.getBOOL("DoNotDisturbResponseChanged")) - { - //LLTrans::getString("DoNotDisturbModeResponseDefault") is used here for localization (EXT-5885) - gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); - } - } - -//static + { + if (!gSavedPerAccountSettings.getBOOL("DoNotDisturbResponseChanged")) + { + //LLTrans::getString("DoNotDisturbModeResponseDefault") is used here for localization (EXT-5885) + gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); + } + } + +//static void LLFloaterPreference::updateShowFavoritesCheckbox(bool val) { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->getChild<LLUICtrl>("favorites_on_login_check")->setValue(val); - } + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->getChild<LLUICtrl>("favorites_on_login_check")->setValue(val); + } } void LLFloaterPreference::setHardwareDefaults() { - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - if (!preset_graphic_active.empty()) - { - saveGraphicsPreset(preset_graphic_active); - saveSettings(); // save here to be able to return to the previous preset by Cancel - } + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + if (!preset_graphic_active.empty()) + { + saveGraphicsPreset(preset_graphic_active); + saveSettings(); // save here to be able to return to the previous preset by Cancel + } setRecommendedSettings(); } @@ -837,27 +837,27 @@ void LLFloaterPreference::setRecommendedSettings() resetAutotuneSettings(); gSavedSettings.getControl("RenderVSyncEnable")->resetToDefault(true); - LLFeatureManager::getInstance()->applyRecommendedSettings(); + LLFeatureManager::getInstance()->applyRecommendedSettings(); - // reset indirects before refresh because we may have changed what they control - LLAvatarComplexityControls::setIndirectControls(); + // reset indirects before refresh because we may have changed what they control + LLAvatarComplexityControls::setIndirectControls(); - refreshEnabledGraphics(); - gSavedSettings.setString("PresetGraphicActive", ""); - LLPresetsManager::getInstance()->triggerChangeSignal(); + refreshEnabledGraphics(); + gSavedSettings.setString("PresetGraphicActive", ""); + LLPresetsManager::getInstance()->triggerChangeSignal(); - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); - child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - child_list_t::const_iterator end = tabcontainer->getChildList()->end(); - for ( ; iter != end; ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); - if (panel) - { - panel->setHardwareDefaults(); - } - } + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + child_list_t::const_iterator end = tabcontainer->getChildList()->end(); + for ( ; iter != end; ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view); + if (panel) + { + panel->setHardwareDefaults(); + } + } } void LLFloaterPreference::resetAutotuneSettings() @@ -884,452 +884,452 @@ void LLFloaterPreference::resetAutotuneSettings() void LLFloaterPreference::getControlNames(std::vector<std::string>& names) { - LLView* view = findChild<LLView>("display"); - LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); - if (view && advanced) - { - std::list<LLView*> stack; - stack.push_back(view); - stack.push_back(advanced); - while(!stack.empty()) - { - // Process view on top of the stack - LLView* curview = stack.front(); - stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); - if (ctrl) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - std::string control_name = control->getName(); - if (std::find(names.begin(), names.end(), control_name) == names.end()) - { - names.push_back(control_name); - } - } - } - - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - stack.push_back(*iter); - } - } - } + LLView* view = findChild<LLView>("display"); + LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); + if (view && advanced) + { + std::list<LLView*> stack; + stack.push_back(view); + stack.push_back(advanced); + while(!stack.empty()) + { + // Process view on top of the stack + LLView* curview = stack.front(); + stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + std::string control_name = control->getName(); + if (std::find(names.begin(), names.end(), control_name) == names.end()) + { + names.push_back(control_name); + } + } + } + + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + stack.push_back(*iter); + } + } + } } //virtual void LLFloaterPreference::onClose(bool app_quitting) { - gSavedSettings.setS32("LastPrefTab", getChild<LLTabContainer>("pref core")->getCurrentPanelIndex()); - LLPanelLogin::setAlwaysRefresh(false); - if (!app_quitting) - { - cancel(); - } + gSavedSettings.setS32("LastPrefTab", getChild<LLTabContainer>("pref core")->getCurrentPanelIndex()); + LLPanelLogin::setAlwaysRefresh(false); + if (!app_quitting) + { + cancel(); + } } -// static +// static void LLFloaterPreference::onBtnOK(const LLSD& userdata) { - // commit any outstanding text entry - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - } - - if (canClose()) - { - saveSettings(); - apply(); - - if (userdata.asString() == "closeadvanced") - { - LLFloaterReg::hideInstance("prefs_graphics_advanced"); - } - else - { - closeFloater(false); - } - - //Conversation transcript and log path changed so reload conversations based on new location - if(mPriorInstantMessageLogPath.length()) - { - if(moveTranscriptsAndLog()) - { - //When floaters are empty but have a chat history files, reload chat history into them - LLFloaterIMSessionTab::reloadEmptyFloaters(); - } - //Couldn't move files so restore the old path and show a notification - else - { - gSavedPerAccountSettings.setString("InstantMessageLogPath", mPriorInstantMessageLogPath); - LLNotificationsUtil::add("PreferenceChatPathChanged"); - } - mPriorInstantMessageLogPath.clear(); - } - - LLUIColorTable::instance().saveUserSettings(); - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - - //Only save once logged in and loaded per account settings - if(mGotPersonalInfo) - { - gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - } - } - else - { - // Show beep, pop up dialog, etc. - LL_INFOS("Preferences") << "Can't close preferences!" << LL_ENDL; - } - - LLPanelLogin::updateLocationSelectorsVisibility(); - //Need to reload the navmesh if the pathing console is up - LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); - if ( !pathfindingConsoleHandle.isDead() ) - { - LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); - pPathfindingConsole->onRegionBoundaryCross(); - } -} - -// static + // commit any outstanding text entry + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + } + + if (canClose()) + { + saveSettings(); + apply(); + + if (userdata.asString() == "closeadvanced") + { + LLFloaterReg::hideInstance("prefs_graphics_advanced"); + } + else + { + closeFloater(false); + } + + //Conversation transcript and log path changed so reload conversations based on new location + if(mPriorInstantMessageLogPath.length()) + { + if(moveTranscriptsAndLog()) + { + //When floaters are empty but have a chat history files, reload chat history into them + LLFloaterIMSessionTab::reloadEmptyFloaters(); + } + //Couldn't move files so restore the old path and show a notification + else + { + gSavedPerAccountSettings.setString("InstantMessageLogPath", mPriorInstantMessageLogPath); + LLNotificationsUtil::add("PreferenceChatPathChanged"); + } + mPriorInstantMessageLogPath.clear(); + } + + LLUIColorTable::instance().saveUserSettings(); + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + + //Only save once logged in and loaded per account settings + if(mGotPersonalInfo) + { + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + } + } + else + { + // Show beep, pop up dialog, etc. + LL_INFOS("Preferences") << "Can't close preferences!" << LL_ENDL; + } + + LLPanelLogin::updateLocationSelectorsVisibility(); + //Need to reload the navmesh if the pathing console is up + LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if ( !pathfindingConsoleHandle.isDead() ) + { + LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); + pPathfindingConsole->onRegionBoundaryCross(); + } +} + +// static void LLFloaterPreference::onBtnCancel(const LLSD& userdata) { - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - refresh(); - } - cancel(); - - if (userdata.asString() == "closeadvanced") - { - LLFloaterReg::hideInstance("prefs_graphics_advanced"); - } - else - { - closeFloater(); - } -} - -// static + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + refresh(); + } + cancel(); + + if (userdata.asString() == "closeadvanced") + { + LLFloaterReg::hideInstance("prefs_graphics_advanced"); + } + else + { + closeFloater(); + } +} + +// static void LLFloaterPreference::updateUserInfo(const std::string& visibility) { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { instance->setPersonalInfo(visibility); - } + } } void LLFloaterPreference::refreshEnabledGraphics() { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->refresh(); - } + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->refresh(); + } - LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); - if (advanced) - { - advanced->refresh(); - } + LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); + if (advanced) + { + advanced->refresh(); + } } void LLFloaterPreference::onClickClearCache() { - LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache); + LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache); } void LLFloaterPreference::onClickBrowserClearCache() { - LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache); + LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache); } // Called when user changes language via the combobox. void LLFloaterPreference::onLanguageChange() { - // Let the user know that the change will only take effect after restart. - // Do it only once so that we're not too irritating. - if (!mLanguageChanged) - { - LLNotificationsUtil::add("ChangeLanguage"); - mLanguageChanged = true; - } + // Let the user know that the change will only take effect after restart. + // Do it only once so that we're not too irritating. + if (!mLanguageChanged) + { + LLNotificationsUtil::add("ChangeLanguage"); + mLanguageChanged = true; + } } void LLFloaterPreference::onNotificationsChange(const std::string& OptionName) { - mNotificationOptions[OptionName] = getChild<LLComboBox>(OptionName)->getSelectedItemLabel(); + mNotificationOptions[OptionName] = getChild<LLComboBox>(OptionName)->getSelectedItemLabel(); - bool show_notifications_alert = true; - for (notifications_map::iterator it_notification = mNotificationOptions.begin(); it_notification != mNotificationOptions.end(); it_notification++) - { - if(it_notification->second != "No action") - { - show_notifications_alert = false; - break; - } - } + bool show_notifications_alert = true; + for (notifications_map::iterator it_notification = mNotificationOptions.begin(); it_notification != mNotificationOptions.end(); it_notification++) + { + if(it_notification->second != "No action") + { + show_notifications_alert = false; + break; + } + } - getChild<LLTextBox>("notifications_alert")->setVisible(show_notifications_alert); + getChild<LLTextBox>("notifications_alert")->setVisible(show_notifications_alert); } void LLFloaterPreference::onNameTagOpacityChange(const LLSD& newvalue) { - LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("background"); - if (color_swatch) - { - LLColor4 new_color = color_swatch->get(); - color_swatch->set( new_color.setAlpha(newvalue.asReal()) ); - } + LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("background"); + if (color_swatch) + { + LLColor4 new_color = color_swatch->get(); + color_swatch->set( new_color.setAlpha(newvalue.asReal()) ); + } } void LLFloaterPreference::onClickSetCache() { - std::string cur_name(gSavedSettings.getString("CacheLocation")); -// std::string cur_top_folder(gDirUtilp->getBaseFileName(cur_name)); - - std::string proposed_name(cur_name); + std::string cur_name(gSavedSettings.getString("CacheLocation")); +// std::string cur_top_folder(gDirUtilp->getBaseFileName(cur_name)); + + std::string proposed_name(cur_name); - (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeCachePath, this, _1, _2), proposed_name))->getFile(); + (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeCachePath, this, _1, _2), proposed_name))->getFile(); } 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)); - LLNotificationsUtil::add("CacheWillBeMoved"); - gSavedSettings.setString("NewCacheLocation", dir_name); - gSavedSettings.setString("NewCacheLocationTopFolder", new_top_folder); - } - else - { - std::string cache_location = gDirUtilp->getCacheDir(); - gSavedSettings.setString("CacheLocation", cache_location); - std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); - gSavedSettings.setString("CacheLocationTopFolder", top_folder); - } + std::string dir_name = filenames[0]; + if (!dir_name.empty() && dir_name != proposed_name) + { + std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name)); + LLNotificationsUtil::add("CacheWillBeMoved"); + gSavedSettings.setString("NewCacheLocation", dir_name); + gSavedSettings.setString("NewCacheLocationTopFolder", new_top_folder); + } + else + { + std::string cache_location = gDirUtilp->getCacheDir(); + gSavedSettings.setString("CacheLocation", cache_location); + std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); + gSavedSettings.setString("CacheLocationTopFolder", top_folder); + } } void LLFloaterPreference::onClickResetCache() { - if (gDirUtilp->getCacheDir(false) == gDirUtilp->getCacheDir(true)) - { - // The cache location was already the default. - return; - } - gSavedSettings.setString("NewCacheLocation", ""); - gSavedSettings.setString("NewCacheLocationTopFolder", ""); - LLNotificationsUtil::add("CacheWillBeMoved"); - std::string cache_location = gDirUtilp->getCacheDir(false); - gSavedSettings.setString("CacheLocation", cache_location); - std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); - gSavedSettings.setString("CacheLocationTopFolder", top_folder); + if (gDirUtilp->getCacheDir(false) == gDirUtilp->getCacheDir(true)) + { + // The cache location was already the default. + return; + } + gSavedSettings.setString("NewCacheLocation", ""); + gSavedSettings.setString("NewCacheLocationTopFolder", ""); + LLNotificationsUtil::add("CacheWillBeMoved"); + std::string cache_location = gDirUtilp->getCacheDir(false); + gSavedSettings.setString("CacheLocation", cache_location); + std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); + gSavedSettings.setString("CacheLocationTopFolder", top_folder); } void LLFloaterPreference::onClickSkin(LLUICtrl* ctrl, const LLSD& userdata) { - gSavedSettings.setString("SkinCurrent", userdata.asString()); - ctrl->setValue(userdata.asString()); + gSavedSettings.setString("SkinCurrent", userdata.asString()); + ctrl->setValue(userdata.asString()); } void LLFloaterPreference::onSelectSkin() { - std::string skin_selection = getChild<LLRadioGroup>("skin_selection")->getValue().asString(); - gSavedSettings.setString("SkinCurrent", skin_selection); + std::string skin_selection = getChild<LLRadioGroup>("skin_selection")->getValue().asString(); + gSavedSettings.setString("SkinCurrent", skin_selection); } void LLFloaterPreference::refreshSkin(void* data) { - LLPanel*self = (LLPanel*)data; - sSkin = gSavedSettings.getString("SkinCurrent"); - self->getChild<LLRadioGroup>("skin_selection", true)->setValue(sSkin); + LLPanel*self = (LLPanel*)data; + sSkin = gSavedSettings.getString("SkinCurrent"); + self->getChild<LLRadioGroup>("skin_selection", true)->setValue(sSkin); } void LLFloaterPreference::buildPopupLists() { - LLScrollListCtrl& disabled_popups = - getChildRef<LLScrollListCtrl>("disabled_popups"); - LLScrollListCtrl& enabled_popups = - getChildRef<LLScrollListCtrl>("enabled_popups"); - - disabled_popups.deleteAllItems(); - enabled_popups.deleteAllItems(); - - for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); - iter != LLNotifications::instance().templatesEnd(); - ++iter) - { - LLNotificationTemplatePtr templatep = iter->second; - LLNotificationFormPtr formp = templatep->mForm; - - LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); - if (ignore <= LLNotificationForm::IGNORE_NO) - continue; - - LLSD row; - row["columns"][0]["value"] = formp->getIgnoreMessage(); - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - row["columns"][0]["width"] = 400; - - LLScrollListItem* item = NULL; - - bool show_popup = !formp->getIgnored(); - if (!show_popup) - { - if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName); - if (!last_response.isUndefined()) - { - for (LLSD::map_const_iterator it = last_response.beginMap(); - it != last_response.endMap(); - ++it) - { - if (it->second.asBoolean()) - { - row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString(); - row["columns"][1]["font"] = "SANSSERIF_SMALL"; - row["columns"][1]["width"] = 360; - break; - } - } - } - } - item = disabled_popups.addElement(row); - } - else - { - item = enabled_popups.addElement(row); - } - - if (item) - { - item->setUserdata((void*)&iter->first); - } - } + LLScrollListCtrl& disabled_popups = + getChildRef<LLScrollListCtrl>("disabled_popups"); + LLScrollListCtrl& enabled_popups = + getChildRef<LLScrollListCtrl>("enabled_popups"); + + disabled_popups.deleteAllItems(); + enabled_popups.deleteAllItems(); + + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + LLNotificationTemplatePtr templatep = iter->second; + LLNotificationFormPtr formp = templatep->mForm; + + LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); + if (ignore <= LLNotificationForm::IGNORE_NO) + continue; + + LLSD row; + row["columns"][0]["value"] = formp->getIgnoreMessage(); + row["columns"][0]["font"] = "SANSSERIF_SMALL"; + row["columns"][0]["width"] = 400; + + LLScrollListItem* item = NULL; + + bool show_popup = !formp->getIgnored(); + if (!show_popup) + { + if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName); + if (!last_response.isUndefined()) + { + for (LLSD::map_const_iterator it = last_response.beginMap(); + it != last_response.endMap(); + ++it) + { + if (it->second.asBoolean()) + { + row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString(); + row["columns"][1]["font"] = "SANSSERIF_SMALL"; + row["columns"][1]["width"] = 360; + break; + } + } + } + } + item = disabled_popups.addElement(row); + } + else + { + item = enabled_popups.addElement(row); + } + + if (item) + { + item->setUserdata((void*)&iter->first); + } + } } void LLFloaterPreference::refreshEnabledState() { - LLCheckBoxCtrl* ctrl_pbr = getChild<LLCheckBoxCtrl>("UsePBRShaders"); + LLCheckBoxCtrl* ctrl_pbr = getChild<LLCheckBoxCtrl>("UsePBRShaders"); //PBR ctrl_pbr->setEnabled(TRUE); - // Cannot have floater active until caps have been received - getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); + // Cannot have floater active until caps have been received + getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); - getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); + getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); } void LLAvatarComplexityControls::setIndirectControls() { - /* - * We have controls that have an indirect relationship between the control - * values and adjacent text and the underlying setting they influence. - * In each case, the control and its associated setting are named Indirect<something> - * This method interrogates the controlled setting and establishes the - * appropriate value for the indirect control. It must be called whenever the - * underlying setting may have changed other than through the indirect control, - * such as when the 'Reset all to recommended settings' button is used... - */ - setIndirectMaxNonImpostors(); - setIndirectMaxArc(); + /* + * We have controls that have an indirect relationship between the control + * values and adjacent text and the underlying setting they influence. + * In each case, the control and its associated setting are named Indirect<something> + * This method interrogates the controlled setting and establishes the + * appropriate value for the indirect control. It must be called whenever the + * underlying setting may have changed other than through the indirect control, + * such as when the 'Reset all to recommended settings' button is used... + */ + setIndirectMaxNonImpostors(); + setIndirectMaxArc(); } // static void LLAvatarComplexityControls::setIndirectMaxNonImpostors() { - U32 max_non_impostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); - // for this one, we just need to make zero, which means off, the max value of the slider - U32 indirect_max_non_impostors = (0 == max_non_impostors) ? LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER : max_non_impostors; - gSavedSettings.setU32("IndirectMaxNonImpostors", indirect_max_non_impostors); + U32 max_non_impostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); + // for this one, we just need to make zero, which means off, the max value of the slider + U32 indirect_max_non_impostors = (0 == max_non_impostors) ? LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER : max_non_impostors; + gSavedSettings.setU32("IndirectMaxNonImpostors", indirect_max_non_impostors); } void LLAvatarComplexityControls::setIndirectMaxArc() { - U32 max_arc = gSavedSettings.getU32("RenderAvatarMaxComplexity"); - U32 indirect_max_arc; - if (0 == max_arc) - { - // the off position is all the way to the right, so set to control max - indirect_max_arc = INDIRECT_MAX_ARC_OFF; - } - else - { - // This is the inverse of the calculation in updateMaxComplexity - indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT; - } - gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); + U32 max_arc = gSavedSettings.getU32("RenderAvatarMaxComplexity"); + U32 indirect_max_arc; + if (0 == max_arc) + { + // the off position is all the way to the right, so set to control max + indirect_max_arc = INDIRECT_MAX_ARC_OFF; + } + else + { + // This is the inverse of the calculation in updateMaxComplexity + indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT; + } + gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); } void LLFloaterPreference::refresh() { - LLPanel::refresh(); + LLPanel::refresh(); LLAvatarComplexityControls::setText( gSavedSettings.getU32("RenderAvatarMaxComplexity"), getChild<LLTextBox>("IndirectMaxComplexityText", true)); - refreshEnabledState(); - LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); - if (advanced) - { - advanced->refresh(); - } + refreshEnabledState(); + LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); + if (advanced) + { + advanced->refresh(); + } updateClickActionViews(); } void LLFloaterPreference::onCommitWindowedMode() { - refresh(); + refresh(); } void LLFloaterPreference::onChangeQuality(const LLSD& data) { - U32 level = (U32)(data.asReal()); - LLFeatureManager::getInstance()->setGraphicsLevel(level, true); - refreshEnabledGraphics(); - refresh(); + U32 level = (U32)(data.asReal()); + LLFeatureManager::getInstance()->setGraphicsLevel(level, true); + refreshEnabledGraphics(); + refresh(); } void LLFloaterPreference::onClickSetSounds() { - // Disable Enable gesture sounds checkbox if the master sound is disabled - // or if sound effects are disabled. - getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); + // Disable Enable gesture sounds checkbox if the master sound is disabled + // or if sound effects are disabled. + getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } void LLFloaterPreference::onClickEnablePopup() -{ - LLScrollListCtrl& disabled_popups = getChildRef<LLScrollListCtrl>("disabled_popups"); - - std::vector<LLScrollListItem*> items = disabled_popups.getAllSelected(); - std::vector<LLScrollListItem*>::iterator itor; - for (itor = items.begin(); itor != items.end(); ++itor) - { - LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); - //gSavedSettings.setWarning(templatep->mName, TRUE); - std::string notification_name = templatep->mName; - LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE); - } - - buildPopupLists(); +{ + LLScrollListCtrl& disabled_popups = getChildRef<LLScrollListCtrl>("disabled_popups"); + + std::vector<LLScrollListItem*> items = disabled_popups.getAllSelected(); + std::vector<LLScrollListItem*>::iterator itor; + for (itor = items.begin(); itor != items.end(); ++itor) + { + LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); + //gSavedSettings.setWarning(templatep->mName, TRUE); + std::string notification_name = templatep->mName; + LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE); + } + + buildPopupLists(); if (!mFilterEdit->getText().empty()) { filterIgnorableNotifications(); @@ -1337,18 +1337,18 @@ void LLFloaterPreference::onClickEnablePopup() } void LLFloaterPreference::onClickDisablePopup() -{ - LLScrollListCtrl& enabled_popups = getChildRef<LLScrollListCtrl>("enabled_popups"); - - std::vector<LLScrollListItem*> items = enabled_popups.getAllSelected(); - std::vector<LLScrollListItem*>::iterator itor; - for (itor = items.begin(); itor != items.end(); ++itor) - { - LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); - templatep->mForm->setIgnored(true); - } - - buildPopupLists(); +{ + LLScrollListCtrl& enabled_popups = getChildRef<LLScrollListCtrl>("enabled_popups"); + + std::vector<LLScrollListItem*> items = enabled_popups.getAllSelected(); + std::vector<LLScrollListItem*>::iterator itor; + for (itor = items.begin(); itor != items.end(); ++itor) + { + LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); + templatep->mForm->setIgnored(true); + } + + buildPopupLists(); if (!mFilterEdit->getText().empty()) { filterIgnorableNotifications(); @@ -1357,191 +1357,191 @@ void LLFloaterPreference::onClickDisablePopup() void LLFloaterPreference::resetAllIgnored() { - for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); - iter != LLNotifications::instance().templatesEnd(); - ++iter) - { - if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) - { - iter->second->mForm->setIgnored(false); - } - } + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) + { + iter->second->mForm->setIgnored(false); + } + } } void LLFloaterPreference::setAllIgnored() { - for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); - iter != LLNotifications::instance().templatesEnd(); - ++iter) - { - if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) - { - iter->second->mForm->setIgnored(true); - } - } + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) + { + iter->second->mForm->setIgnored(true); + } + } } void LLFloaterPreference::onClickLogPath() { - std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - mPriorInstantMessageLogPath.clear(); - + std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + mPriorInstantMessageLogPath.clear(); + - (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeLogPath, this, _1, _2), proposed_name))->getFile(); + (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 != filenames[0]) - { - gSavedPerAccountSettings.setString("InstantMessageLogPath", filenames[0]); - mPriorInstantMessageLogPath = proposed_name; + //Path changed + if (proposed_name != filenames[0]) + { + gSavedPerAccountSettings.setString("InstantMessageLogPath", filenames[0]); + mPriorInstantMessageLogPath = proposed_name; - // enable/disable 'Delete transcripts button - updateDeleteTranscriptsButton(); - } + // enable/disable 'Delete transcripts button + updateDeleteTranscriptsButton(); + } } bool LLFloaterPreference::moveTranscriptsAndLog() { - std::string instantMessageLogPath(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - std::string chatLogPath = gDirUtilp->add(instantMessageLogPath, gDirUtilp->getUserName()); - - bool madeDirectory = false; - - //Does the directory really exist, if not then make it - if(!LLFile::isdir(chatLogPath)) - { - //mkdir success is defined as zero - if(LLFile::mkdir(chatLogPath) != 0) - { - return false; - } - madeDirectory = true; - } - - std::string originalConversationLogDir = LLConversationLog::instance().getFileName(); - std::string targetConversationLogDir = gDirUtilp->add(chatLogPath, "conversation.log"); - //Try to move the conversation log - if(!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir)) - { - //Couldn't move the log and created a new directory so remove the new directory - if(madeDirectory) - { - LLFile::rmdir(chatLogPath); - } - return false; - } - - //Attempt to move transcripts - std::vector<std::string> listOfTranscripts; - std::vector<std::string> listOfFilesMoved; - - LLLogChat::getListOfTranscriptFiles(listOfTranscripts); - - if(!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(), - instantMessageLogPath, - listOfTranscripts, - listOfFilesMoved)) - { - //Couldn't move all the transcripts so restore those that moved back to their old location - LLLogChat::moveTranscripts(instantMessageLogPath, - gDirUtilp->getChatLogsDir(), - listOfFilesMoved); - - //Move the conversation log back - LLConversationLog::instance().moveLog(targetConversationLogDir, originalConversationLogDir); - - if(madeDirectory) - { - LLFile::rmdir(chatLogPath); - } - - return false; - } - - gDirUtilp->setChatLogsDir(instantMessageLogPath); - gDirUtilp->updatePerAccountChatLogsDir(); - - return true; + std::string instantMessageLogPath(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + std::string chatLogPath = gDirUtilp->add(instantMessageLogPath, gDirUtilp->getUserName()); + + bool madeDirectory = false; + + //Does the directory really exist, if not then make it + if(!LLFile::isdir(chatLogPath)) + { + //mkdir success is defined as zero + if(LLFile::mkdir(chatLogPath) != 0) + { + return false; + } + madeDirectory = true; + } + + std::string originalConversationLogDir = LLConversationLog::instance().getFileName(); + std::string targetConversationLogDir = gDirUtilp->add(chatLogPath, "conversation.log"); + //Try to move the conversation log + if(!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir)) + { + //Couldn't move the log and created a new directory so remove the new directory + if(madeDirectory) + { + LLFile::rmdir(chatLogPath); + } + return false; + } + + //Attempt to move transcripts + std::vector<std::string> listOfTranscripts; + std::vector<std::string> listOfFilesMoved; + + LLLogChat::getListOfTranscriptFiles(listOfTranscripts); + + if(!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(), + instantMessageLogPath, + listOfTranscripts, + listOfFilesMoved)) + { + //Couldn't move all the transcripts so restore those that moved back to their old location + LLLogChat::moveTranscripts(instantMessageLogPath, + gDirUtilp->getChatLogsDir(), + listOfFilesMoved); + + //Move the conversation log back + LLConversationLog::instance().moveLog(targetConversationLogDir, originalConversationLogDir); + + if(madeDirectory) + { + LLFile::rmdir(chatLogPath); + } + + return false; + } + + gDirUtilp->setChatLogsDir(instantMessageLogPath); + gDirUtilp->updatePerAccountChatLogsDir(); + + return true; } void LLFloaterPreference::setPersonalInfo(const std::string& visibility) { - mGotPersonalInfo = true; - mDirectoryVisibility = visibility; - - if (visibility == VISIBILITY_DEFAULT) - { - mOriginalHideOnlineStatus = false; - getChildView("online_visibility")->setEnabled(TRUE); - } - else if (visibility == VISIBILITY_HIDDEN) - { - mOriginalHideOnlineStatus = true; - getChildView("online_visibility")->setEnabled(TRUE); - } - else - { - mOriginalHideOnlineStatus = true; - } - - getChild<LLUICtrl>("online_searchresults")->setEnabled(TRUE); - getChildView("friends_online_notify_checkbox")->setEnabled(TRUE); - getChild<LLUICtrl>("online_visibility")->setValue(mOriginalHideOnlineStatus); - getChild<LLUICtrl>("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility); - - getChildView("favorites_on_login_check")->setEnabled(TRUE); - getChildView("log_path_button")->setEnabled(TRUE); - getChildView("chat_font_size")->setEnabled(TRUE); - getChildView("conversation_log_combo")->setEnabled(TRUE); - getChild<LLUICtrl>("voice_call_friends_only_check")->setEnabled(TRUE); - getChild<LLUICtrl>("voice_call_friends_only_check")->setValue(gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly")); + mGotPersonalInfo = true; + mDirectoryVisibility = visibility; + + if (visibility == VISIBILITY_DEFAULT) + { + mOriginalHideOnlineStatus = false; + getChildView("online_visibility")->setEnabled(TRUE); + } + else if (visibility == VISIBILITY_HIDDEN) + { + mOriginalHideOnlineStatus = true; + getChildView("online_visibility")->setEnabled(TRUE); + } + else + { + mOriginalHideOnlineStatus = true; + } + + getChild<LLUICtrl>("online_searchresults")->setEnabled(TRUE); + getChildView("friends_online_notify_checkbox")->setEnabled(TRUE); + getChild<LLUICtrl>("online_visibility")->setValue(mOriginalHideOnlineStatus); + getChild<LLUICtrl>("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility); + + getChildView("favorites_on_login_check")->setEnabled(TRUE); + getChildView("log_path_button")->setEnabled(TRUE); + getChildView("chat_font_size")->setEnabled(TRUE); + getChildView("conversation_log_combo")->setEnabled(TRUE); + getChild<LLUICtrl>("voice_call_friends_only_check")->setEnabled(TRUE); + getChild<LLUICtrl>("voice_call_friends_only_check")->setValue(gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly")); } void LLFloaterPreference::refreshUI() { - refresh(); + refresh(); } -void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) -{ - // Called when the IndirectMaxComplexity control changes - // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity - U32 indirect_value = slider->getValue().asInteger(); - U32 max_arc; - - if (INDIRECT_MAX_ARC_OFF == indirect_value) - { - // The 'off' position is when the slider is all the way to the right, - // which is a value of INDIRECT_MAX_ARC_OFF, - // so it is necessary to set max_arc to 0 disable muted avatars. - max_arc = 0; - } - else - { - // if this is changed, the inverse calculation in setIndirectMaxArc - // must be changed to match - max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT)))); - } - - gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); - setText(max_arc, value_label, short_val); +void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) +{ + // Called when the IndirectMaxComplexity control changes + // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity + U32 indirect_value = slider->getValue().asInteger(); + U32 max_arc; + + if (INDIRECT_MAX_ARC_OFF == indirect_value) + { + // The 'off' position is when the slider is all the way to the right, + // which is a value of INDIRECT_MAX_ARC_OFF, + // so it is necessary to set max_arc to 0 disable muted avatars. + max_arc = 0; + } + else + { + // if this is changed, the inverse calculation in setIndirectMaxArc + // must be changed to match + max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT)))); + } + + gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); + setText(max_arc, value_label, short_val); } void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool short_val) { - if (0 == value) - { - text_box->setText(LLTrans::getString("no_limit")); - } - else - { + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { std::string text_value = short_val ? llformat("%d", value / 1000) : llformat("%d", value); text_box->setText(text_value); - } + } } void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) @@ -1563,7 +1563,7 @@ void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_bo void LLFloaterPreference::updateMaxComplexity() { - // Called when the IndirectMaxComplexity control changes + // Called when the IndirectMaxComplexity control changes LLAvatarComplexityControls::updateMax( getChild<LLSliderCtrl>("IndirectMaxComplexity"), getChild<LLTextBox>("IndirectMaxComplexityText")); @@ -1616,16 +1616,16 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map void LLFloaterPreference::onChangeMaturity() { - U8 sim_access = gSavedSettings.getU32("PreferredMaturity"); + U8 sim_access = gSavedSettings.getU32("PreferredMaturity"); - getChild<LLIconCtrl>("rating_icon_general")->setVisible(sim_access == SIM_ACCESS_PG - || sim_access == SIM_ACCESS_MATURE - || sim_access == SIM_ACCESS_ADULT); + getChild<LLIconCtrl>("rating_icon_general")->setVisible(sim_access == SIM_ACCESS_PG + || sim_access == SIM_ACCESS_MATURE + || sim_access == SIM_ACCESS_ADULT); - getChild<LLIconCtrl>("rating_icon_moderate")->setVisible(sim_access == SIM_ACCESS_MATURE - || sim_access == SIM_ACCESS_ADULT); + getChild<LLIconCtrl>("rating_icon_moderate")->setVisible(sim_access == SIM_ACCESS_MATURE + || sim_access == SIM_ACCESS_ADULT); - getChild<LLIconCtrl>("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT); + getChild<LLIconCtrl>("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT); } std::string get_category_path(LLFolderType::EType cat_type) @@ -1678,23 +1678,23 @@ void LLFloaterPreference::onChangeAnimationFolder() // but the UI for this will still be enabled void LLFloaterPreference::onClickBlockList() { - LLFloaterSidePanelContainer::showPanel("people", "panel_people", - LLSD().with("people_panel_tab_name", "blocked_panel")); + LLFloaterSidePanelContainer::showPanel("people", "panel_people", + LLSD().with("people_panel_tab_name", "blocked_panel")); } void LLFloaterPreference::onClickProxySettings() { - LLFloaterReg::showInstance("prefs_proxy"); + LLFloaterReg::showInstance("prefs_proxy"); } void LLFloaterPreference::onClickTranslationSettings() { - LLFloaterReg::showInstance("prefs_translation"); + LLFloaterReg::showInstance("prefs_translation"); } void LLFloaterPreference::onClickAutoReplace() { - LLFloaterReg::showInstance("prefs_autoreplace"); + LLFloaterReg::showInstance("prefs_autoreplace"); } void LLFloaterPreference::onClickSpellChecker() @@ -1718,19 +1718,19 @@ void LLFloaterPreference::onClickAutoAdjustments() void LLFloaterPreference::onClickAdvanced() { - LLFloaterReg::showInstance("prefs_graphics_advanced"); + LLFloaterReg::showInstance("prefs_graphics_advanced"); - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); - for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - iter != tabcontainer->getChildList()->end(); ++iter) - { - LLView* view = *iter; - LLPanelPreferenceGraphics* panel = dynamic_cast<LLPanelPreferenceGraphics*>(view); - if (panel) - { - panel->resetDirtyChilds(); - } - } + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreferenceGraphics* panel = dynamic_cast<LLPanelPreferenceGraphics*>(view); + if (panel) + { + panel->resetDirtyChilds(); + } + } } void LLFloaterPreference::onClickActionChange() @@ -1756,7 +1756,7 @@ void LLFloaterPreference::onAtmosShaderChange() void LLFloaterPreference::onClickPermsDefault() { - LLFloaterReg::showInstance("perms_default"); + LLFloaterReg::showInstance("perms_default"); } void LLFloaterPreference::onClickRememberedUsernames() @@ -1766,29 +1766,29 @@ void LLFloaterPreference::onClickRememberedUsernames() void LLFloaterPreference::onDeleteTranscripts() { - LLSD args; - args["FOLDER"] = gDirUtilp->getUserName(); + LLSD args; + args["FOLDER"] = gDirUtilp->getUserName(); - LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", args, LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); + LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", args, LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); } void LLFloaterPreference::onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response) { - if (0 == LLNotificationsUtil::getSelectedOption(notification, response)) - { - LLLogChat::deleteTranscripts(); - updateDeleteTranscriptsButton(); - } + if (0 == LLNotificationsUtil::getSelectedOption(notification, response)) + { + LLLogChat::deleteTranscripts(); + updateDeleteTranscriptsButton(); + } } void LLFloaterPreference::onLogChatHistorySaved() { - LLButton * delete_transcripts_buttonp = getChild<LLButton>("delete_transcripts"); + LLButton * delete_transcripts_buttonp = getChild<LLButton>("delete_transcripts"); - if (!delete_transcripts_buttonp->getEnabled()) - { - delete_transcripts_buttonp->setEnabled(true); - } + if (!delete_transcripts_buttonp->getEnabled()) + { + delete_transcripts_buttonp->setEnabled(true); + } } void LLFloaterPreference::updateClickActionControls() @@ -1816,13 +1816,13 @@ void LLFloaterPreference::updateClickActionControls() KEY_NONE, MASK_NONE, single_clk_action == 1); - + panel->setKeyBind("walk_to", EMouseClickType::CLICK_DOUBLELEFT, KEY_NONE, MASK_NONE, double_clk_action == 1); - + panel->setKeyBind("teleport_to", EMouseClickType::CLICK_DOUBLELEFT, KEY_NONE, @@ -1867,8 +1867,8 @@ void LLFloaterPreference::updateClickActionViews() } } - getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk); - getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); + getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk); + getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); } void LLFloaterPreference::updateSearchableItems() @@ -1878,62 +1878,62 @@ void LLFloaterPreference::updateSearchableItems() void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param) { - LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); + LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); } void LLFloaterPreference::getUIColor(LLUICtrl* ctrl, const LLSD& param) { - LLColorSwatchCtrl* color_swatch = (LLColorSwatchCtrl*) ctrl; - color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString())); + LLColorSwatchCtrl* color_swatch = (LLColorSwatchCtrl*) ctrl; + color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString())); } void LLFloaterPreference::setCacheLocation(const LLStringExplicit& location) { - LLUICtrl* cache_location_editor = getChild<LLUICtrl>("cache_location"); - cache_location_editor->setValue(location); - cache_location_editor->setToolTip(location); + LLUICtrl* cache_location_editor = getChild<LLUICtrl>("cache_location"); + cache_location_editor->setValue(location); + cache_location_editor->setToolTip(location); } void LLFloaterPreference::selectPanel(const LLSD& name) { - LLTabContainer * tab_containerp = getChild<LLTabContainer>("pref core"); - LLPanel * panel = tab_containerp->getPanelByName(name); - if (NULL != panel) - { - tab_containerp->selectTabPanel(panel); - } + LLTabContainer * tab_containerp = getChild<LLTabContainer>("pref core"); + LLPanel * panel = tab_containerp->getPanelByName(name); + if (NULL != panel) + { + tab_containerp->selectTabPanel(panel); + } } void LLFloaterPreference::selectPrivacyPanel() { - selectPanel("im"); + selectPanel("im"); } void LLFloaterPreference::selectChatPanel() { - selectPanel("chat"); + selectPanel("chat"); } void LLFloaterPreference::changed() { - getChild<LLButton>("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0); + getChild<LLButton>("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0); - // set 'enable' property for 'Delete transcripts...' button - updateDeleteTranscriptsButton(); + // set 'enable' property for 'Delete transcripts...' button + updateDeleteTranscriptsButton(); } void LLFloaterPreference::saveGraphicsPreset(std::string& preset) { - mSavedGraphicsPreset = preset; + mSavedGraphicsPreset = preset; } //------------------------------Updater--------------------------------------- static bool handleBandwidthChanged(const LLSD& newvalue) { - gViewerThrottle.setMaxBandwidth((F32) newvalue.asReal()); - return true; + gViewerThrottle.setMaxBandwidth((F32) newvalue.asReal()); + return true; } class LLPanelPreference::Updater : public LLEventTimer @@ -1941,37 +1941,37 @@ class LLPanelPreference::Updater : public LLEventTimer public: - typedef boost::function<bool(const LLSD&)> callback_t; + typedef boost::function<bool(const LLSD&)> callback_t; - Updater(callback_t cb, F32 period) - :LLEventTimer(period), - mCallback(cb) - { - stop(); - } + Updater(callback_t cb, F32 period) + :LLEventTimer(period), + mCallback(cb) + { + stop(); + } - virtual ~Updater(){} + virtual ~Updater(){} - void update(const LLSD& new_value) - { - mNewValue = new_value; - start(); - } + void update(const LLSD& new_value) + { + mNewValue = new_value; + start(); + } protected: - bool tick() override - { - mCallback(mNewValue); - stop(); + bool tick() override + { + mCallback(mNewValue); + stop(); - return false; - } + return false; + } private: - LLSD mNewValue; - callback_t mCallback; + LLSD mNewValue; + callback_t mCallback; }; //---------------------------------------------------------------------------- static LLPanelInjector<LLPanelPreference> t_places("panel_preference"); @@ -1979,160 +1979,160 @@ LLPanelPreference::LLPanelPreference() : LLPanel(), mBandWidthUpdater(NULL) { - mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2)); - mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1)); - mCommitCallbackRegistrar.add("Pref.PrefDelete", boost::bind(&LLPanelPreference::deletePreset, this, _2)); - mCommitCallbackRegistrar.add("Pref.PrefSave", boost::bind(&LLPanelPreference::savePreset, this, _2)); - mCommitCallbackRegistrar.add("Pref.PrefLoad", boost::bind(&LLPanelPreference::loadPreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2)); + mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1)); + mCommitCallbackRegistrar.add("Pref.PrefDelete", boost::bind(&LLPanelPreference::deletePreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.PrefSave", boost::bind(&LLPanelPreference::savePreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.PrefLoad", boost::bind(&LLPanelPreference::loadPreset, this, _2)); } //virtual BOOL LLPanelPreference::postBuild() { - ////////////////////// PanelGeneral /////////////////// - if (hasChild("display_names_check", TRUE)) - { - BOOL use_people_api = gSavedSettings.getBOOL("UsePeopleAPI"); - LLCheckBoxCtrl* ctrl_display_name = getChild<LLCheckBoxCtrl>("display_names_check"); - ctrl_display_name->setEnabled(use_people_api); - if (!use_people_api) - { - ctrl_display_name->setValue(FALSE); - } - } - - ////////////////////// PanelVoice /////////////////// - if (hasChild("voice_unavailable", TRUE)) - { - BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice"); - getChildView("voice_unavailable")->setVisible( voice_disabled); - getChildView("enable_voice_check")->setVisible( !voice_disabled); - } - - //////////////////////PanelSkins /////////////////// - - if (hasChild("skin_selection", TRUE)) - { - LLFloaterPreference::refreshSkin(this); - - // if skin is set to a skin that no longer exists (silver) set back to default - if (getChild<LLRadioGroup>("skin_selection")->getSelectedIndex() < 0) - { - gSavedSettings.setString("SkinCurrent", "default"); - LLFloaterPreference::refreshSkin(this); - } - - } - - //////////////////////PanelPrivacy /////////////////// - if (hasChild("media_enabled", TRUE)) - { - bool media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); - - getChild<LLCheckBoxCtrl>("media_enabled")->set(media_enabled); - getChild<LLCheckBoxCtrl>("autoplay_enabled")->setEnabled(media_enabled); - } - if (hasChild("music_enabled", TRUE)) - { - getChild<LLCheckBoxCtrl>("music_enabled")->set(gSavedSettings.getBOOL("AudioStreamingMusic")); - } - if (hasChild("voice_call_friends_only_check", TRUE)) - { - getChild<LLCheckBoxCtrl>("voice_call_friends_only_check")->setCommitCallback(boost::bind(&showFriendsOnlyWarning, _1, _2)); - } - if (hasChild("allow_multiple_viewer_check", TRUE)) - { - getChild<LLCheckBoxCtrl>("allow_multiple_viewer_check")->setCommitCallback(boost::bind(&showMultipleViewersWarning, _1, _2)); - } - if (hasChild("favorites_on_login_check", TRUE)) - { - getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2)); - bool show_favorites_at_login = LLPanelLogin::getShowFavorites(); - getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login); - } - if (hasChild("mute_chb_label", TRUE)) - { - getChild<LLTextBox>("mute_chb_label")->setShowCursorHand(false); - getChild<LLTextBox>("mute_chb_label")->setSoundFlags(LLView::MOUSE_UP); - getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); - } - - //////////////////////PanelSetup /////////////////// - if (hasChild("max_bandwidth", TRUE)) - { - mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT); - gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2)); - } + ////////////////////// PanelGeneral /////////////////// + if (hasChild("display_names_check", TRUE)) + { + BOOL use_people_api = gSavedSettings.getBOOL("UsePeopleAPI"); + LLCheckBoxCtrl* ctrl_display_name = getChild<LLCheckBoxCtrl>("display_names_check"); + ctrl_display_name->setEnabled(use_people_api); + if (!use_people_api) + { + ctrl_display_name->setValue(FALSE); + } + } + + ////////////////////// PanelVoice /////////////////// + if (hasChild("voice_unavailable", TRUE)) + { + BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice"); + getChildView("voice_unavailable")->setVisible( voice_disabled); + getChildView("enable_voice_check")->setVisible( !voice_disabled); + } + + //////////////////////PanelSkins /////////////////// + + if (hasChild("skin_selection", TRUE)) + { + LLFloaterPreference::refreshSkin(this); + + // if skin is set to a skin that no longer exists (silver) set back to default + if (getChild<LLRadioGroup>("skin_selection")->getSelectedIndex() < 0) + { + gSavedSettings.setString("SkinCurrent", "default"); + LLFloaterPreference::refreshSkin(this); + } + + } + + //////////////////////PanelPrivacy /////////////////// + if (hasChild("media_enabled", TRUE)) + { + bool media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); + + getChild<LLCheckBoxCtrl>("media_enabled")->set(media_enabled); + getChild<LLCheckBoxCtrl>("autoplay_enabled")->setEnabled(media_enabled); + } + if (hasChild("music_enabled", TRUE)) + { + getChild<LLCheckBoxCtrl>("music_enabled")->set(gSavedSettings.getBOOL("AudioStreamingMusic")); + } + if (hasChild("voice_call_friends_only_check", TRUE)) + { + getChild<LLCheckBoxCtrl>("voice_call_friends_only_check")->setCommitCallback(boost::bind(&showFriendsOnlyWarning, _1, _2)); + } + if (hasChild("allow_multiple_viewer_check", TRUE)) + { + getChild<LLCheckBoxCtrl>("allow_multiple_viewer_check")->setCommitCallback(boost::bind(&showMultipleViewersWarning, _1, _2)); + } + if (hasChild("favorites_on_login_check", TRUE)) + { + getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2)); + bool show_favorites_at_login = LLPanelLogin::getShowFavorites(); + getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login); + } + if (hasChild("mute_chb_label", TRUE)) + { + getChild<LLTextBox>("mute_chb_label")->setShowCursorHand(false); + getChild<LLTextBox>("mute_chb_label")->setSoundFlags(LLView::MOUSE_UP); + getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); + } + + //////////////////////PanelSetup /////////////////// + if (hasChild("max_bandwidth", TRUE)) + { + mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT); + gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2)); + } #ifdef EXTERNAL_TOS - LLRadioGroup* ext_browser_settings = getChild<LLRadioGroup>("preferred_browser_behavior"); - if (ext_browser_settings) - { - // turn off ability to set external/internal browser - ext_browser_settings->setSelectedByValue(LLWeb::BROWSER_EXTERNAL_ONLY, true); - ext_browser_settings->setEnabled(false); - } + LLRadioGroup* ext_browser_settings = getChild<LLRadioGroup>("preferred_browser_behavior"); + if (ext_browser_settings) + { + // turn off ability to set external/internal browser + ext_browser_settings->setSelectedByValue(LLWeb::BROWSER_EXTERNAL_ONLY, true); + ext_browser_settings->setEnabled(false); + } #endif - apply(); - return true; + apply(); + return true; } LLPanelPreference::~LLPanelPreference() { - if (mBandWidthUpdater) - { - delete mBandWidthUpdater; - } + if (mBandWidthUpdater) + { + delete mBandWidthUpdater; + } } void LLPanelPreference::apply() { - // no-op + // no-op } void LLPanelPreference::saveSettings() { - LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); - - // Save the value of all controls in the hierarchy - mSavedValues.clear(); - std::list<LLView*> view_stack; - view_stack.push_back(this); - if (advanced) - { - view_stack.push_back(advanced); - } - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLColorSwatchCtrl* color_swatch = dynamic_cast<LLColorSwatchCtrl *>(curview); - if (color_swatch) - { - mSavedColors[color_swatch->getName()] = color_swatch->get(); - } - else - { - LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); - if (ctrl) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - mSavedValues[control] = control->getValue(); - } - } - } - - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } + LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); + + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list<LLView*> view_stack; + view_stack.push_back(this); + if (advanced) + { + view_stack.push_back(advanced); + } + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLColorSwatchCtrl* color_swatch = dynamic_cast<LLColorSwatchCtrl *>(curview); + if (color_swatch) + { + mSavedColors[color_swatch->getName()] = color_swatch->get(); + } + else + { + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + mSavedValues[control] = control->getValue(); + } + } + } + + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } if (LLStartUp::getStartupState() == STATE_STARTED) { @@ -2154,104 +2154,104 @@ void LLPanelPreference::showMultipleViewersWarning(LLUICtrl* checkbox, const LLS void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& value) { - if (checkbox) - { - gSavedPerAccountSettings.setBOOL("VoiceCallsFriendsOnly", checkbox->getValue().asBoolean()); - if (checkbox->getValue()) - { - LLNotificationsUtil::add("FriendsAndGroupsOnly"); - } - } + if (checkbox) + { + gSavedPerAccountSettings.setBOOL("VoiceCallsFriendsOnly", checkbox->getValue().asBoolean()); + if (checkbox->getValue()) + { + LLNotificationsUtil::add("FriendsAndGroupsOnly"); + } + } } void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value) { - if (checkbox) - { - LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean()); - if(checkbox->getValue()) - { - LLNotificationsUtil::add("FavoritesOnLogin"); - } - } + if (checkbox) + { + LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean()); + if(checkbox->getValue()) + { + LLNotificationsUtil::add("FavoritesOnLogin"); + } + } } void LLPanelPreference::toggleMuteWhenMinimized() { - std::string mute("MuteWhenMinimized"); - gSavedSettings.setBOOL(mute, !gSavedSettings.getBOOL(mute)); - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->getChild<LLCheckBoxCtrl>("mute_when_minimized")->setBtnFocus(); - } + std::string mute("MuteWhenMinimized"); + gSavedSettings.setBOOL(mute, !gSavedSettings.getBOOL(mute)); + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->getChild<LLCheckBoxCtrl>("mute_when_minimized")->setBtnFocus(); + } } void LLPanelPreference::cancel() { - for (control_values_map_t::iterator iter = mSavedValues.begin(); - iter != mSavedValues.end(); ++iter) - { - LLControlVariable* control = iter->first; - LLSD ctrl_value = iter->second; + for (control_values_map_t::iterator iter = mSavedValues.begin(); + iter != mSavedValues.end(); ++iter) + { + LLControlVariable* control = iter->first; + LLSD ctrl_value = iter->second; - if((control->getName() == "InstantMessageLogPath") && (ctrl_value.asString() == "")) - { - continue; - } + if((control->getName() == "InstantMessageLogPath") && (ctrl_value.asString() == "")) + { + continue; + } - control->set(ctrl_value); - } + control->set(ctrl_value); + } - for (string_color_map_t::iterator iter = mSavedColors.begin(); - iter != mSavedColors.end(); ++iter) - { - LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>(iter->first); - if (color_swatch) - { - color_swatch->set(iter->second); - color_swatch->onCommit(); - } - } + for (string_color_map_t::iterator iter = mSavedColors.begin(); + iter != mSavedColors.end(); ++iter) + { + LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>(iter->first); + if (color_swatch) + { + color_swatch->set(iter->second); + color_swatch->onCommit(); + } + } } void LLPanelPreference::setControlFalse(const LLSD& user_data) { - std::string control_name = user_data.asString(); - LLControlVariable* control = findControl(control_name); - - if (control) - control->set(LLSD(FALSE)); + std::string control_name = user_data.asString(); + LLControlVariable* control = findControl(control_name); + + if (control) + control->set(LLSD(FALSE)); } void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) { - std::string name = ctrl->getName(); + std::string name = ctrl->getName(); - // Disable "Allow Media to auto play" only when both - // "Streaming Music" and "Media" are unchecked. STORM-513. - if ((name == "enable_music") || (name == "enable_media")) - { - bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get(); - bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); + // Disable "Allow Media to auto play" only when both + // "Streaming Music" and "Media" are unchecked. STORM-513. + if ((name == "enable_music") || (name == "enable_media")) + { + bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get(); + bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); - getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); - } + getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); + } } void LLPanelPreference::deletePreset(const LLSD& user_data) { - LLFloaterReg::showInstance("delete_pref_preset", user_data.asString()); + LLFloaterReg::showInstance("delete_pref_preset", user_data.asString()); } void LLPanelPreference::savePreset(const LLSD& user_data) { - LLFloaterReg::showInstance("save_pref_preset", user_data.asString()); + LLFloaterReg::showInstance("save_pref_preset", user_data.asString()); } void LLPanelPreference::loadPreset(const LLSD& user_data) { - LLFloaterReg::showInstance("load_pref_preset", user_data.asString()); + LLFloaterReg::showInstance("load_pref_preset", user_data.asString()); } void LLPanelPreference::setHardwareDefaults() @@ -2261,38 +2261,38 @@ void LLPanelPreference::setHardwareDefaults() class LLPanelPreferencePrivacy : public LLPanelPreference { public: - LLPanelPreferencePrivacy() - { - mAccountIndependentSettings.push_back("AutoDisengageMic"); - } - - /*virtual*/ void saveSettings() - { - LLPanelPreference::saveSettings(); - - // Don't save (=erase from the saved values map) per-account privacy settings - // if we're not logged in, otherwise they will be reset to defaults on log off. - if (LLStartUp::getStartupState() != STATE_STARTED) - { - // Erase only common settings, assuming there are no color settings on Privacy page. - for (control_values_map_t::iterator it = mSavedValues.begin(); it != mSavedValues.end(); ) - { - const std::string setting = it->first->getName(); - if (find(mAccountIndependentSettings.begin(), - mAccountIndependentSettings.end(), setting) == mAccountIndependentSettings.end()) - { - mSavedValues.erase(it++); - } - else - { - ++it; - } - } - } - } + LLPanelPreferencePrivacy() + { + mAccountIndependentSettings.push_back("AutoDisengageMic"); + } + + /*virtual*/ void saveSettings() + { + LLPanelPreference::saveSettings(); + + // Don't save (=erase from the saved values map) per-account privacy settings + // if we're not logged in, otherwise they will be reset to defaults on log off. + if (LLStartUp::getStartupState() != STATE_STARTED) + { + // Erase only common settings, assuming there are no color settings on Privacy page. + for (control_values_map_t::iterator it = mSavedValues.begin(); it != mSavedValues.end(); ) + { + const std::string setting = it->first->getName(); + if (find(mAccountIndependentSettings.begin(), + mAccountIndependentSettings.end(), setting) == mAccountIndependentSettings.end()) + { + mSavedValues.erase(it++); + } + else + { + ++it; + } + } + } + } private: - std::list<std::string> mAccountIndependentSettings; + std::list<std::string> mAccountIndependentSettings; }; static LLPanelInjector<LLPanelPreferenceGraphics> t_pref_graph("panel_preference_graphics"); @@ -2300,170 +2300,170 @@ static LLPanelInjector<LLPanelPreferencePrivacy> t_pref_privacy("panel_preferenc BOOL LLPanelPreferenceGraphics::postBuild() { - LLFloaterReg::showInstance("prefs_graphics_advanced"); - LLFloaterReg::hideInstance("prefs_graphics_advanced"); + LLFloaterReg::showInstance("prefs_graphics_advanced"); + LLFloaterReg::hideInstance("prefs_graphics_advanced"); - resetDirtyChilds(); - setPresetText(); + resetDirtyChilds(); + setPresetText(); - LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); + LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); presetsMgr->setPresetListChangeCallback(boost::bind(&LLPanelPreferenceGraphics::onPresetsListChange, this)); presetsMgr->createMissingDefault(PRESETS_GRAPHIC); // a no-op after the first time, but that's ok - - return LLPanelPreference::postBuild(); + + return LLPanelPreference::postBuild(); } void LLPanelPreferenceGraphics::draw() { - setPresetText(); - LLPanelPreference::draw(); + setPresetText(); + LLPanelPreference::draw(); } void LLPanelPreferenceGraphics::onPresetsListChange() { - resetDirtyChilds(); - setPresetText(); + resetDirtyChilds(); + setPresetText(); - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance && !gSavedSettings.getString("PresetGraphicActive").empty()) - { - instance->saveSettings(); //make cancel work correctly after changing the preset - } + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance && !gSavedSettings.getString("PresetGraphicActive").empty()) + { + instance->saveSettings(); //make cancel work correctly after changing the preset + } } void LLPanelPreferenceGraphics::setPresetText() { - LLTextBox* preset_text = getChild<LLTextBox>("preset_text"); + LLTextBox* preset_text = getChild<LLTextBox>("preset_text"); - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - if (!preset_graphic_active.empty() && preset_graphic_active != preset_text->getText()) - { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->saveGraphicsPreset(preset_graphic_active); - } - } + if (!preset_graphic_active.empty() && preset_graphic_active != preset_text->getText()) + { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->saveGraphicsPreset(preset_graphic_active); + } + } if (hasDirtyChilds() && !preset_graphic_active.empty()) - { - gSavedSettings.setString("PresetGraphicActive", ""); - preset_graphic_active.clear(); - // This doesn't seem to cause an infinite recursion. This trigger is needed to cause the pulldown - // panel to update. - LLPresetsManager::getInstance()->triggerChangeSignal(); - } - - if (!preset_graphic_active.empty()) - { - if (preset_graphic_active == PRESETS_DEFAULT) - { - preset_graphic_active = LLTrans::getString(PRESETS_DEFAULT); - } - preset_text->setText(preset_graphic_active); - } - else - { - preset_text->setText(LLTrans::getString("none_paren_cap")); - } - - preset_text->resetDirty(); + { + gSavedSettings.setString("PresetGraphicActive", ""); + preset_graphic_active.clear(); + // This doesn't seem to cause an infinite recursion. This trigger is needed to cause the pulldown + // panel to update. + LLPresetsManager::getInstance()->triggerChangeSignal(); + } + + if (!preset_graphic_active.empty()) + { + if (preset_graphic_active == PRESETS_DEFAULT) + { + preset_graphic_active = LLTrans::getString(PRESETS_DEFAULT); + } + preset_text->setText(preset_graphic_active); + } + else + { + preset_text->setText(LLTrans::getString("none_paren_cap")); + } + + preset_text->resetDirty(); } bool LLPanelPreferenceGraphics::hasDirtyChilds() { - LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); - std::list<LLView*> view_stack; - view_stack.push_back(this); - if (advanced) - { - view_stack.push_back(advanced); - } - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); - if (ctrl) - { - if (ctrl->isDirty()) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - std::string control_name = control->getName(); - if (!control_name.empty()) - { - return true; - } - } - } - } - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } - - return false; + LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); + std::list<LLView*> view_stack; + view_stack.push_back(this); + if (advanced) + { + view_stack.push_back(advanced); + } + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); + if (ctrl) + { + if (ctrl->isDirty()) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + std::string control_name = control->getName(); + if (!control_name.empty()) + { + return true; + } + } + } + } + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } + + return false; } void LLPanelPreferenceGraphics::resetDirtyChilds() { - LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); - std::list<LLView*> view_stack; - view_stack.push_back(this); - if (advanced) - { - view_stack.push_back(advanced); - } - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); - if (ctrl) - { - ctrl->resetDirty(); - } - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } + LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"); + std::list<LLView*> view_stack; + view_stack.push_back(this); + if (advanced) + { + view_stack.push_back(advanced); + } + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); + if (ctrl) + { + ctrl->resetDirty(); + } + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } } void LLPanelPreferenceGraphics::cancel() { - LLPanelPreference::cancel(); + LLPanelPreference::cancel(); } void LLPanelPreferenceGraphics::saveSettings() { - resetDirtyChilds(); - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - if (preset_graphic_active.empty()) - { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - //don't restore previous preset after closing Preferences - instance->saveGraphicsPreset(preset_graphic_active); - } - } - LLPanelPreference::saveSettings(); + resetDirtyChilds(); + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + if (preset_graphic_active.empty()) + { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + //don't restore previous preset after closing Preferences + instance->saveGraphicsPreset(preset_graphic_active); + } + } + LLPanelPreference::saveSettings(); } void LLPanelPreferenceGraphics::setHardwareDefaults() { - resetDirtyChilds(); + resetDirtyChilds(); } //------------------------LLPanelPreferenceControls-------------------------------- @@ -3033,7 +3033,7 @@ void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes) { return; } - + if (mEditingColumn > 0) { if (all_modes) @@ -3075,12 +3075,12 @@ void LLPanelPreferenceControls::onCancelKeyBind() } LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) - : LLFloater(key), - mSocksSettingsDirty(false) + : LLFloater(key), + mSocksSettingsDirty(false) { - mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); - mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); - mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); + mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); + mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); + mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); } LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() @@ -3089,192 +3089,192 @@ LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() BOOL LLFloaterPreferenceProxy::postBuild() { - LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); - if (!socksAuth) - { - return FALSE; - } - if (socksAuth->getSelectedValue().asString() == "None") - { - getChild<LLLineEditor>("socks5_username")->setEnabled(false); - getChild<LLLineEditor>("socks5_password")->setEnabled(false); - } - else - { - // Populate the SOCKS 5 credential fields with protected values. - LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); - getChild<LLLineEditor>("socks5_username")->setValue(socks_cred->getIdentifier()["username"].asString()); - getChild<LLLineEditor>("socks5_password")->setValue(socks_cred->getAuthenticator()["creds"].asString()); - } - - return TRUE; + LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); + if (!socksAuth) + { + return FALSE; + } + if (socksAuth->getSelectedValue().asString() == "None") + { + getChild<LLLineEditor>("socks5_username")->setEnabled(false); + getChild<LLLineEditor>("socks5_password")->setEnabled(false); + } + else + { + // Populate the SOCKS 5 credential fields with protected values. + LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + getChild<LLLineEditor>("socks5_username")->setValue(socks_cred->getIdentifier()["username"].asString()); + getChild<LLLineEditor>("socks5_password")->setValue(socks_cred->getAuthenticator()["creds"].asString()); + } + + return TRUE; } void LLFloaterPreferenceProxy::onOpen(const LLSD& key) { - saveSettings(); + saveSettings(); } void LLFloaterPreferenceProxy::onClose(bool app_quitting) { - if(app_quitting) - { - cancel(); - } + if(app_quitting) + { + cancel(); + } - if (mSocksSettingsDirty) - { + if (mSocksSettingsDirty) + { - // If the user plays with the Socks proxy settings after login, it's only fair we let them know - // it will not be updated until next restart. - if (LLStartUp::getStartupState()>STATE_LOGIN_WAIT) - { - LLNotifications::instance().add("ChangeProxySettings", LLSD(), LLSD()); - mSocksSettingsDirty = false; // we have notified the user now be quiet again - } - } + // If the user plays with the Socks proxy settings after login, it's only fair we let them know + // it will not be updated until next restart. + if (LLStartUp::getStartupState()>STATE_LOGIN_WAIT) + { + LLNotifications::instance().add("ChangeProxySettings", LLSD(), LLSD()); + mSocksSettingsDirty = false; // we have notified the user now be quiet again + } + } } void LLFloaterPreferenceProxy::saveSettings() { - // Save the value of all controls in the hierarchy - mSavedValues.clear(); - std::list<LLView*> view_stack; - view_stack.push_back(this); - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); - if (ctrl) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - mSavedValues[control] = control->getValue(); - } - } - - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list<LLView*> view_stack; + view_stack.push_back(this); + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + mSavedValues[control] = control->getValue(); + } + } + + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } } void LLFloaterPreferenceProxy::onBtnOk() { - // commit any outstanding text entry - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - } - - // Save SOCKS proxy credentials securely if password auth is enabled - LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); - if (socksAuth->getSelectedValue().asString() == "UserPass") - { - LLSD socks_id = LLSD::emptyMap(); - socks_id["type"] = "SOCKS5"; - socks_id["username"] = getChild<LLLineEditor>("socks5_username")->getValue().asString(); - - LLSD socks_authenticator = LLSD::emptyMap(); - socks_authenticator["type"] = "SOCKS5"; - socks_authenticator["creds"] = getChild<LLLineEditor>("socks5_password")->getValue().asString(); - - // Using "SOCKS5" as the "grid" argument since the same proxy - // settings will be used for all grids and because there is no - // way to specify the type of credential. - LLPointer<LLCredential> socks_cred = gSecAPIHandler->createCredential("SOCKS5", socks_id, socks_authenticator); - gSecAPIHandler->saveCredential(socks_cred, true); - } - else - { - // Clear SOCKS5 credentials since they are no longer needed. - LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5"); - gSecAPIHandler->deleteCredential(socks_cred); - } - - closeFloater(false); + // commit any outstanding text entry + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + } + + // Save SOCKS proxy credentials securely if password auth is enabled + LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); + if (socksAuth->getSelectedValue().asString() == "UserPass") + { + LLSD socks_id = LLSD::emptyMap(); + socks_id["type"] = "SOCKS5"; + socks_id["username"] = getChild<LLLineEditor>("socks5_username")->getValue().asString(); + + LLSD socks_authenticator = LLSD::emptyMap(); + socks_authenticator["type"] = "SOCKS5"; + socks_authenticator["creds"] = getChild<LLLineEditor>("socks5_password")->getValue().asString(); + + // Using "SOCKS5" as the "grid" argument since the same proxy + // settings will be used for all grids and because there is no + // way to specify the type of credential. + LLPointer<LLCredential> socks_cred = gSecAPIHandler->createCredential("SOCKS5", socks_id, socks_authenticator); + gSecAPIHandler->saveCredential(socks_cred, true); + } + else + { + // Clear SOCKS5 credentials since they are no longer needed. + LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + } + + closeFloater(false); } void LLFloaterPreferenceProxy::onBtnCancel() { - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - refresh(); - } + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + refresh(); + } - cancel(); + cancel(); } void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting) { - cancel(); + cancel(); } void LLFloaterPreferenceProxy::cancel() { - for (control_values_map_t::iterator iter = mSavedValues.begin(); - iter != mSavedValues.end(); ++iter) - { - LLControlVariable* control = iter->first; - LLSD ctrl_value = iter->second; - control->set(ctrl_value); - } - mSocksSettingsDirty = false; - closeFloater(); + for (control_values_map_t::iterator iter = mSavedValues.begin(); + iter != mSavedValues.end(); ++iter) + { + LLControlVariable* control = iter->first; + LLSD ctrl_value = iter->second; + control->set(ctrl_value); + } + mSocksSettingsDirty = false; + closeFloater(); } -void LLFloaterPreferenceProxy::onChangeSocksSettings() +void LLFloaterPreferenceProxy::onChangeSocksSettings() { - mSocksSettingsDirty = true; + mSocksSettingsDirty = true; - LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); - if (socksAuth->getSelectedValue().asString() == "None") - { - getChild<LLLineEditor>("socks5_username")->setEnabled(false); - getChild<LLLineEditor>("socks5_password")->setEnabled(false); - } - else - { - getChild<LLLineEditor>("socks5_username")->setEnabled(true); - getChild<LLLineEditor>("socks5_password")->setEnabled(true); - } + LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type"); + if (socksAuth->getSelectedValue().asString() == "None") + { + getChild<LLLineEditor>("socks5_username")->setEnabled(false); + getChild<LLLineEditor>("socks5_password")->setEnabled(false); + } + else + { + getChild<LLLineEditor>("socks5_username")->setEnabled(true); + getChild<LLLineEditor>("socks5_password")->setEnabled(true); + } - // Check for invalid states for the other HTTP proxy radio - LLRadioGroup* otherHttpProxy = getChild<LLRadioGroup>("other_http_proxy_type"); - if ((otherHttpProxy->getSelectedValue().asString() == "Socks" && - getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get() == FALSE )||( - otherHttpProxy->getSelectedValue().asString() == "Web" && - getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get() == FALSE ) ) - { - otherHttpProxy->selectFirstItem(); - } + // Check for invalid states for the other HTTP proxy radio + LLRadioGroup* otherHttpProxy = getChild<LLRadioGroup>("other_http_proxy_type"); + if ((otherHttpProxy->getSelectedValue().asString() == "Socks" && + getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get() == FALSE )||( + otherHttpProxy->getSelectedValue().asString() == "Web" && + getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get() == FALSE ) ) + { + otherHttpProxy->selectFirstItem(); + } } void LLFloaterPreference::onUpdateFilterTerm(bool force) { - LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() ); - LLWStringUtil::toLower( seachValue ); + LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() ); + LLWStringUtil::toLower( seachValue ); - if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force)) - return; + if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force)) + return; if (mSearchDataDirty) { @@ -3282,17 +3282,17 @@ void LLFloaterPreference::onUpdateFilterTerm(bool force) collectSearchableItems(); } - mSearchData->mLastFilter = seachValue; + mSearchData->mLastFilter = seachValue; - if( !mSearchData->mRootTab ) - return; + if( !mSearchData->mRootTab ) + return; - mSearchData->mRootTab->hightlightAndHide( seachValue ); + mSearchData->mRootTab->hightlightAndHide( seachValue ); filterIgnorableNotifications(); - LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); - if( pRoot ) - pRoot->selectFirstTab(); + LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); + if( pRoot ) + pRoot->selectFirstTab(); } void LLFloaterPreference::filterIgnorableNotifications() @@ -3308,91 +3308,91 @@ void LLFloaterPreference::filterIgnorableNotifications() void collectChildren( LLView const *aView, ll::prefs::PanelDataPtr aParentPanel, ll::prefs::TabContainerDataPtr aParentTabContainer ) { - if( !aView ) - return; - - llassert_always( aParentPanel || aParentTabContainer ); - - LLView::child_list_const_iter_t itr = aView->beginChild(); - LLView::child_list_const_iter_t itrEnd = aView->endChild(); - - while( itr != itrEnd ) - { - LLView *pView = *itr; - ll::prefs::PanelDataPtr pCurPanelData = aParentPanel; - ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer; - if( !pView ) - continue; - LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView ); - LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView ); - ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView ); - - if( pTabContainer ) - { - pCurPanelData.reset(); - - pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); - pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer ); - pCurTabContainer->mLabel = pTabContainer->getLabel(); - pCurTabContainer->mPanel = 0; - - if( aParentPanel ) - aParentPanel->mChildPanel.push_back( pCurTabContainer ); - if( aParentTabContainer ) - aParentTabContainer->mChildPanel.push_back( pCurTabContainer ); - } - else if( pPanel ) - { - pCurTabContainer.reset(); - - pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData ); - pCurPanelData->mPanel = pPanel; - pCurPanelData->mLabel = pPanel->getLabel(); - - llassert_always( aParentPanel || aParentTabContainer ); - - if( aParentTabContainer ) - aParentTabContainer->mChildPanel.push_back( pCurPanelData ); - else if( aParentPanel ) - aParentPanel->mChildPanel.push_back( pCurPanelData ); - } - else if( pSCtrl && pSCtrl->getSearchText().size() ) - { - ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() ); - item->mView = pView; - item->mCtrl = pSCtrl; - - item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() ); - LLWStringUtil::toLower( item->mLabel ); - - llassert_always( aParentPanel || aParentTabContainer ); - - if( aParentPanel ) - aParentPanel->mChildren.push_back( item ); - if( aParentTabContainer ) - aParentTabContainer->mChildren.push_back( item ); - } - collectChildren( pView, pCurPanelData, pCurTabContainer ); - ++itr; - } + if( !aView ) + return; + + llassert_always( aParentPanel || aParentTabContainer ); + + LLView::child_list_const_iter_t itr = aView->beginChild(); + LLView::child_list_const_iter_t itrEnd = aView->endChild(); + + while( itr != itrEnd ) + { + LLView *pView = *itr; + ll::prefs::PanelDataPtr pCurPanelData = aParentPanel; + ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer; + if( !pView ) + continue; + LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView ); + LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView ); + ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView ); + + if( pTabContainer ) + { + pCurPanelData.reset(); + + pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); + pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer ); + pCurTabContainer->mLabel = pTabContainer->getLabel(); + pCurTabContainer->mPanel = 0; + + if( aParentPanel ) + aParentPanel->mChildPanel.push_back( pCurTabContainer ); + if( aParentTabContainer ) + aParentTabContainer->mChildPanel.push_back( pCurTabContainer ); + } + else if( pPanel ) + { + pCurTabContainer.reset(); + + pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData ); + pCurPanelData->mPanel = pPanel; + pCurPanelData->mLabel = pPanel->getLabel(); + + llassert_always( aParentPanel || aParentTabContainer ); + + if( aParentTabContainer ) + aParentTabContainer->mChildPanel.push_back( pCurPanelData ); + else if( aParentPanel ) + aParentPanel->mChildPanel.push_back( pCurPanelData ); + } + else if( pSCtrl && pSCtrl->getSearchText().size() ) + { + ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() ); + item->mView = pView; + item->mCtrl = pSCtrl; + + item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() ); + LLWStringUtil::toLower( item->mLabel ); + + llassert_always( aParentPanel || aParentTabContainer ); + + if( aParentPanel ) + aParentPanel->mChildren.push_back( item ); + if( aParentTabContainer ) + aParentTabContainer->mChildren.push_back( item ); + } + collectChildren( pView, pCurPanelData, pCurTabContainer ); + ++itr; + } } void LLFloaterPreference::collectSearchableItems() { - mSearchData.reset( nullptr ); - LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); - if( mFilterEdit && pRoot ) - { - mSearchData.reset(new ll::prefs::SearchData() ); + mSearchData.reset( nullptr ); + LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); + if( mFilterEdit && pRoot ) + { + mSearchData.reset(new ll::prefs::SearchData() ); - ll::prefs::TabContainerDataPtr pRootTabcontainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); - pRootTabcontainer->mTabContainer = pRoot; - pRootTabcontainer->mLabel = pRoot->getLabel(); - mSearchData->mRootTab = pRootTabcontainer; + ll::prefs::TabContainerDataPtr pRootTabcontainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); + pRootTabcontainer->mTabContainer = pRoot; + pRootTabcontainer->mLabel = pRoot->getLabel(); + mSearchData->mRootTab = pRootTabcontainer; - collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); - } - mSearchDataDirty = false; + collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); + } + mSearchDataDirty = false; } void LLFloaterPreference::saveIgnoredNotifications() diff --git a/indra/newview/llfloaterregionrestarting.cpp b/indra/newview/llfloaterregionrestarting.cpp index 6817cce5f6..d37a2912a0 100644 --- a/indra/newview/llfloaterregionrestarting.cpp +++ b/indra/newview/llfloaterregionrestarting.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterregionrestarting.cpp * @brief Shows countdown timer during region restart * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,139 +38,139 @@ static S32 sSeconds; static U32 sShakeState; LLFloaterRegionRestarting::LLFloaterRegionRestarting(const LLSD& key) : - LLFloater(key), - LLEventTimer(1) + LLFloater(key), + LLEventTimer(1) { - mName = (std::string)key["NAME"]; - sSeconds = (LLSD::Integer)key["SECONDS"]; + mName = (std::string)key["NAME"]; + sSeconds = (LLSD::Integer)key["SECONDS"]; } LLFloaterRegionRestarting::~LLFloaterRegionRestarting() { - mRegionChangedConnection.disconnect(); + mRegionChangedConnection.disconnect(); } BOOL LLFloaterRegionRestarting::postBuild() { - mRegionChangedConnection = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionRestarting::regionChange, this)); + mRegionChangedConnection = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionRestarting::regionChange, this)); - LLStringUtil::format_map_t args; - std::string text; + LLStringUtil::format_map_t args; + std::string text; - args["[NAME]"] = mName; - text = getString("RegionName", args); - LLTextBox* textbox = getChild<LLTextBox>("region_name"); - textbox->setValue(text); + args["[NAME]"] = mName; + text = getString("RegionName", args); + LLTextBox* textbox = getChild<LLTextBox>("region_name"); + textbox->setValue(text); - sShakeState = SHAKE_START; + sShakeState = SHAKE_START; - refresh(); + refresh(); - return TRUE; + return TRUE; } void LLFloaterRegionRestarting::regionChange() { - close(); + close(); } bool LLFloaterRegionRestarting::tick() { - refresh(); + refresh(); - return false; + return false; } void LLFloaterRegionRestarting::refresh() { - LLStringUtil::format_map_t args; - std::string text; + LLStringUtil::format_map_t args; + std::string text; - args["[SECONDS]"] = llformat("%d", sSeconds); - getChild<LLTextBox>("restart_seconds")->setValue(getString("RestartSeconds", args)); + args["[SECONDS]"] = llformat("%d", sSeconds); + getChild<LLTextBox>("restart_seconds")->setValue(getString("RestartSeconds", args)); - sSeconds = sSeconds - 1; - if(sSeconds < 0.0) - { - sSeconds = 0; - } + sSeconds = sSeconds - 1; + if(sSeconds < 0.0) + { + sSeconds = 0; + } } void LLFloaterRegionRestarting::draw() { - LLFloater::draw(); - - const F32 SHAKE_INTERVAL = 0.025; - const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this - const F32 SHAKE_INITIAL_MAGNITUDE = 1.5; - const F32 SHAKE_HORIZONTAL_BIAS = 0.25; - F32 time_shaking; - - if(SHAKE_START == sShakeState) - { - mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); - sShakeState = SHAKE_LEFT; - mShakeIterations = 0; - mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE; - } - - if(SHAKE_DONE != sShakeState && mShakeTimer.hasExpired()) - { - gAgentCamera.unlockView(); - - switch(sShakeState) - { - case SHAKE_LEFT: - gAgentCamera.setPanLeftKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); - sShakeState = SHAKE_UP; - break; - - case SHAKE_UP: - gAgentCamera.setPanUpKey(mShakeMagnitude); - sShakeState = SHAKE_RIGHT; - break; - - case SHAKE_RIGHT: - gAgentCamera.setPanRightKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); - sShakeState = SHAKE_DOWN; - break; - - case SHAKE_DOWN: - gAgentCamera.setPanDownKey(mShakeMagnitude); - mShakeIterations++; - time_shaking = SHAKE_INTERVAL * (mShakeIterations * 4 /* left, up, right, down */); - if(SHAKE_TOTAL_DURATION <= time_shaking) - { - sShakeState = SHAKE_DONE; - mShakeMagnitude = 0.0; - } - else - { - sShakeState = SHAKE_LEFT; - F32 percent_done_shaking = (SHAKE_TOTAL_DURATION - time_shaking) / SHAKE_TOTAL_DURATION; - mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE * (percent_done_shaking * percent_done_shaking); // exponential decay - } - break; - - default: - break; - } - mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); - } + LLFloater::draw(); + + const F32 SHAKE_INTERVAL = 0.025; + const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this + const F32 SHAKE_INITIAL_MAGNITUDE = 1.5; + const F32 SHAKE_HORIZONTAL_BIAS = 0.25; + F32 time_shaking; + + if(SHAKE_START == sShakeState) + { + mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); + sShakeState = SHAKE_LEFT; + mShakeIterations = 0; + mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE; + } + + if(SHAKE_DONE != sShakeState && mShakeTimer.hasExpired()) + { + gAgentCamera.unlockView(); + + switch(sShakeState) + { + case SHAKE_LEFT: + gAgentCamera.setPanLeftKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); + sShakeState = SHAKE_UP; + break; + + case SHAKE_UP: + gAgentCamera.setPanUpKey(mShakeMagnitude); + sShakeState = SHAKE_RIGHT; + break; + + case SHAKE_RIGHT: + gAgentCamera.setPanRightKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); + sShakeState = SHAKE_DOWN; + break; + + case SHAKE_DOWN: + gAgentCamera.setPanDownKey(mShakeMagnitude); + mShakeIterations++; + time_shaking = SHAKE_INTERVAL * (mShakeIterations * 4 /* left, up, right, down */); + if(SHAKE_TOTAL_DURATION <= time_shaking) + { + sShakeState = SHAKE_DONE; + mShakeMagnitude = 0.0; + } + else + { + sShakeState = SHAKE_LEFT; + F32 percent_done_shaking = (SHAKE_TOTAL_DURATION - time_shaking) / SHAKE_TOTAL_DURATION; + mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE * (percent_done_shaking * percent_done_shaking); // exponential decay + } + break; + + default: + break; + } + mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); + } } void LLFloaterRegionRestarting::close() { - LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance<LLFloaterRegionRestarting>("region_restarting"); + LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance<LLFloaterRegionRestarting>("region_restarting"); - if (floaterp) - { - floaterp->closeFloater(); - } + if (floaterp) + { + floaterp->closeFloater(); + } } void LLFloaterRegionRestarting::updateTime(S32 time) { - sSeconds = time; - sShakeState = SHAKE_START; + sSeconds = time; + sShakeState = SHAKE_START; } diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h index 6d3639c40c..52f067fa94 100644 --- a/indra/newview/llfloaterregionrestarting.h +++ b/indra/newview/llfloaterregionrestarting.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterregionrestarting.h * @brief Shows countdown timer during region restart * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,37 +33,37 @@ class LLFloaterRegionRestarting : public LLFloater, public LLEventTimer { - friend class LLFloaterReg; + friend class LLFloaterReg; public: - static void close(); - static void updateTime(S32 time); + static void close(); + static void updateTime(S32 time); private: - LLFloaterRegionRestarting(const LLSD& key); - virtual ~LLFloaterRegionRestarting(); - BOOL postBuild() override; - bool tick() override; - void refresh() override; - void draw() override; - virtual void regionChange(); + LLFloaterRegionRestarting(const LLSD& key); + virtual ~LLFloaterRegionRestarting(); + BOOL postBuild() override; + bool tick() override; + void refresh() override; + void draw() override; + virtual void regionChange(); - std::string mName; - U32 mShakeIterations; - F32 mShakeMagnitude; - LLTimer mShakeTimer; + std::string mName; + U32 mShakeIterations; + F32 mShakeMagnitude; + LLTimer mShakeTimer; - boost::signals2::connection mRegionChangedConnection; + boost::signals2::connection mRegionChangedConnection; - enum - { - SHAKE_START, - SHAKE_LEFT, - SHAKE_UP, - SHAKE_RIGHT, - SHAKE_DOWN, - SHAKE_DONE - }; + enum + { + SHAKE_START, + SHAKE_LEFT, + SHAKE_UP, + SHAKE_RIGHT, + SHAKE_DOWN, + SHAKE_DONE + }; }; #endif // LL_LLFLOATERREGIONRESTARTING_H diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index e1df6a4b1f..751990b3b6 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloatersettingsdebug.cpp * @brief floater for debugging internal viewer settings * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,12 +37,12 @@ #include "llclipboard.h" -LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) +LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) : LLFloater(key), mSettingList(NULL) { - mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); - mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); + mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); + mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); } LLFloaterSettingsDebug::~LLFloaterSettingsDebug() @@ -68,7 +68,7 @@ BOOL LLFloaterSettingsDebug::postBuild() gSavedSettings.getControl("DebugSettingsHideDefault")->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateList, this, false)); - return TRUE; + return TRUE; } void LLFloaterSettingsDebug::draw() @@ -80,7 +80,7 @@ void LLFloaterSettingsDebug::draw() updateControl(controlp); } - LLFloater::draw(); + LLFloater::draw(); } void LLFloaterSettingsDebug::onCommitSettings() @@ -92,78 +92,78 @@ void LLFloaterSettingsDebug::onCommitSettings() } LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata(); - if (!controlp) - { - return; - } - - LLVector3 vector; - LLVector3d vectord; - LLQuaternion quat; - LLRect rect; - LLColor4 col4; - LLColor3 col3; - LLColor4U col4U; - LLColor4 color_with_alpha; - - switch(controlp->type()) - { - case TYPE_U32: - controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); - break; - case TYPE_S32: - controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); - break; - case TYPE_F32: - controlp->set(LLSD(getChild<LLUICtrl>("val_spinner_1")->getValue().asReal())); - break; - case TYPE_BOOLEAN: - controlp->set(getChild<LLUICtrl>("boolean_combo")->getValue()); - break; - case TYPE_STRING: - controlp->set(LLSD(getChild<LLUICtrl>("val_text")->getValue().asString())); - break; - case TYPE_VEC3: - vector.mV[VX] = (F32)getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); - vector.mV[VY] = (F32)getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - vector.mV[VZ] = (F32)getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - controlp->set(vector.getValue()); - break; - case TYPE_VEC3D: - vectord.mdV[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); - vectord.mdV[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - vectord.mdV[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - controlp->set(vectord.getValue()); - break; - case TYPE_QUAT: - quat.mQ[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); - quat.mQ[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - quat.mQ[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - quat.mQ[VS] = getChild<LLUICtrl>("val_spinner_4")->getValue().asReal();; - controlp->set(quat.getValue()); - break; - case TYPE_RECT: - rect.mLeft = getChild<LLUICtrl>("val_spinner_1")->getValue().asInteger(); - rect.mRight = getChild<LLUICtrl>("val_spinner_2")->getValue().asInteger(); - rect.mBottom = getChild<LLUICtrl>("val_spinner_3")->getValue().asInteger(); - rect.mTop = getChild<LLUICtrl>("val_spinner_4")->getValue().asInteger(); - controlp->set(rect.getValue()); - break; - case TYPE_COL4: - col3.setValue(getChild<LLUICtrl>("val_color_swatch")->getValue()); - col4 = LLColor4(col3, (F32)getChild<LLUICtrl>("val_spinner_4")->getValue().asReal()); - controlp->set(col4.getValue()); - break; - case TYPE_COL3: - controlp->set(getChild<LLUICtrl>("val_color_swatch")->getValue()); - //col3.mV[VRED] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_1")->getValue().asC(); - //col3.mV[VGREEN] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); - //col3.mV[VBLUE] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); - //controlp->set(col3.getValue()); - break; - default: - break; - } + if (!controlp) + { + return; + } + + LLVector3 vector; + LLVector3d vectord; + LLQuaternion quat; + LLRect rect; + LLColor4 col4; + LLColor3 col3; + LLColor4U col4U; + LLColor4 color_with_alpha; + + switch(controlp->type()) + { + case TYPE_U32: + controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); + break; + case TYPE_S32: + controlp->set(getChild<LLUICtrl>("val_spinner_1")->getValue()); + break; + case TYPE_F32: + controlp->set(LLSD(getChild<LLUICtrl>("val_spinner_1")->getValue().asReal())); + break; + case TYPE_BOOLEAN: + controlp->set(getChild<LLUICtrl>("boolean_combo")->getValue()); + break; + case TYPE_STRING: + controlp->set(LLSD(getChild<LLUICtrl>("val_text")->getValue().asString())); + break; + case TYPE_VEC3: + vector.mV[VX] = (F32)getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + vector.mV[VY] = (F32)getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + vector.mV[VZ] = (F32)getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + controlp->set(vector.getValue()); + break; + case TYPE_VEC3D: + vectord.mdV[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + vectord.mdV[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + vectord.mdV[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + controlp->set(vectord.getValue()); + break; + case TYPE_QUAT: + quat.mQ[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal(); + quat.mQ[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + quat.mQ[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + quat.mQ[VS] = getChild<LLUICtrl>("val_spinner_4")->getValue().asReal();; + controlp->set(quat.getValue()); + break; + case TYPE_RECT: + rect.mLeft = getChild<LLUICtrl>("val_spinner_1")->getValue().asInteger(); + rect.mRight = getChild<LLUICtrl>("val_spinner_2")->getValue().asInteger(); + rect.mBottom = getChild<LLUICtrl>("val_spinner_3")->getValue().asInteger(); + rect.mTop = getChild<LLUICtrl>("val_spinner_4")->getValue().asInteger(); + controlp->set(rect.getValue()); + break; + case TYPE_COL4: + col3.setValue(getChild<LLUICtrl>("val_color_swatch")->getValue()); + col4 = LLColor4(col3, (F32)getChild<LLUICtrl>("val_spinner_4")->getValue().asReal()); + controlp->set(col4.getValue()); + break; + case TYPE_COL3: + controlp->set(getChild<LLUICtrl>("val_color_swatch")->getValue()); + //col3.mV[VRED] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_1")->getValue().asC(); + //col3.mV[VGREEN] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_2")->getValue().asReal(); + //col3.mV[VBLUE] = (F32)floaterp->getChild<LLUICtrl>("val_spinner_3")->getValue().asReal(); + //controlp->set(col3.getValue()); + break; + default: + break; + } updateDefaultColumn(controlp); } @@ -186,27 +186,27 @@ void LLFloaterSettingsDebug::onClickDefault() // we've switched controls, or doing per-frame update, so update spinners, etc. void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) { - LLSpinCtrl* spinner1 = getChild<LLSpinCtrl>("val_spinner_1"); - LLSpinCtrl* spinner2 = getChild<LLSpinCtrl>("val_spinner_2"); - LLSpinCtrl* spinner3 = getChild<LLSpinCtrl>("val_spinner_3"); - LLSpinCtrl* spinner4 = getChild<LLSpinCtrl>("val_spinner_4"); - LLColorSwatchCtrl* color_swatch = getChild<LLColorSwatchCtrl>("val_color_swatch"); - - if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) - { - LL_WARNS() << "Could not find all desired controls by name" - << LL_ENDL; - return; - } + LLSpinCtrl* spinner1 = getChild<LLSpinCtrl>("val_spinner_1"); + LLSpinCtrl* spinner2 = getChild<LLSpinCtrl>("val_spinner_2"); + LLSpinCtrl* spinner3 = getChild<LLSpinCtrl>("val_spinner_3"); + LLSpinCtrl* spinner4 = getChild<LLSpinCtrl>("val_spinner_4"); + LLColorSwatchCtrl* color_swatch = getChild<LLColorSwatchCtrl>("val_color_swatch"); + + if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) + { + LL_WARNS() << "Could not find all desired controls by name" + << LL_ENDL; + return; + } hideUIControls(); - if (controlp && !isSettingHidden(controlp)) - { - eControlType type = controlp->type(); + if (controlp && !isSettingHidden(controlp)) + { + eControlType type = controlp->type(); - //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame - getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); + //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame + getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); getChildView("default_btn")->setVisible(true); mSettingName->setVisible(true); mSettingName->setText(controlp->getName()); @@ -224,259 +224,259 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) mComment->setText(controlp->getComment()); } - spinner1->setMaxValue(F32_MAX); - spinner2->setMaxValue(F32_MAX); - spinner3->setMaxValue(F32_MAX); - spinner4->setMaxValue(F32_MAX); - spinner1->setMinValue(-F32_MAX); - spinner2->setMinValue(-F32_MAX); - spinner3->setMinValue(-F32_MAX); - spinner4->setMinValue(-F32_MAX); - if (!spinner1->hasFocus()) - { - spinner1->setIncrement(0.1f); - } - if (!spinner2->hasFocus()) - { - spinner2->setIncrement(0.1f); - } - if (!spinner3->hasFocus()) - { - spinner3->setIncrement(0.1f); - } - if (!spinner4->hasFocus()) - { - spinner4->setIncrement(0.1f); - } - - LLSD sd = controlp->get(); - switch(type) - { - case TYPE_U32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setValue(sd); - spinner1->setMinValue((F32)U32_MIN); - spinner1->setMaxValue((F32)U32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); - } - break; - case TYPE_S32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setValue(sd); - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); - } - break; - case TYPE_F32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(sd); - } - break; - case TYPE_BOOLEAN: - if (!getChild<LLUICtrl>("boolean_combo")->hasFocus()) - { - if (sd.asBoolean()) - { - getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("true")); - } - else - { - getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("")); - } - } - break; - case TYPE_STRING: - getChildView("val_text")->setVisible( TRUE); - if (!getChild<LLUICtrl>("val_text")->hasFocus()) - { - getChild<LLUICtrl>("val_text")->setValue(sd); - } - break; - case TYPE_VEC3: - { - LLVector3 v; - v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); - } - break; - } - case TYPE_VEC3D: - { - LLVector3d v; - v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); - } - break; - } - case TYPE_QUAT: - { - LLQuaternion q; - q.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("S")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(4); - spinner1->setValue(q.mQ[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(4); - spinner2->setValue(q.mQ[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(4); - spinner3->setValue(q.mQ[VZ]); - } - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(4); - spinner4->setValue(q.mQ[VS]); - } - break; - } - case TYPE_RECT: - { - LLRect r; - r.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("Left")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Right")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Bottom")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Top")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(0); - spinner1->setValue(r.mLeft); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(0); - spinner2->setValue(r.mRight); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(0); - spinner3->setValue(r.mBottom); - } - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(0); - spinner4->setValue(r.mTop); - } - - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - - spinner2->setMinValue((F32)S32_MIN); - spinner2->setMaxValue((F32)S32_MAX); - spinner2->setIncrement(1.f); - - spinner3->setMinValue((F32)S32_MIN); - spinner3->setMaxValue((F32)S32_MAX); - spinner3->setIncrement(1.f); - - spinner4->setMinValue((F32)S32_MIN); - spinner4->setMaxValue((F32)S32_MAX); - spinner4->setIncrement(1.f); - break; - } - case TYPE_COL4: - { - LLColor4 clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - // only set if changed so color picker doesn't update - if(clr != LLColor4(color_swatch->getValue())) - { - color_swatch->set(LLColor4(sd), TRUE, FALSE); - } - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Alpha")); - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(3); - spinner4->setMinValue(0.0); - spinner4->setMaxValue(1.f); - spinner4->setValue(clr.mV[VALPHA]); - } - break; - } - case TYPE_COL3: - { - LLColor3 clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - color_swatch->setValue(sd); - break; - } - default: - mComment->setText(std::string("unknown")); - break; - } - } + spinner1->setMaxValue(F32_MAX); + spinner2->setMaxValue(F32_MAX); + spinner3->setMaxValue(F32_MAX); + spinner4->setMaxValue(F32_MAX); + spinner1->setMinValue(-F32_MAX); + spinner2->setMinValue(-F32_MAX); + spinner3->setMinValue(-F32_MAX); + spinner4->setMinValue(-F32_MAX); + if (!spinner1->hasFocus()) + { + spinner1->setIncrement(0.1f); + } + if (!spinner2->hasFocus()) + { + spinner2->setIncrement(0.1f); + } + if (!spinner3->hasFocus()) + { + spinner3->setIncrement(0.1f); + } + if (!spinner4->hasFocus()) + { + spinner4->setIncrement(0.1f); + } + + LLSD sd = controlp->get(); + switch(type) + { + case TYPE_U32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setValue(sd); + spinner1->setMinValue((F32)U32_MIN); + spinner1->setMaxValue((F32)U32_MAX); + spinner1->setIncrement(1.f); + spinner1->setPrecision(0); + } + break; + case TYPE_S32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setValue(sd); + spinner1->setMinValue((F32)S32_MIN); + spinner1->setMaxValue((F32)S32_MAX); + spinner1->setIncrement(1.f); + spinner1->setPrecision(0); + } + break; + case TYPE_F32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(sd); + } + break; + case TYPE_BOOLEAN: + if (!getChild<LLUICtrl>("boolean_combo")->hasFocus()) + { + if (sd.asBoolean()) + { + getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("true")); + } + else + { + getChild<LLUICtrl>("boolean_combo")->setValue(LLSD("")); + } + } + break; + case TYPE_STRING: + getChildView("val_text")->setVisible( TRUE); + if (!getChild<LLUICtrl>("val_text")->hasFocus()) + { + getChild<LLUICtrl>("val_text")->setValue(sd); + } + break; + case TYPE_VEC3: + { + LLVector3 v; + v.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(v[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(3); + spinner2->setValue(v[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(3); + spinner3->setValue(v[VZ]); + } + break; + } + case TYPE_VEC3D: + { + LLVector3d v; + v.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(v[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(3); + spinner2->setValue(v[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(3); + spinner3->setValue(v[VZ]); + } + break; + } + case TYPE_QUAT: + { + LLQuaternion q; + q.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("S")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(4); + spinner1->setValue(q.mQ[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(4); + spinner2->setValue(q.mQ[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(4); + spinner3->setValue(q.mQ[VZ]); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(4); + spinner4->setValue(q.mQ[VS]); + } + break; + } + case TYPE_RECT: + { + LLRect r; + r.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("Left")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Right")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Bottom")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("Top")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(0); + spinner1->setValue(r.mLeft); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(0); + spinner2->setValue(r.mRight); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(0); + spinner3->setValue(r.mBottom); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(0); + spinner4->setValue(r.mTop); + } + + spinner1->setMinValue((F32)S32_MIN); + spinner1->setMaxValue((F32)S32_MAX); + spinner1->setIncrement(1.f); + + spinner2->setMinValue((F32)S32_MIN); + spinner2->setMaxValue((F32)S32_MAX); + spinner2->setIncrement(1.f); + + spinner3->setMinValue((F32)S32_MIN); + spinner3->setMaxValue((F32)S32_MAX); + spinner3->setIncrement(1.f); + + spinner4->setMinValue((F32)S32_MIN); + spinner4->setMaxValue((F32)S32_MAX); + spinner4->setIncrement(1.f); + break; + } + case TYPE_COL4: + { + LLColor4 clr; + clr.setValue(sd); + color_swatch->setVisible(TRUE); + // only set if changed so color picker doesn't update + if(clr != LLColor4(color_swatch->getValue())) + { + color_swatch->set(LLColor4(sd), TRUE, FALSE); + } + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("Alpha")); + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(3); + spinner4->setMinValue(0.0); + spinner4->setMaxValue(1.f); + spinner4->setValue(clr.mV[VALPHA]); + } + break; + } + case TYPE_COL3: + { + LLColor3 clr; + clr.setValue(sd); + color_swatch->setVisible(TRUE); + color_swatch->setValue(sd); + break; + } + default: + mComment->setText(std::string("unknown")); + break; + } + } } @@ -500,7 +500,7 @@ void LLFloaterSettingsDebug::updateList(bool skip_selection) LLFloaterSettingsDebug* floater; std::string selected_setting; bool skip_selection; - f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection) + f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection) : setting_list(list), floater(floater), selected_setting(setting), skip_selection(skip_selection) {} virtual void apply(const std::string& name, LLControlVariable* control) { diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index 6ff3e344b4..e52d5ac863 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloatersettingsdebug.h * @brief floater for debugging internal viewer settings * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,30 +33,30 @@ class LLScrollListCtrl; class LLTextBox; -class LLFloaterSettingsDebug -: public LLFloater +class LLFloaterSettingsDebug +: public LLFloater { - friend class LLFloaterReg; + friend class LLFloaterReg; public: - virtual BOOL postBuild(); - virtual void draw(); + virtual BOOL postBuild(); + virtual void draw(); - void updateControl(LLControlVariable* control); + void updateControl(LLControlVariable* control); - void onCommitSettings(); - void onClickDefault(); + void onCommitSettings(); + void onClickDefault(); void onClickCopy(); bool matchesSearchFilter(std::string setting_name); bool isSettingHidden(LLControlVariable* control); private: - // key - selects which settings to show, one of: - // "all", "base", "account", "skin" - LLFloaterSettingsDebug(const LLSD& key); - virtual ~LLFloaterSettingsDebug(); + // key - selects which settings to show, one of: + // "all", "base", "account", "skin" + LLFloaterSettingsDebug(const LLSD& key); + virtual ~LLFloaterSettingsDebug(); void updateList(bool skip_selection = false); void onSettingSelect(); @@ -66,9 +66,9 @@ private: void hideUIControls(); LLScrollListCtrl* mSettingList; - + protected: - class LLTextEditor* mComment; + class LLTextEditor* mComment; LLTextBox* mSettingName; LLButton* mCopyBtn; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 74b6218b46..4e35290a3b 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,9 +30,9 @@ // *TODO: Translate error messgaes using notifications/alerts.xml -#include "llviewerprecompiledheaders.h" // Precompiled headers +#include "llviewerprecompiledheaders.h" // Precompiled headers -#include "llfloateruipreview.h" // Own header +#include "llfloateruipreview.h" // Own header // Internal utility #include "lldiriterator.h" @@ -56,10 +56,10 @@ #include "lltooltip.h" #include "llviewermenu.h" #include "llrngwriter.h" -#include "llfloater.h" // superclass +#include "llfloater.h" // superclass #include "llfloaterreg.h" -#include "llscrollcontainer.h" // scroll container for overlapping elements -#include "lllivefile.h" // live file poll/stat/reload +#include "llscrollcontainer.h" // scroll container for overlapping elements +#include "lllivefile.h" // live file poll/stat/reload #include "llviewermenufile.h" // LLFilePickerReplyThread // Boost (for linux/unix command-line execv) @@ -84,8 +84,8 @@ static LLDefaultChildRegistry::Register<LLOverlapPanel> register_overlap_panel(" static std::string get_xui_dir() { - std::string delim = gDirUtilp->getDirDelimiter(); - return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim; + std::string delim = gDirUtilp->getDirDelimiter(); + return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim; } // Forward declarations to avoid header dependencies @@ -107,115 +107,115 @@ class LLPreviewedFloater; class LLOverlapPanel : public LLPanel { public: - struct Params : public LLInitParam::Block<Params, LLPanel::Params> - { - Params() {} - }; - LLOverlapPanel(Params p = Params()) : LLPanel(p), - mSpacing(10), - // mClickedElement(NULL), - mLastClickedElement(NULL) - { - mOriginalWidth = getRect().getWidth(); - mOriginalHeight = getRect().getHeight(); - } - virtual void draw(); - - typedef std::map<LLView*, std::list<LLView*> > OverlapMap; - OverlapMap mOverlapMap; // map, of XUI element to a list of XUI elements it overlaps - - // LLView *mClickedElement; - LLView *mLastClickedElement; - int mOriginalWidth, mOriginalHeight, mSpacing; + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + { + Params() {} + }; + LLOverlapPanel(Params p = Params()) : LLPanel(p), + mSpacing(10), + // mClickedElement(NULL), + mLastClickedElement(NULL) + { + mOriginalWidth = getRect().getWidth(); + mOriginalHeight = getRect().getHeight(); + } + virtual void draw(); + + typedef std::map<LLView*, std::list<LLView*> > OverlapMap; + OverlapMap mOverlapMap; // map, of XUI element to a list of XUI elements it overlaps + + // LLView *mClickedElement; + LLView *mLastClickedElement; + int mOriginalWidth, mOriginalHeight, mSpacing; }; class LLFloaterUIPreview : public LLFloater { public: - // Setup - LLFloaterUIPreview(const LLSD& key); - virtual ~LLFloaterUIPreview(); - - std::string getLocStr(S32 ID); // fetches the localization string based on what is selected in the drop-down menu - void displayFloater(BOOL click, S32 ID); // needs to be public so live file can call it when it finds an update - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onClose(bool app_quitting); - - void refreshList(); // refresh list (empty it out and fill it up from scratch) - void addFloaterEntry(const std::string& path); // add a single file's entry to the list of floaters - - static BOOL containerType(LLView* viewp); // check if the element is a container type and tree traverses need to look at its children - -public: - LLPreviewedFloater* mDisplayedFloater; // the floater which is currently being displayed - LLPreviewedFloater* mDisplayedFloater_2; // the floater which is currently being displayed - LLGUIPreviewLiveFile* mLiveFile; // live file for checking for updates to the currently-displayed XML file - LLOverlapPanel* mOverlapPanel; // custom overlapping elements panel - // BOOL mHighlightingDiffs; // bool for whether localization diffs are being highlighted or not - BOOL mHighlightingOverlaps; // bool for whether overlapping elements are being highlighted - - // typedef std::map<std::string,std::pair<std::list<std::string>,std::list<std::string> > > DiffMap; // this version copies the lists etc., and thus is bad memory-wise - typedef std::list<std::string> StringList; - typedef std::shared_ptr<StringList> StringListPtr; - typedef std::map<std::string, std::pair<StringListPtr,StringListPtr> > DiffMap; - DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors + // Setup + LLFloaterUIPreview(const LLSD& key); + virtual ~LLFloaterUIPreview(); + + std::string getLocStr(S32 ID); // fetches the localization string based on what is selected in the drop-down menu + void displayFloater(BOOL click, S32 ID); // needs to be public so live file can call it when it finds an update + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + + void refreshList(); // refresh list (empty it out and fill it up from scratch) + void addFloaterEntry(const std::string& path); // add a single file's entry to the list of floaters + + static BOOL containerType(LLView* viewp); // check if the element is a container type and tree traverses need to look at its children + +public: + LLPreviewedFloater* mDisplayedFloater; // the floater which is currently being displayed + LLPreviewedFloater* mDisplayedFloater_2; // the floater which is currently being displayed + LLGUIPreviewLiveFile* mLiveFile; // live file for checking for updates to the currently-displayed XML file + LLOverlapPanel* mOverlapPanel; // custom overlapping elements panel + // BOOL mHighlightingDiffs; // bool for whether localization diffs are being highlighted or not + BOOL mHighlightingOverlaps; // bool for whether overlapping elements are being highlighted + + // typedef std::map<std::string,std::pair<std::list<std::string>,std::list<std::string> > > DiffMap; // this version copies the lists etc., and thus is bad memory-wise + typedef std::list<std::string> StringList; + typedef std::shared_ptr<StringList> StringListPtr; + typedef std::map<std::string, std::pair<StringListPtr,StringListPtr> > DiffMap; + DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors private: - LLExternalEditor mExternalEditor; - - // XUI elements for this floater - LLScrollListCtrl* mFileList; // scroll list control for file list - LLLineEditor* mEditorPathTextBox; // text field for path to editor executable - LLLineEditor* mEditorArgsTextBox; // text field for arguments to editor executable - LLLineEditor* mDiffPathTextBox; // text field for path to diff file - LLButton* mDisplayFloaterBtn; // button to display primary floater - LLButton* mDisplayFloaterBtn_2; // button to display secondary floater - LLButton* mEditFloaterBtn; // button to edit floater - LLButton* mExecutableBrowseButton; // button to browse for executable - LLButton* mCloseOtherButton; // button to close primary displayed floater - LLButton* mCloseOtherButton_2; // button to close secondary displayed floater - LLButton* mDiffBrowseButton; // button to browse for diff file - LLButton* mToggleHighlightButton; // button to toggle highlight of files/elements with diffs - LLButton* mToggleOverlapButton; // button to togle overlap panel/highlighting - LLComboBox* mLanguageSelection; // combo box for primary language selection - LLComboBox* mLanguageSelection_2; // combo box for secondary language selection - S32 mLastDisplayedX, mLastDisplayedY; // stored position of last floater so the new one opens up in the same place - std::string mDelim; // the OS-specific delimiter character (/ or \) (*TODO: this shouldn't be needed, right?) - - std::string mSavedEditorPath; // stored editor path so closing this floater doesn't reset it - std::string mSavedEditorArgs; // stored editor args so closing this floater doesn't reset it - std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it - - // Internal functionality - static void popupAndPrintWarning(const std::string& warning); // pop up a warning - std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization - void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file - void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater - void highlightChangedFiles(); // look up the list of changed files to highlight and highlight them in the scroll list - void findOverlapsInChildren(LLView* parent); // fill the map below with element overlap information - static BOOL overlapIgnorable(LLView* viewp); // check it the element can be ignored for overlap/localization purposes - - // check if two elements overlap using their rectangles - // used instead of llrect functions because by adding a few pixels of leeway I can cut down drastically on the number of overlaps - BOOL elementOverlap(LLView* view1, LLView* view2); - - // Button/drop-down action listeners (self explanatory) - void onClickDisplayFloater(S32 id); - void onClickSaveFloater(S32 id); - void onClickSaveAll(S32 id); - void onClickEditFloater(); - void onClickBrowseForEditor(); - void getExecutablePath(const std::vector<std::string>& filenames); - void onClickBrowseForDiffs(); - void getDiffsFilePath(const std::vector<std::string>& filenames); - void onClickToggleDiffHighlighting(); - void onClickToggleOverlapping(); - void onClickCloseDisplayedFloater(S32 id); - void onLanguageComboSelect(LLUICtrl* ctrl); - void onClickExportSchema(); - void onClickShowRectangles(const LLSD& data); + LLExternalEditor mExternalEditor; + + // XUI elements for this floater + LLScrollListCtrl* mFileList; // scroll list control for file list + LLLineEditor* mEditorPathTextBox; // text field for path to editor executable + LLLineEditor* mEditorArgsTextBox; // text field for arguments to editor executable + LLLineEditor* mDiffPathTextBox; // text field for path to diff file + LLButton* mDisplayFloaterBtn; // button to display primary floater + LLButton* mDisplayFloaterBtn_2; // button to display secondary floater + LLButton* mEditFloaterBtn; // button to edit floater + LLButton* mExecutableBrowseButton; // button to browse for executable + LLButton* mCloseOtherButton; // button to close primary displayed floater + LLButton* mCloseOtherButton_2; // button to close secondary displayed floater + LLButton* mDiffBrowseButton; // button to browse for diff file + LLButton* mToggleHighlightButton; // button to toggle highlight of files/elements with diffs + LLButton* mToggleOverlapButton; // button to togle overlap panel/highlighting + LLComboBox* mLanguageSelection; // combo box for primary language selection + LLComboBox* mLanguageSelection_2; // combo box for secondary language selection + S32 mLastDisplayedX, mLastDisplayedY; // stored position of last floater so the new one opens up in the same place + std::string mDelim; // the OS-specific delimiter character (/ or \) (*TODO: this shouldn't be needed, right?) + + std::string mSavedEditorPath; // stored editor path so closing this floater doesn't reset it + std::string mSavedEditorArgs; // stored editor args so closing this floater doesn't reset it + std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it + + // Internal functionality + static void popupAndPrintWarning(const std::string& warning); // pop up a warning + std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization + void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file + void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater + void highlightChangedFiles(); // look up the list of changed files to highlight and highlight them in the scroll list + void findOverlapsInChildren(LLView* parent); // fill the map below with element overlap information + static BOOL overlapIgnorable(LLView* viewp); // check it the element can be ignored for overlap/localization purposes + + // check if two elements overlap using their rectangles + // used instead of llrect functions because by adding a few pixels of leeway I can cut down drastically on the number of overlaps + BOOL elementOverlap(LLView* view1, LLView* view2); + + // Button/drop-down action listeners (self explanatory) + void onClickDisplayFloater(S32 id); + void onClickSaveFloater(S32 id); + void onClickSaveAll(S32 id); + void onClickEditFloater(); + void onClickBrowseForEditor(); + void getExecutablePath(const std::vector<std::string>& filenames); + void onClickBrowseForDiffs(); + void getDiffsFilePath(const std::vector<std::string>& filenames); + void onClickToggleDiffHighlighting(); + void onClickToggleOverlapping(); + void onClickCloseDisplayedFloater(S32 id); + void onLanguageComboSelect(LLUICtrl* ctrl); + void onClickExportSchema(); + void onClickShowRectangles(const LLSD& data); }; //---------------------------------------------------------------------------- @@ -226,11 +226,11 @@ private: class LLLocalizationResetForcer { public: - LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID); - virtual ~LLLocalizationResetForcer(); + LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID); + virtual ~LLLocalizationResetForcer(); private: - std::string mSavedLocalization; // the localization before we change it + std::string mSavedLocalization; // the localization before we change it }; // Implementation of live file @@ -239,26 +239,26 @@ private: class LLGUIPreviewLiveFile : public LLLiveFile { public: - LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent); - virtual ~LLGUIPreviewLiveFile(); - LLFloaterUIPreview* mParent; - LLFadeEventTimer* mFadeTimer; // timer for fade-to-yellow-and-back effect to warn that file has been reloaded - BOOL mFirstFade; // setting this avoids showing the fade reload warning on first load - std::string mFileName; + LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent); + virtual ~LLGUIPreviewLiveFile(); + LLFloaterUIPreview* mParent; + LLFadeEventTimer* mFadeTimer; // timer for fade-to-yellow-and-back effect to warn that file has been reloaded + BOOL mFirstFade; // setting this avoids showing the fade reload warning on first load + std::string mFileName; protected: - bool loadFile(); + bool loadFile(); }; // Implementation of graphical fade in/out (on timer) for when XUI files are updated class LLFadeEventTimer : public LLEventTimer { public: - LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); - bool tick() override; - LLGUIPreviewLiveFile* mParent; + LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); + bool tick() override; + LLGUIPreviewLiveFile* mParent; private: - BOOL mFadingOut; // fades in then out; this is toggled in between - LLColor4 mOriginalColor; // original color; color is reset to this after fade is coimplete + BOOL mFadingOut; // fades in then out; this is toggled in between + LLColor4 mOriginalColor; // original color; color is reset to this after fade is coimplete }; // Implementation of previewed floater @@ -266,21 +266,21 @@ private: class LLPreviewedFloater : public LLFloater { public: - LLPreviewedFloater(LLFloaterUIPreview* floater, const Params& params) - : LLFloater(LLSD(), params), - mFloaterUIPreview(floater) - { - } + LLPreviewedFloater(LLFloaterUIPreview* floater, const Params& params) + : LLFloater(LLSD(), params), + mFloaterUIPreview(floater) + { + } - virtual void draw(); - BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - BOOL handleToolTip(S32 x, S32 y, MASK mask); - BOOL selectElement(LLView* parent, int x, int y, int depth); // select element to display its overlappers + virtual void draw(); + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + BOOL handleToolTip(S32 x, S32 y, MASK mask); + BOOL selectElement(LLView* parent, int x, int y, int depth); // select element to display its overlappers - LLFloaterUIPreview* mFloaterUIPreview; + LLFloaterUIPreview* mFloaterUIPreview; - // draw widget outlines - static bool sShowRectangles; + // draw widget outlines + static bool sShowRectangles; }; bool LLPreviewedFloater::sShowRectangles = false; @@ -291,507 +291,507 @@ bool LLPreviewedFloater::sShowRectangles = false; // Changes are made here LLLocalizationResetForcer::LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID) { - mSavedLocalization = LLUI::getInstance()->mSettingGroups["config"]->getString("Language"); // save current localization setting - LLUI::getInstance()->mSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in - // forcibly reset XUI paths with this new language - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), floater->getLocStr(ID)); + mSavedLocalization = LLUI::getInstance()->mSettingGroups["config"]->getString("Language"); // save current localization setting + LLUI::getInstance()->mSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in + // forcibly reset XUI paths with this new language + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), floater->getLocStr(ID)); } // Actually reset in destructor // Changes are reversed here LLLocalizationResetForcer::~LLLocalizationResetForcer() { - LLUI::getInstance()->mSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it - // forcibly reset XUI paths with this new language - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), mSavedLocalization); + LLUI::getInstance()->mSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it + // forcibly reset XUI paths with this new language + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), mSavedLocalization); } // Live file constructor // Needs full path for LLLiveFile but needs just file name for this code, hence the reduntant arguments; easier than separating later LLGUIPreviewLiveFile::LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent) : mFileName(name), - mParent(parent), - mFirstFade(TRUE), - mFadeTimer(NULL), - LLLiveFile(path, 1.0) + mParent(parent), + mFirstFade(TRUE), + mFadeTimer(NULL), + LLLiveFile(path, 1.0) {} LLGUIPreviewLiveFile::~LLGUIPreviewLiveFile() { - mParent->mLiveFile = NULL; - if(mFadeTimer) - { - mFadeTimer->mParent = NULL; - // deletes itself; see lltimer.cpp - } + mParent->mLiveFile = NULL; + if(mFadeTimer) + { + mFadeTimer->mParent = NULL; + // deletes itself; see lltimer.cpp + } } // Live file load bool LLGUIPreviewLiveFile::loadFile() { - mParent->displayFloater(FALSE,1); // redisplay the floater - if(mFirstFade) // only fade if it wasn't just clicked on; can't use "clicked" BOOL below because of an oddity with setting LLLiveFile initial state - { - mFirstFade = FALSE; - } - else - { - if(mFadeTimer) - { - mFadeTimer->mParent = NULL; - } - mFadeTimer = new LLFadeEventTimer(0.05f,this); - } - return true; + mParent->displayFloater(FALSE,1); // redisplay the floater + if(mFirstFade) // only fade if it wasn't just clicked on; can't use "clicked" BOOL below because of an oddity with setting LLLiveFile initial state + { + mFirstFade = FALSE; + } + else + { + if(mFadeTimer) + { + mFadeTimer->mParent = NULL; + } + mFadeTimer = new LLFadeEventTimer(0.05f,this); + } + return true; } // Initialize fade event timer LLFadeEventTimer::LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent) - : mParent(parent), - mFadingOut(TRUE), - LLEventTimer(refresh) + : mParent(parent), + mFadingOut(TRUE), + LLEventTimer(refresh) { - mOriginalColor = mParent->mParent->mDisplayedFloater->getBackgroundColor(); + mOriginalColor = mParent->mParent->mDisplayedFloater->getBackgroundColor(); } // Single tick of fade event timer: increment the color bool LLFadeEventTimer::tick() { - float diff = 0.04f; - if(TRUE == mFadingOut) // set fade for in/out color direction - { - diff = -diff; - } - - if(NULL == mParent) // no more need to tick, so suicide - { - return true; - } - - // Set up colors - LLColor4 bg_color = mParent->mParent->mDisplayedFloater->getBackgroundColor(); - LLSD colors = bg_color.getValue(); - LLSD colors_old = colors; - - // Tick colors - colors[0] = colors[0].asReal() - diff; if(colors[0].asReal() < mOriginalColor.getValue()[0].asReal()) { colors[0] = colors_old[0]; } - colors[1] = colors[1].asReal() - diff; if(colors[1].asReal() < mOriginalColor.getValue()[1].asReal()) { colors[1] = colors_old[1]; } - colors[2] = colors[2].asReal() + diff; if(colors[2].asReal() > mOriginalColor.getValue()[2].asReal()) { colors[2] = colors_old[2]; } - - // Clamp and set colors - bg_color.setValue(colors); - bg_color.clamp(); // make sure we didn't exceed [0,1] - mParent->mParent->mDisplayedFloater->setBackgroundColor(bg_color); - - if(bg_color[2] <= 0.0f) // end of fade out, start fading in - { - mFadingOut = FALSE; - } - - return false; + float diff = 0.04f; + if(TRUE == mFadingOut) // set fade for in/out color direction + { + diff = -diff; + } + + if(NULL == mParent) // no more need to tick, so suicide + { + return true; + } + + // Set up colors + LLColor4 bg_color = mParent->mParent->mDisplayedFloater->getBackgroundColor(); + LLSD colors = bg_color.getValue(); + LLSD colors_old = colors; + + // Tick colors + colors[0] = colors[0].asReal() - diff; if(colors[0].asReal() < mOriginalColor.getValue()[0].asReal()) { colors[0] = colors_old[0]; } + colors[1] = colors[1].asReal() - diff; if(colors[1].asReal() < mOriginalColor.getValue()[1].asReal()) { colors[1] = colors_old[1]; } + colors[2] = colors[2].asReal() + diff; if(colors[2].asReal() > mOriginalColor.getValue()[2].asReal()) { colors[2] = colors_old[2]; } + + // Clamp and set colors + bg_color.setValue(colors); + bg_color.clamp(); // make sure we didn't exceed [0,1] + mParent->mParent->mDisplayedFloater->setBackgroundColor(bg_color); + + if(bg_color[2] <= 0.0f) // end of fade out, start fading in + { + mFadingOut = FALSE; + } + + return false; } // Constructor LLFloaterUIPreview::LLFloaterUIPreview(const LLSD& key) : LLFloater(key), - mDisplayedFloater(NULL), - mDisplayedFloater_2(NULL), - mLiveFile(NULL), - // sHighlightingDiffs(FALSE), - mHighlightingOverlaps(FALSE), - mLastDisplayedX(0), - mLastDisplayedY(0) + mDisplayedFloater(NULL), + mDisplayedFloater_2(NULL), + mLiveFile(NULL), + // sHighlightingDiffs(FALSE), + mHighlightingOverlaps(FALSE), + mLastDisplayedX(0), + mLastDisplayedY(0) { } // Destructor LLFloaterUIPreview::~LLFloaterUIPreview() { - // spawned floaters are deleted automatically, so we don't need to delete them here - - // save contents of textfields so it can be restored later if the floater is created again this session - mSavedEditorPath = mEditorPathTextBox->getText(); - mSavedEditorArgs = mEditorArgsTextBox->getText(); - mSavedDiffPath = mDiffPathTextBox->getText(); - - // delete live file if it exists - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } + // spawned floaters are deleted automatically, so we don't need to delete them here + + // save contents of textfields so it can be restored later if the floater is created again this session + mSavedEditorPath = mEditorPathTextBox->getText(); + mSavedEditorArgs = mEditorArgsTextBox->getText(); + mSavedDiffPath = mDiffPathTextBox->getText(); + + // delete live file if it exists + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } } // Perform post-build setup (defined in superclass) BOOL LLFloaterUIPreview::postBuild() { - LLPanel* main_panel_tmp = getChild<LLPanel>("main_panel"); // get a pointer to the main panel in order to... - mFileList = main_panel_tmp->getChild<LLScrollListCtrl>("name_list"); // save pointer to file list - // Double-click opens the floater, for convenience - mFileList->setDoubleClickCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); - - setDefaultBtn("display_floater"); - // get pointers to buttons and link to callbacks - mLanguageSelection = main_panel_tmp->getChild<LLComboBox>("language_select_combo"); - mLanguageSelection->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); - mLanguageSelection_2 = main_panel_tmp->getChild<LLComboBox>("language_select_combo_2"); - mLanguageSelection_2->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); - LLPanel* editor_panel_tmp = main_panel_tmp->getChild<LLPanel>("editor_panel"); - mDisplayFloaterBtn = main_panel_tmp->getChild<LLButton>("display_floater"); - mDisplayFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); - mDisplayFloaterBtn_2 = main_panel_tmp->getChild<LLButton>("display_floater_2"); - mDisplayFloaterBtn_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, SECONDARY_FLOATER)); - mToggleOverlapButton = main_panel_tmp->getChild<LLButton>("toggle_overlap_panel"); - mToggleOverlapButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleOverlapping, this)); - mCloseOtherButton = main_panel_tmp->getChild<LLButton>("close_displayed_floater"); - mCloseOtherButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, PRIMARY_FLOATER)); - mCloseOtherButton_2 = main_panel_tmp->getChild<LLButton>("close_displayed_floater_2"); - mCloseOtherButton_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, SECONDARY_FLOATER)); - mEditFloaterBtn = main_panel_tmp->getChild<LLButton>("edit_floater"); - mEditFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickEditFloater, this)); - mExecutableBrowseButton = editor_panel_tmp->getChild<LLButton>("browse_for_executable"); - LLPanel* vlt_panel_tmp = main_panel_tmp->getChild<LLPanel>("vlt_panel"); - mExecutableBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForEditor, this)); - mDiffBrowseButton = vlt_panel_tmp->getChild<LLButton>("browse_for_vlt_diffs"); - mDiffBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForDiffs, this)); - mToggleHighlightButton = vlt_panel_tmp->getChild<LLButton>("toggle_vlt_diff_highlight"); - mToggleHighlightButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleDiffHighlighting, this)); - main_panel_tmp->getChild<LLButton>("save_floater")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveFloater, this, PRIMARY_FLOATER)); - main_panel_tmp->getChild<LLButton>("save_all_floaters")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveAll, this, PRIMARY_FLOATER)); - - getChild<LLButton>("export_schema")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickExportSchema, this)); - getChild<LLUICtrl>("show_rectangles")->setCommitCallback( - boost::bind(&LLFloaterUIPreview::onClickShowRectangles, this, _2)); - - // get pointers to text fields - mEditorPathTextBox = editor_panel_tmp->getChild<LLLineEditor>("executable_path_field"); - mEditorArgsTextBox = editor_panel_tmp->getChild<LLLineEditor>("executable_args_field"); - mDiffPathTextBox = vlt_panel_tmp->getChild<LLLineEditor>("vlt_diff_path_field"); - - // *HACK: restored saved editor path and args to textfields - mEditorPathTextBox->setText(mSavedEditorPath); - mEditorArgsTextBox->setText(mSavedEditorArgs); - mDiffPathTextBox->setText(mSavedDiffPath); - - // Set up overlap panel - mOverlapPanel = getChild<LLOverlapPanel>("overlap_panel"); - - getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); - - mDelim = gDirUtilp->getDirDelimiter(); // initialize delimiter to dir sep slash - - // refresh list of available languages (EN will still be default) - BOOL found = TRUE; - BOOL found_en_us = FALSE; - std::string language_directory; - std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim - mLanguageSelection->removeall(); // clear out anything temporarily in list from XML - - LLDirIterator iter(xui_dir, "*"); - while(found) // for every directory - { - if((found = iter.next(language_directory))) // get next directory - { - std::string full_path = gDirUtilp->add(xui_dir, language_directory); - if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it - { - continue; - } - - if(strncmp("template",language_directory.c_str(),8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory - { - if(!strncmp("en",language_directory.c_str(),5)) // remember if we've seen en, so we can make it default - { - found_en_us = TRUE; - } - else - { - mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu - mLanguageSelection_2->add(std::string(language_directory)); - } - } - } - } - if(found_en_us) - { - mLanguageSelection->add(std::string("en"),ADD_TOP); // make en first item if we found it - mLanguageSelection_2->add(std::string("en"),ADD_TOP); - } - else - { - std::string warning = std::string("No EN localization found; check your XUI directories!"); - popupAndPrintWarning(warning); - } - mLanguageSelection->selectFirstItem(); // select the first item - mLanguageSelection_2->selectFirstItem(); - - refreshList(); // refresh the list of available floaters - - return TRUE; + LLPanel* main_panel_tmp = getChild<LLPanel>("main_panel"); // get a pointer to the main panel in order to... + mFileList = main_panel_tmp->getChild<LLScrollListCtrl>("name_list"); // save pointer to file list + // Double-click opens the floater, for convenience + mFileList->setDoubleClickCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); + + setDefaultBtn("display_floater"); + // get pointers to buttons and link to callbacks + mLanguageSelection = main_panel_tmp->getChild<LLComboBox>("language_select_combo"); + mLanguageSelection->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); + mLanguageSelection_2 = main_panel_tmp->getChild<LLComboBox>("language_select_combo_2"); + mLanguageSelection_2->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); + LLPanel* editor_panel_tmp = main_panel_tmp->getChild<LLPanel>("editor_panel"); + mDisplayFloaterBtn = main_panel_tmp->getChild<LLButton>("display_floater"); + mDisplayFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); + mDisplayFloaterBtn_2 = main_panel_tmp->getChild<LLButton>("display_floater_2"); + mDisplayFloaterBtn_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, SECONDARY_FLOATER)); + mToggleOverlapButton = main_panel_tmp->getChild<LLButton>("toggle_overlap_panel"); + mToggleOverlapButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleOverlapping, this)); + mCloseOtherButton = main_panel_tmp->getChild<LLButton>("close_displayed_floater"); + mCloseOtherButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, PRIMARY_FLOATER)); + mCloseOtherButton_2 = main_panel_tmp->getChild<LLButton>("close_displayed_floater_2"); + mCloseOtherButton_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, SECONDARY_FLOATER)); + mEditFloaterBtn = main_panel_tmp->getChild<LLButton>("edit_floater"); + mEditFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickEditFloater, this)); + mExecutableBrowseButton = editor_panel_tmp->getChild<LLButton>("browse_for_executable"); + LLPanel* vlt_panel_tmp = main_panel_tmp->getChild<LLPanel>("vlt_panel"); + mExecutableBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForEditor, this)); + mDiffBrowseButton = vlt_panel_tmp->getChild<LLButton>("browse_for_vlt_diffs"); + mDiffBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForDiffs, this)); + mToggleHighlightButton = vlt_panel_tmp->getChild<LLButton>("toggle_vlt_diff_highlight"); + mToggleHighlightButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleDiffHighlighting, this)); + main_panel_tmp->getChild<LLButton>("save_floater")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveFloater, this, PRIMARY_FLOATER)); + main_panel_tmp->getChild<LLButton>("save_all_floaters")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveAll, this, PRIMARY_FLOATER)); + + getChild<LLButton>("export_schema")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickExportSchema, this)); + getChild<LLUICtrl>("show_rectangles")->setCommitCallback( + boost::bind(&LLFloaterUIPreview::onClickShowRectangles, this, _2)); + + // get pointers to text fields + mEditorPathTextBox = editor_panel_tmp->getChild<LLLineEditor>("executable_path_field"); + mEditorArgsTextBox = editor_panel_tmp->getChild<LLLineEditor>("executable_args_field"); + mDiffPathTextBox = vlt_panel_tmp->getChild<LLLineEditor>("vlt_diff_path_field"); + + // *HACK: restored saved editor path and args to textfields + mEditorPathTextBox->setText(mSavedEditorPath); + mEditorArgsTextBox->setText(mSavedEditorArgs); + mDiffPathTextBox->setText(mSavedDiffPath); + + // Set up overlap panel + mOverlapPanel = getChild<LLOverlapPanel>("overlap_panel"); + + getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); + + mDelim = gDirUtilp->getDirDelimiter(); // initialize delimiter to dir sep slash + + // refresh list of available languages (EN will still be default) + BOOL found = TRUE; + BOOL found_en_us = FALSE; + std::string language_directory; + std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim + mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + + LLDirIterator iter(xui_dir, "*"); + while(found) // for every directory + { + if((found = iter.next(language_directory))) // get next directory + { + std::string full_path = gDirUtilp->add(xui_dir, language_directory); + if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it + { + continue; + } + + if(strncmp("template",language_directory.c_str(),8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory + { + if(!strncmp("en",language_directory.c_str(),5)) // remember if we've seen en, so we can make it default + { + found_en_us = TRUE; + } + else + { + mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu + mLanguageSelection_2->add(std::string(language_directory)); + } + } + } + } + if(found_en_us) + { + mLanguageSelection->add(std::string("en"),ADD_TOP); // make en first item if we found it + mLanguageSelection_2->add(std::string("en"),ADD_TOP); + } + else + { + std::string warning = std::string("No EN localization found; check your XUI directories!"); + popupAndPrintWarning(warning); + } + mLanguageSelection->selectFirstItem(); // select the first item + mLanguageSelection_2->selectFirstItem(); + + refreshList(); // refresh the list of available floaters + + return TRUE; } // Callback for language combo box selection: refresh current floater when you change languages void LLFloaterUIPreview::onLanguageComboSelect(LLUICtrl* ctrl) { - LLComboBox* caller = dynamic_cast<LLComboBox*>(ctrl); - if (!caller) - return; - if(caller->getName() == std::string("language_select_combo")) - { - if(mDisplayedFloater) - { - onClickCloseDisplayedFloater(PRIMARY_FLOATER); - displayFloater(TRUE,1); - } - } - else - { - if(mDisplayedFloater_2) - { - onClickCloseDisplayedFloater(PRIMARY_FLOATER); - displayFloater(TRUE,2); // *TODO: make take an arg - } - } + LLComboBox* caller = dynamic_cast<LLComboBox*>(ctrl); + if (!caller) + return; + if(caller->getName() == std::string("language_select_combo")) + { + if(mDisplayedFloater) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + displayFloater(TRUE,1); + } + } + else + { + if(mDisplayedFloater_2) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + displayFloater(TRUE,2); // *TODO: make take an arg + } + } } void LLFloaterUIPreview::onClickExportSchema() { - //NOTE: schema generation not complete - //gViewerWindow->setCursor(UI_CURSOR_WAIT); - //std::string template_path = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "xui", "schema"); - - //typedef LLWidgetTypeRegistry::Registrar::registry_map_t::const_iterator registry_it; - //registry_it end_it = LLWidgetTypeRegistry::defaultRegistrar().endItems(); - //for(registry_it it = LLWidgetTypeRegistry::defaultRegistrar().beginItems(); - // it != end_it; - // ++it) - //{ - // std::string widget_name = it->first; - // const LLInitParam::BaseBlock& block = - // (*LLDefaultParamBlockRegistry::instance().getValue(*LLWidgetTypeRegistry::instance().getValue(widget_name)))(); - // LLXMLNodePtr root_nodep = new LLXMLNode(); - // LLRNGWriter().writeRNG(widget_name, root_nodep, block, "http://www.lindenlab.com/xui"); - - // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); - - // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), "w"); - // { - // LLXMLNode::writeHeaderToFile(rng_file); - // const bool use_type_decorations = false; - // root_nodep->writeToFile(rng_file, std::string(), use_type_decorations); - // } - // fclose(rng_file); - //} - //gViewerWindow->setCursor(UI_CURSOR_ARROW); + //NOTE: schema generation not complete + //gViewerWindow->setCursor(UI_CURSOR_WAIT); + //std::string template_path = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "xui", "schema"); + + //typedef LLWidgetTypeRegistry::Registrar::registry_map_t::const_iterator registry_it; + //registry_it end_it = LLWidgetTypeRegistry::defaultRegistrar().endItems(); + //for(registry_it it = LLWidgetTypeRegistry::defaultRegistrar().beginItems(); + // it != end_it; + // ++it) + //{ + // std::string widget_name = it->first; + // const LLInitParam::BaseBlock& block = + // (*LLDefaultParamBlockRegistry::instance().getValue(*LLWidgetTypeRegistry::instance().getValue(widget_name)))(); + // LLXMLNodePtr root_nodep = new LLXMLNode(); + // LLRNGWriter().writeRNG(widget_name, root_nodep, block, "http://www.lindenlab.com/xui"); + + // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); + + // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), "w"); + // { + // LLXMLNode::writeHeaderToFile(rng_file); + // const bool use_type_decorations = false; + // root_nodep->writeToFile(rng_file, std::string(), use_type_decorations); + // } + // fclose(rng_file); + //} + //gViewerWindow->setCursor(UI_CURSOR_ARROW); } void LLFloaterUIPreview::onClickShowRectangles(const LLSD& data) { - LLPreviewedFloater::sShowRectangles = data.asBoolean(); + LLPreviewedFloater::sShowRectangles = data.asBoolean(); } // Close click handler -- delete my displayed floater if it exists void LLFloaterUIPreview::onClose(bool app_quitting) { - if(!app_quitting && mDisplayedFloater) - { - onClickCloseDisplayedFloater(PRIMARY_FLOATER); - onClickCloseDisplayedFloater(SECONDARY_FLOATER); - delete mDisplayedFloater; - mDisplayedFloater = NULL; - delete mDisplayedFloater_2; - mDisplayedFloater_2 = NULL; - } + if(!app_quitting && mDisplayedFloater) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + onClickCloseDisplayedFloater(SECONDARY_FLOATER); + delete mDisplayedFloater; + mDisplayedFloater = NULL; + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } } // Error handling (to avoid code repetition) // *TODO: this is currently unlocalized. Add to alerts/notifications.xml, someday, maybe. void LLFloaterUIPreview::popupAndPrintWarning(const std::string& warning) { - LL_WARNS() << warning << LL_ENDL; - LLSD args; - args["MESSAGE"] = warning; - LLNotificationsUtil::add("GenericAlert", args); + LL_WARNS() << warning << LL_ENDL; + LLSD args; + args["MESSAGE"] = warning; + LLNotificationsUtil::add("GenericAlert", args); } // Get localization string from drop-down menu std::string LLFloaterUIPreview::getLocStr(S32 ID) { - if(ID == 1) - { - return mLanguageSelection->getSelectedItemLabel(0); - } - else - { - return mLanguageSelection_2->getSelectedItemLabel(0); - } + if(ID == 1) + { + return mLanguageSelection->getSelectedItemLabel(0); + } + else + { + return mLanguageSelection_2->getSelectedItemLabel(0); + } } // Get localized directory (build path from data directory to XUI files, substituting localization string in for language) std::string LLFloaterUIPreview::getLocalizedDirectory() { - return get_xui_dir() + (getLocStr(1)) + mDelim; // e.g. "C:/Code/guipreview/indra/newview/skins/xui/en/"; + return get_xui_dir() + (getLocStr(1)) + mDelim; // e.g. "C:/Code/guipreview/indra/newview/skins/xui/en/"; } // Refresh the list of floaters by doing a directory traverse for XML XUI floater files // Could be used to grab any specific language's list of compatible floaters, but currently it's just used to get all of them void LLFloaterUIPreview::refreshList() { - // Note: the mask doesn't seem to accept regular expressions, so there need to be two directory searches here - mFileList->clearRows(); // empty list - std::string name; - BOOL found = TRUE; - - LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); - while(found) // for every floater file that matches the pattern - { - if((found = floater_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); - while(found) // for every inspector file that matches the pattern - { - if((found = inspect_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); - while(found) // for every menu file that matches the pattern - { - if((found = menu_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); - while(found) // for every panel file that matches the pattern - { - if((found = panel_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); - while(found) // for every sidepanel file that matches the pattern - { - if((found = sidepanel_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - - if(!mFileList->isEmpty()) // if there were any matching files, just select the first one (so we don't have to worry about disabling buttons when no entry is selected) - { - mFileList->selectFirstItem(); - } + // Note: the mask doesn't seem to accept regular expressions, so there need to be two directory searches here + mFileList->clearRows(); // empty list + std::string name; + BOOL found = TRUE; + + LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); + while(found) // for every floater file that matches the pattern + { + if((found = floater_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); + while(found) // for every inspector file that matches the pattern + { + if((found = inspect_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); + while(found) // for every menu file that matches the pattern + { + if((found = menu_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); + while(found) // for every panel file that matches the pattern + { + if((found = panel_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); + while(found) // for every sidepanel file that matches the pattern + { + if((found = sidepanel_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + + if(!mFileList->isEmpty()) // if there were any matching files, just select the first one (so we don't have to worry about disabling buttons when no entry is selected) + { + mFileList->selectFirstItem(); + } } // Add a single entry to the list of available floaters // Note: no deduplification (shouldn't be necessary) void LLFloaterUIPreview::addFloaterEntry(const std::string& path) { - LLUUID* entry_id = new LLUUID(); // create a new UUID - entry_id->generate(path); - const LLUUID& entry_id_ref = *entry_id; // get a reference to the UUID for the LLSD block - - // fill LLSD column entry: initialize row/col structure - LLSD row; - row["id"] = entry_id_ref; - LLSD& columns = row["columns"]; - - // Get name of floater: - LLXmlTree xml_tree; - std::string full_path = getLocalizedDirectory() + path; // get full path - BOOL success = xml_tree.parseFile(full_path.c_str(), TRUE); // parse xml - std::string entry_name; - std::string entry_title; - if(success) - { - // get root (or error handle) - LLXmlTreeNode* root_floater = xml_tree.getRoot(); - if (!root_floater) - { - std::string warning = std::string("No root node found in XUI file: ") + path; - popupAndPrintWarning(warning); - return; - } - - // get name - root_floater->getAttributeString("name",entry_name); - if(std::string("") == entry_name) - { - entry_name = "Error: unable to load " + std::string(path); // set to error state if load fails - } - - // get title - root_floater->getAttributeString("title",entry_title); // some don't have a title, and some have title = "(unknown)", so just leave it blank if it fails - } - else - { - std::string warning = std::string("Unable to parse XUI file: ") + path; // error handling - popupAndPrintWarning(warning); - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } - return; - } - - // Fill floater title column - columns[0]["column"] = "title_column"; - columns[0]["type"] = "text"; - columns[0]["value"] = entry_title; - - // Fill floater path column - columns[1]["column"] = "file_column"; - columns[1]["type"] = "text"; - columns[1]["value"] = std::string(path); - - // Fill floater name column - columns[2]["column"] = "top_level_node_column"; - columns[2]["type"] = "text"; - columns[2]["value"] = entry_name; - - mFileList->addElement(row); // actually add to list + LLUUID* entry_id = new LLUUID(); // create a new UUID + entry_id->generate(path); + const LLUUID& entry_id_ref = *entry_id; // get a reference to the UUID for the LLSD block + + // fill LLSD column entry: initialize row/col structure + LLSD row; + row["id"] = entry_id_ref; + LLSD& columns = row["columns"]; + + // Get name of floater: + LLXmlTree xml_tree; + std::string full_path = getLocalizedDirectory() + path; // get full path + BOOL success = xml_tree.parseFile(full_path.c_str(), TRUE); // parse xml + std::string entry_name; + std::string entry_title; + if(success) + { + // get root (or error handle) + LLXmlTreeNode* root_floater = xml_tree.getRoot(); + if (!root_floater) + { + std::string warning = std::string("No root node found in XUI file: ") + path; + popupAndPrintWarning(warning); + return; + } + + // get name + root_floater->getAttributeString("name",entry_name); + if(std::string("") == entry_name) + { + entry_name = "Error: unable to load " + std::string(path); // set to error state if load fails + } + + // get title + root_floater->getAttributeString("title",entry_title); // some don't have a title, and some have title = "(unknown)", so just leave it blank if it fails + } + else + { + std::string warning = std::string("Unable to parse XUI file: ") + path; // error handling + popupAndPrintWarning(warning); + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + return; + } + + // Fill floater title column + columns[0]["column"] = "title_column"; + columns[0]["type"] = "text"; + columns[0]["value"] = entry_title; + + // Fill floater path column + columns[1]["column"] = "file_column"; + columns[1]["type"] = "text"; + columns[1]["value"] = std::string(path); + + // Fill floater name column + columns[2]["column"] = "top_level_node_column"; + columns[2]["type"] = "text"; + columns[2]["value"] = entry_name; + + mFileList->addElement(row); // actually add to list } // Respond to button click to display/refresh currently-selected floater void LLFloaterUIPreview::onClickDisplayFloater(S32 caller_id) { - displayFloater(TRUE, caller_id); + displayFloater(TRUE, caller_id); } // Saves the current floater/panel void LLFloaterUIPreview::onClickSaveFloater(S32 caller_id) { - displayFloater(TRUE, caller_id); - popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); + displayFloater(TRUE, caller_id); + popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); } // Saves all floater/panels void LLFloaterUIPreview::onClickSaveAll(S32 caller_id) { - int listSize = mFileList->getItemCount(); - - for (int index = 0; index < listSize; index++) - { - mFileList->selectNthItem(index); - displayFloater(TRUE, caller_id); - } - popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); + int listSize = mFileList->getItemCount(); + + for (int index = 0; index < listSize; index++) + { + mFileList->selectNthItem(index); + displayFloater(TRUE, caller_id); + } + popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); } // Actually display the floater @@ -799,224 +799,224 @@ void LLFloaterUIPreview::onClickSaveAll(S32 caller_id) // otherwise, we get an infinite loop as the live file keeps recreating itself. That means this function is generally called twice. void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID) { - // Convince UI that we're in a different language (the one selected on the drop-down menu) - LLLocalizationResetForcer reset_forcer(this, ID); // save old language in reset forcer object (to be reset upon destruction when it falls out of scope) - - LLPreviewedFloater** floaterp = (ID == 1 ? &(mDisplayedFloater) : &(mDisplayedFloater_2)); - if(ID == 1) - { - BOOL floater_already_open = mDisplayedFloater != NULL; - if(floater_already_open) // if we are already displaying a floater - { - mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; // save floater's last known position to put the new one there - mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; - delete mDisplayedFloater; // delete it (this closes it too) - mDisplayedFloater = NULL; // and reset the pointer - } - } - else - { - if(mDisplayedFloater_2 != NULL) - { - delete mDisplayedFloater_2; - mDisplayedFloater_2 = NULL; - } - } - - std::string path = mFileList->getSelectedItemLabel(1); // get the path of the currently-selected floater - if(std::string("") == path) // if no item is selected - { - return; // ignore click (this can only happen with empty list; otherwise an item is always selected) - } - - LLFloater::Params p(LLFloater::getDefaultParams()); - p.min_height=p.header_height; - p.min_width=10; - - *floaterp = new LLPreviewedFloater(this, p); - - if(!strncmp(path.c_str(),"floater_",8) - || !strncmp(path.c_str(), "inspect_", 8)) // if it's a floater - { - (*floaterp)->buildFromFile(path); // just build it - (*floaterp)->openFloater((*floaterp)->getKey()); - (*floaterp)->setCanResize((*floaterp)->isResizable()); - } - else if (!strncmp(path.c_str(),"menu_",5)) // if it's a menu - { - // former 'save' processing excised - } - else // if it is a panel... - { - (*floaterp)->setCanResize(true); - - const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); - S32 floater_header_size = floater_params.header_height; - - LLPanel::Params panel_params; - LLPanel* panel = LLUICtrlFactory::create<LLPanel>(panel_params); // create a new panel - - panel->buildFromFile(path); // build it - panel->setOrigin(2,2); // reset its origin point so it's not offset by -left or other XUI attributes - (*floaterp)->setTitle(path); // use the file name as its title, since panels have no guaranteed meaningful name attribute - panel->setUseBoundingRect(TRUE); // enable the use of its outer bounding rect (normally disabled because it's O(n) on the number of sub-elements) - panel->updateBoundingRect(); // update bounding rect - LLRect bounding_rect = panel->getBoundingRect(); // get the bounding rect - LLRect new_rect = panel->getRect(); // get the panel's rect - new_rect.unionWith(bounding_rect); // union them to make sure we get the biggest one possible - LLRect floater_rect = new_rect; - floater_rect.stretch(4, 4); - (*floaterp)->reshape(floater_rect.getWidth(), floater_rect.getHeight() + floater_header_size); // reshape floater to match the union rect's dimensions - panel->reshape(new_rect.getWidth(), new_rect.getHeight()); // reshape panel to match the union rect's dimensions as well (both are needed) - (*floaterp)->addChild(panel); // add panel as child - (*floaterp)->openFloater(); // open floater (needed?) - } - - if(ID == 1) - { - (*floaterp)->setOrigin(mLastDisplayedX, mLastDisplayedY); - } - - // *HACK: Remove ability to close it; if you close it, its destructor gets called, but we don't know it's null and try to delete it again, - // resulting in a double free - (*floaterp)->setCanClose(FALSE); - - if(ID == 1) - { - mCloseOtherButton->setEnabled(TRUE); // enable my floater's close button - } - else - { - mCloseOtherButton_2->setEnabled(TRUE); - } - - // Add localization to title so user knows whether it's localized or defaulted to en - std::string full_path = getLocalizedDirectory() + path; - std::string floater_lang = "EN"; - llstat dummy; - if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist - { - floater_lang = getLocStr(ID); - } - std::string new_title = (*floaterp)->getTitle() + std::string(" [") + floater_lang + - (ID == 1 ? " - Primary" : " - Secondary") + std::string("]"); - (*floaterp)->setTitle(new_title); - - (*floaterp)->center(); - addDependentFloater(*floaterp); - - if(click && ID == 1) - { - // set up live file to track it - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } - mLiveFile = new LLGUIPreviewLiveFile(std::string(full_path.c_str()),std::string(path.c_str()),this); - mLiveFile->checkAndReload(); - mLiveFile->addToEventTimer(); - } - - if(ID == 1) - { - mToggleOverlapButton->setEnabled(TRUE); - } - - if(LLView::sHighlightingDiffs && click && ID == 1) - { - highlightChangedElements(); - } - - if(ID == 1) - { - mOverlapPanel->mOverlapMap.clear(); - LLView::sPreviewClickedElement = NULL; // stop overlapping elements from drawing - mOverlapPanel->mLastClickedElement = NULL; - findOverlapsInChildren((LLView*)mDisplayedFloater); - - // highlight and enable them - if(mHighlightingOverlaps) - { - for(LLOverlapPanel::OverlapMap::iterator iter = mOverlapPanel->mOverlapMap.begin(); iter != mOverlapPanel->mOverlapMap.end(); ++iter) - { - LLView* viewp = iter->first; - LLView::sPreviewHighlightedElements.insert(viewp); - } - } - else if(LLView::sHighlightingDiffs) - { - highlightChangedElements(); - } - } - - // NOTE: language is reset here automatically when the reset forcer object falls out of scope (see header for details) + // Convince UI that we're in a different language (the one selected on the drop-down menu) + LLLocalizationResetForcer reset_forcer(this, ID); // save old language in reset forcer object (to be reset upon destruction when it falls out of scope) + + LLPreviewedFloater** floaterp = (ID == 1 ? &(mDisplayedFloater) : &(mDisplayedFloater_2)); + if(ID == 1) + { + BOOL floater_already_open = mDisplayedFloater != NULL; + if(floater_already_open) // if we are already displaying a floater + { + mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; // save floater's last known position to put the new one there + mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; + delete mDisplayedFloater; // delete it (this closes it too) + mDisplayedFloater = NULL; // and reset the pointer + } + } + else + { + if(mDisplayedFloater_2 != NULL) + { + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } + } + + std::string path = mFileList->getSelectedItemLabel(1); // get the path of the currently-selected floater + if(std::string("") == path) // if no item is selected + { + return; // ignore click (this can only happen with empty list; otherwise an item is always selected) + } + + LLFloater::Params p(LLFloater::getDefaultParams()); + p.min_height=p.header_height; + p.min_width=10; + + *floaterp = new LLPreviewedFloater(this, p); + + if(!strncmp(path.c_str(),"floater_",8) + || !strncmp(path.c_str(), "inspect_", 8)) // if it's a floater + { + (*floaterp)->buildFromFile(path); // just build it + (*floaterp)->openFloater((*floaterp)->getKey()); + (*floaterp)->setCanResize((*floaterp)->isResizable()); + } + else if (!strncmp(path.c_str(),"menu_",5)) // if it's a menu + { + // former 'save' processing excised + } + else // if it is a panel... + { + (*floaterp)->setCanResize(true); + + const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); + S32 floater_header_size = floater_params.header_height; + + LLPanel::Params panel_params; + LLPanel* panel = LLUICtrlFactory::create<LLPanel>(panel_params); // create a new panel + + panel->buildFromFile(path); // build it + panel->setOrigin(2,2); // reset its origin point so it's not offset by -left or other XUI attributes + (*floaterp)->setTitle(path); // use the file name as its title, since panels have no guaranteed meaningful name attribute + panel->setUseBoundingRect(TRUE); // enable the use of its outer bounding rect (normally disabled because it's O(n) on the number of sub-elements) + panel->updateBoundingRect(); // update bounding rect + LLRect bounding_rect = panel->getBoundingRect(); // get the bounding rect + LLRect new_rect = panel->getRect(); // get the panel's rect + new_rect.unionWith(bounding_rect); // union them to make sure we get the biggest one possible + LLRect floater_rect = new_rect; + floater_rect.stretch(4, 4); + (*floaterp)->reshape(floater_rect.getWidth(), floater_rect.getHeight() + floater_header_size); // reshape floater to match the union rect's dimensions + panel->reshape(new_rect.getWidth(), new_rect.getHeight()); // reshape panel to match the union rect's dimensions as well (both are needed) + (*floaterp)->addChild(panel); // add panel as child + (*floaterp)->openFloater(); // open floater (needed?) + } + + if(ID == 1) + { + (*floaterp)->setOrigin(mLastDisplayedX, mLastDisplayedY); + } + + // *HACK: Remove ability to close it; if you close it, its destructor gets called, but we don't know it's null and try to delete it again, + // resulting in a double free + (*floaterp)->setCanClose(FALSE); + + if(ID == 1) + { + mCloseOtherButton->setEnabled(TRUE); // enable my floater's close button + } + else + { + mCloseOtherButton_2->setEnabled(TRUE); + } + + // Add localization to title so user knows whether it's localized or defaulted to en + std::string full_path = getLocalizedDirectory() + path; + std::string floater_lang = "EN"; + llstat dummy; + if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist + { + floater_lang = getLocStr(ID); + } + std::string new_title = (*floaterp)->getTitle() + std::string(" [") + floater_lang + + (ID == 1 ? " - Primary" : " - Secondary") + std::string("]"); + (*floaterp)->setTitle(new_title); + + (*floaterp)->center(); + addDependentFloater(*floaterp); + + if(click && ID == 1) + { + // set up live file to track it + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + mLiveFile = new LLGUIPreviewLiveFile(std::string(full_path.c_str()),std::string(path.c_str()),this); + mLiveFile->checkAndReload(); + mLiveFile->addToEventTimer(); + } + + if(ID == 1) + { + mToggleOverlapButton->setEnabled(TRUE); + } + + if(LLView::sHighlightingDiffs && click && ID == 1) + { + highlightChangedElements(); + } + + if(ID == 1) + { + mOverlapPanel->mOverlapMap.clear(); + LLView::sPreviewClickedElement = NULL; // stop overlapping elements from drawing + mOverlapPanel->mLastClickedElement = NULL; + findOverlapsInChildren((LLView*)mDisplayedFloater); + + // highlight and enable them + if(mHighlightingOverlaps) + { + for(LLOverlapPanel::OverlapMap::iterator iter = mOverlapPanel->mOverlapMap.begin(); iter != mOverlapPanel->mOverlapMap.end(); ++iter) + { + LLView* viewp = iter->first; + LLView::sPreviewHighlightedElements.insert(viewp); + } + } + else if(LLView::sHighlightingDiffs) + { + highlightChangedElements(); + } + } + + // NOTE: language is reset here automatically when the reset forcer object falls out of scope (see header for details) } // Respond to button click to edit currently-selected floater void LLFloaterUIPreview::onClickEditFloater() { - // Determine file to edit. - std::string file_path; - { - std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater - if (file_name.empty()) // if no item is selected - { - LL_WARNS() << "No file selected" << LL_ENDL; - return; // ignore click - } - file_path = getLocalizedDirectory() + file_name; - - // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) - llstat dummy; - if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist - { - popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead."); - file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default - } - } - - // Set the editor command. - std::string cmd_override; - { - std::string bin = mEditorPathTextBox->getText(); - if (!bin.empty()) - { - // surround command with double quotes for the case if the path contains spaces - if (bin.find("\"") == std::string::npos) - { - bin = "\"" + bin + "\""; - } - - std::string args = mEditorArgsTextBox->getText(); - cmd_override = bin + " " + args; - } - } - - LLExternalEditor::EErrorCode status = mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override); - if (status != LLExternalEditor::EC_SUCCESS) - { - std::string warning; - - if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error. - { - warning = getString("ExternalEditorNotSet"); - } - else - { - warning = LLExternalEditor::getErrorMessage(status); - } - - popupAndPrintWarning(warning); - return; - } - - // Run the editor. - if (mExternalEditor.run(file_path) != LLExternalEditor::EC_SUCCESS) - { - popupAndPrintWarning(LLExternalEditor::getErrorMessage(status)); - return; - } + // Determine file to edit. + std::string file_path; + { + std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater + if (file_name.empty()) // if no item is selected + { + LL_WARNS() << "No file selected" << LL_ENDL; + return; // ignore click + } + file_path = getLocalizedDirectory() + file_name; + + // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) + llstat dummy; + if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist + { + popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead."); + file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default + } + } + + // Set the editor command. + std::string cmd_override; + { + std::string bin = mEditorPathTextBox->getText(); + if (!bin.empty()) + { + // surround command with double quotes for the case if the path contains spaces + if (bin.find("\"") == std::string::npos) + { + bin = "\"" + bin + "\""; + } + + std::string args = mEditorArgsTextBox->getText(); + cmd_override = bin + " " + args; + } + } + + LLExternalEditor::EErrorCode status = mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override); + if (status != LLExternalEditor::EC_SUCCESS) + { + std::string warning; + + if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error. + { + warning = getString("ExternalEditorNotSet"); + } + else + { + warning = LLExternalEditor::getErrorMessage(status); + } + + popupAndPrintWarning(warning); + return; + } + + // Run the editor. + if (mExternalEditor.run(file_path) != LLExternalEditor::EC_SUCCESS) + { + popupAndPrintWarning(LLExternalEditor::getErrorMessage(status)); + return; + } } // Respond to button click to browse for an executable with which to edit XML files @@ -1028,398 +1028,398 @@ void LLFloaterUIPreview::onClickBrowseForEditor() void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filenames) { - // put the selected path into text field - const std::string chosen_path = filenames[0]; - std::string executable_path = chosen_path; + // put the selected path into text field + const std::string chosen_path = filenames[0]; + std::string executable_path = chosen_path; #if LL_DARWIN - // on Mac, if it's an application bundle, figure out the actual path from the Info.plist file - CFStringRef path_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, chosen_path.c_str(), kCFStringEncodingMacRoman); // get path as a CFStringRef - CFURLRef path_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_cfstr, kCFURLPOSIXPathStyle, TRUE); // turn it into a CFURLRef - CFBundleRef chosen_bundle = CFBundleCreate(kCFAllocatorDefault, path_url); // get a handle for the bundle - if(NULL != chosen_bundle) - { - CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(chosen_bundle); // get the bundle's dictionary - if(NULL != bundleInfoDict) - { - CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) - int max_file_length = 256; // (max file name length is 255 in OSX) - char executable_buf[max_file_length]; - if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* - { - executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path - } - else - { - std::string warning = "Unable to get CString from CFString for executable path"; - popupAndPrintWarning(warning); - } - } - else - { - std::string warning = "Unable to get bundle info dictionary from application bundle"; - popupAndPrintWarning(warning); - } - } - else - { - if(-1 != executable_path.find(".app")) // only warn if this path actually had ".app" in it, i.e. it probably just wasn'nt an app bundle and that's okay - { - std::string warning = std::string("Unable to get bundle from path \"") + chosen_path + std::string("\""); - popupAndPrintWarning(warning); - } - } + // on Mac, if it's an application bundle, figure out the actual path from the Info.plist file + CFStringRef path_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, chosen_path.c_str(), kCFStringEncodingMacRoman); // get path as a CFStringRef + CFURLRef path_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_cfstr, kCFURLPOSIXPathStyle, TRUE); // turn it into a CFURLRef + CFBundleRef chosen_bundle = CFBundleCreate(kCFAllocatorDefault, path_url); // get a handle for the bundle + if(NULL != chosen_bundle) + { + CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(chosen_bundle); // get the bundle's dictionary + if(NULL != bundleInfoDict) + { + CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) + int max_file_length = 256; // (max file name length is 255 in OSX) + char executable_buf[max_file_length]; + if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* + { + executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path + } + else + { + std::string warning = "Unable to get CString from CFString for executable path"; + popupAndPrintWarning(warning); + } + } + else + { + std::string warning = "Unable to get bundle info dictionary from application bundle"; + popupAndPrintWarning(warning); + } + } + else + { + if(-1 != executable_path.find(".app")) // only warn if this path actually had ".app" in it, i.e. it probably just wasn'nt an app bundle and that's okay + { + std::string warning = std::string("Unable to get bundle from path \"") + chosen_path + std::string("\""); + popupAndPrintWarning(warning); + } + } #endif - mEditorPathTextBox->setText(std::string(executable_path)); // copy the path to the executable to the textfield for display and later fetching + mEditorPathTextBox->setText(std::string(executable_path)); // copy the path to the executable to the textfield for display and later fetching } // Respond to button click to browse for a VLT-generated diffs file void LLFloaterUIPreview::onClickBrowseForDiffs() { - // create load dialog box + // create load dialog box LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterUIPreview::getDiffsFilePath(const std::vector<std::string>& filenames) { - // put the selected path into text field - const std::string chosen_path = filenames[0]; - mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching - if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file - { - onClickToggleDiffHighlighting(); - onClickToggleDiffHighlighting(); - } + // put the selected path into text field + const std::string chosen_path = filenames[0]; + mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching + if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file + { + onClickToggleDiffHighlighting(); + onClickToggleDiffHighlighting(); + } } void LLFloaterUIPreview::onClickToggleDiffHighlighting() { - if(mHighlightingOverlaps) - { - onClickToggleOverlapping(); - mToggleOverlapButton->toggleState(); - } - - LLView::sPreviewHighlightedElements.clear(); // clear lists first - mDiffsMap.clear(); - mFileList->clearHighlightedItems(); - - if(LLView::sHighlightingDiffs) // Turning highlighting off - { - LLView::sHighlightingDiffs = !sHighlightingDiffs; - return; - } - else // Turning highlighting on - { - // Get the file and make sure it exists - std::string path_in_textfield = mDiffPathTextBox->getText(); // get file path - BOOL error = FALSE; - - if(std::string("") == path_in_textfield) // check for blank file - { - std::string warning = "Unable to highlight differences because no file was provided; fill in the relevant text field"; - popupAndPrintWarning(warning); - error = TRUE; - } - - llstat dummy; - if(LLFile::stat(path_in_textfield.c_str(), &dummy) && !error) // check if the file exists (empty check is reduntant but useful for the informative error message) - { - std::string warning = std::string("Unable to highlight differences because an invalid path to a difference file was provided:\"") + path_in_textfield + "\""; - popupAndPrintWarning(warning); - error = TRUE; - } - - // Build a list of changed elements as given by the XML - std::list<std::string> changed_element_names; - LLXmlTree xml_tree; - BOOL success = xml_tree.parseFile(path_in_textfield.c_str(), TRUE); - - if(success && !error) - { - LLXmlTreeNode* root_floater = xml_tree.getRoot(); - if(!strncmp("XuiDelta",root_floater->getName().c_str(),9)) - { - for (LLXmlTreeNode* child = root_floater->getFirstChild(); // get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) - child != NULL; - child = root_floater->getNextChild()) // get child for next iteration - { - if(!strncmp("file",child->getName().c_str(),5)) - { - scanDiffFile(child); - } - else if(!strncmp("error",child->getName().c_str(),6)) - { - std::string error_file, error_message; - child->getAttributeString("filename",error_file); - child->getAttributeString("message",error_message); - if(mDiffsMap.find(error_file) != mDiffsMap.end()) - { - mDiffsMap.insert(std::make_pair(error_file,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); - } - mDiffsMap[error_file].second->push_back(error_message); - } - else - { - std::string warning = std::string("Child was neither a file or an error, but rather the following:\"") + std::string(child->getName()) + "\""; - popupAndPrintWarning(warning); - error = TRUE; - break; - } - } - } - else - { - std::string warning = std::string("Root node not named XuiDelta:\"") + path_in_textfield + "\""; - popupAndPrintWarning(warning); - error = TRUE; - } - } - else if(!error) - { - std::string warning = std::string("Unable to create tree from XML:\"") + path_in_textfield + "\""; - popupAndPrintWarning(warning); - error = TRUE; - } - - if(error) // if we encountered an error, reset the button to off - { - mToggleHighlightButton->setToggleState(FALSE); - } - else // only toggle if we didn't encounter an error - { - LLView::sHighlightingDiffs = !sHighlightingDiffs; - highlightChangedElements(); // *TODO: this is extraneous, right? - highlightChangedFiles(); // *TODO: this is extraneous, right? - } - } + if(mHighlightingOverlaps) + { + onClickToggleOverlapping(); + mToggleOverlapButton->toggleState(); + } + + LLView::sPreviewHighlightedElements.clear(); // clear lists first + mDiffsMap.clear(); + mFileList->clearHighlightedItems(); + + if(LLView::sHighlightingDiffs) // Turning highlighting off + { + LLView::sHighlightingDiffs = !sHighlightingDiffs; + return; + } + else // Turning highlighting on + { + // Get the file and make sure it exists + std::string path_in_textfield = mDiffPathTextBox->getText(); // get file path + BOOL error = FALSE; + + if(std::string("") == path_in_textfield) // check for blank file + { + std::string warning = "Unable to highlight differences because no file was provided; fill in the relevant text field"; + popupAndPrintWarning(warning); + error = TRUE; + } + + llstat dummy; + if(LLFile::stat(path_in_textfield.c_str(), &dummy) && !error) // check if the file exists (empty check is reduntant but useful for the informative error message) + { + std::string warning = std::string("Unable to highlight differences because an invalid path to a difference file was provided:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + + // Build a list of changed elements as given by the XML + std::list<std::string> changed_element_names; + LLXmlTree xml_tree; + BOOL success = xml_tree.parseFile(path_in_textfield.c_str(), TRUE); + + if(success && !error) + { + LLXmlTreeNode* root_floater = xml_tree.getRoot(); + if(!strncmp("XuiDelta",root_floater->getName().c_str(),9)) + { + for (LLXmlTreeNode* child = root_floater->getFirstChild(); // get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) + child != NULL; + child = root_floater->getNextChild()) // get child for next iteration + { + if(!strncmp("file",child->getName().c_str(),5)) + { + scanDiffFile(child); + } + else if(!strncmp("error",child->getName().c_str(),6)) + { + std::string error_file, error_message; + child->getAttributeString("filename",error_file); + child->getAttributeString("message",error_message); + if(mDiffsMap.find(error_file) != mDiffsMap.end()) + { + mDiffsMap.insert(std::make_pair(error_file,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); + } + mDiffsMap[error_file].second->push_back(error_message); + } + else + { + std::string warning = std::string("Child was neither a file or an error, but rather the following:\"") + std::string(child->getName()) + "\""; + popupAndPrintWarning(warning); + error = TRUE; + break; + } + } + } + else + { + std::string warning = std::string("Root node not named XuiDelta:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + } + else if(!error) + { + std::string warning = std::string("Unable to create tree from XML:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + + if(error) // if we encountered an error, reset the button to off + { + mToggleHighlightButton->setToggleState(FALSE); + } + else // only toggle if we didn't encounter an error + { + LLView::sHighlightingDiffs = !sHighlightingDiffs; + highlightChangedElements(); // *TODO: this is extraneous, right? + highlightChangedFiles(); // *TODO: this is extraneous, right? + } + } } void LLFloaterUIPreview::scanDiffFile(LLXmlTreeNode* file_node) { - // Get file name - std::string file_name; - file_node->getAttributeString("name",file_name); - if(std::string("") == file_name) - { - std::string warning = std::string("Empty file name encountered in differences:\"") + file_name + "\""; - popupAndPrintWarning(warning); - return; - } - - // Get a list of changed elements - // Get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) - for (LLXmlTreeNode* child = file_node->getFirstChild(); child != NULL; child = file_node->getNextChild()) - { - if(!strncmp("delta",child->getName().c_str(),6)) - { - std::string id; - child->getAttributeString("id",id); - if(mDiffsMap.find(file_name) == mDiffsMap.end()) - { - mDiffsMap.insert(std::make_pair(file_name,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); - } - mDiffsMap[file_name].first->push_back(std::string(id.c_str())); - } - else - { - std::string warning = std::string("Child of file was not a delta, but rather the following:\"") + std::string(child->getName()) + "\""; - popupAndPrintWarning(warning); - return; - } - } + // Get file name + std::string file_name; + file_node->getAttributeString("name",file_name); + if(std::string("") == file_name) + { + std::string warning = std::string("Empty file name encountered in differences:\"") + file_name + "\""; + popupAndPrintWarning(warning); + return; + } + + // Get a list of changed elements + // Get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) + for (LLXmlTreeNode* child = file_node->getFirstChild(); child != NULL; child = file_node->getNextChild()) + { + if(!strncmp("delta",child->getName().c_str(),6)) + { + std::string id; + child->getAttributeString("id",id); + if(mDiffsMap.find(file_name) == mDiffsMap.end()) + { + mDiffsMap.insert(std::make_pair(file_name,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); + } + mDiffsMap[file_name].first->push_back(std::string(id.c_str())); + } + else + { + std::string warning = std::string("Child of file was not a delta, but rather the following:\"") + std::string(child->getName()) + "\""; + popupAndPrintWarning(warning); + return; + } + } } void LLFloaterUIPreview::highlightChangedElements() { - if(NULL == mLiveFile) - { - return; - } - - // Process differences first (we want their warnings to be shown underneath other warnings) - StringListPtr changed_element_paths; - DiffMap::iterator iterExists = mDiffsMap.find(mLiveFile->mFileName); - if(iterExists != mDiffsMap.end()) - { - changed_element_paths = mDiffsMap[mLiveFile->mFileName].first; // retrieve list of changed element paths from map - } - - for(std::list<std::string>::iterator iter = changed_element_paths->begin(); iter != changed_element_paths->end(); ++iter) // for every changed element path - { - LLView* element = mDisplayedFloater; - if(!strncmp(iter->c_str(),".",1)) // if it's the root floater itself - { - continue; - } - - // Split element hierarchy path on period (*HACK: it's possible that the element name will have a period in it, in which case this won't work. See https://wiki.lindenlab.com/wiki/Viewer_Localization_Tool_Documentation.) - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("."); - tokenizer tokens(*iter, sep); - tokenizer::iterator token_iter; - BOOL failed = FALSE; - for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - element = element->findChild<LLView>(*token_iter,FALSE); // try to find element: don't recur, and don't create if missing - - // if we still didn't find it... - if(NULL == element) - { - LL_INFOS() << "Unable to find element in XuiDelta file named \"" << *iter << "\" in file \"" << mLiveFile->mFileName << - "\". The element may no longer exist, the path may be incorrect, or it may not be a non-displayable element (not an LLView) such as a \"string\" type." << LL_ENDL; - failed = TRUE; - break; - } - } - - if(!failed) - { - // Now that we have a pointer to the actual element, add it to the list of elements to be highlighted - std::set<LLView*>::iterator iter2 = std::find(LLView::sPreviewHighlightedElements.begin(), LLView::sPreviewHighlightedElements.end(), element); - if(iter2 == LLView::sPreviewHighlightedElements.end()) - { - LLView::sPreviewHighlightedElements.insert(element); - } - } - } - - // Process errors second, so their warnings show up on top of other warnings - StringListPtr error_list; - if(iterExists != mDiffsMap.end()) - { - error_list = mDiffsMap[mLiveFile->mFileName].second; - } - for(std::list<std::string>::iterator iter = error_list->begin(); iter != error_list->end(); ++iter) // for every changed element path - { - std::string warning = std::string("Error listed among differences. Filename: \"") + mLiveFile->mFileName + "\". Message: \"" + *iter + "\""; - popupAndPrintWarning(warning); - } + if(NULL == mLiveFile) + { + return; + } + + // Process differences first (we want their warnings to be shown underneath other warnings) + StringListPtr changed_element_paths; + DiffMap::iterator iterExists = mDiffsMap.find(mLiveFile->mFileName); + if(iterExists != mDiffsMap.end()) + { + changed_element_paths = mDiffsMap[mLiveFile->mFileName].first; // retrieve list of changed element paths from map + } + + for(std::list<std::string>::iterator iter = changed_element_paths->begin(); iter != changed_element_paths->end(); ++iter) // for every changed element path + { + LLView* element = mDisplayedFloater; + if(!strncmp(iter->c_str(),".",1)) // if it's the root floater itself + { + continue; + } + + // Split element hierarchy path on period (*HACK: it's possible that the element name will have a period in it, in which case this won't work. See https://wiki.lindenlab.com/wiki/Viewer_Localization_Tool_Documentation.) + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("."); + tokenizer tokens(*iter, sep); + tokenizer::iterator token_iter; + BOOL failed = FALSE; + for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + element = element->findChild<LLView>(*token_iter,FALSE); // try to find element: don't recur, and don't create if missing + + // if we still didn't find it... + if(NULL == element) + { + LL_INFOS() << "Unable to find element in XuiDelta file named \"" << *iter << "\" in file \"" << mLiveFile->mFileName << + "\". The element may no longer exist, the path may be incorrect, or it may not be a non-displayable element (not an LLView) such as a \"string\" type." << LL_ENDL; + failed = TRUE; + break; + } + } + + if(!failed) + { + // Now that we have a pointer to the actual element, add it to the list of elements to be highlighted + std::set<LLView*>::iterator iter2 = std::find(LLView::sPreviewHighlightedElements.begin(), LLView::sPreviewHighlightedElements.end(), element); + if(iter2 == LLView::sPreviewHighlightedElements.end()) + { + LLView::sPreviewHighlightedElements.insert(element); + } + } + } + + // Process errors second, so their warnings show up on top of other warnings + StringListPtr error_list; + if(iterExists != mDiffsMap.end()) + { + error_list = mDiffsMap[mLiveFile->mFileName].second; + } + for(std::list<std::string>::iterator iter = error_list->begin(); iter != error_list->end(); ++iter) // for every changed element path + { + std::string warning = std::string("Error listed among differences. Filename: \"") + mLiveFile->mFileName + "\". Message: \"" + *iter + "\""; + popupAndPrintWarning(warning); + } } void LLFloaterUIPreview::highlightChangedFiles() { - for(DiffMap::iterator iter = mDiffsMap.begin(); iter != mDiffsMap.end(); ++iter) // for every file listed in diffs - { - LLScrollListItem* item = mFileList->getItemByLabel(std::string(iter->first), FALSE, 1); - if(item) - { - item->setHighlighted(TRUE); - } - } + for(DiffMap::iterator iter = mDiffsMap.begin(); iter != mDiffsMap.end(); ++iter) // for every file listed in diffs + { + LLScrollListItem* item = mFileList->getItemByLabel(std::string(iter->first), FALSE, 1); + if(item) + { + item->setHighlighted(TRUE); + } + } } // Respond to button click to browse for an executable with which to edit XML files void LLFloaterUIPreview::onClickCloseDisplayedFloater(S32 caller_id) { - if(caller_id == PRIMARY_FLOATER) - { - mCloseOtherButton->setEnabled(FALSE); - mToggleOverlapButton->setEnabled(FALSE); - - if(mDisplayedFloater) - { - mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; - mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; - delete mDisplayedFloater; - mDisplayedFloater = NULL; - } - - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } - - if(mToggleOverlapButton->getToggleState()) - { - mToggleOverlapButton->toggleState(); - onClickToggleOverlapping(); - } - - LLView::sPreviewClickedElement = NULL; // stop overlapping elements panel from drawing - mOverlapPanel->mLastClickedElement = NULL; - } - else - { - mCloseOtherButton_2->setEnabled(FALSE); - delete mDisplayedFloater_2; - mDisplayedFloater_2 = NULL; - } + if(caller_id == PRIMARY_FLOATER) + { + mCloseOtherButton->setEnabled(FALSE); + mToggleOverlapButton->setEnabled(FALSE); + + if(mDisplayedFloater) + { + mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; + mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; + delete mDisplayedFloater; + mDisplayedFloater = NULL; + } + + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + + if(mToggleOverlapButton->getToggleState()) + { + mToggleOverlapButton->toggleState(); + onClickToggleOverlapping(); + } + + LLView::sPreviewClickedElement = NULL; // stop overlapping elements panel from drawing + mOverlapPanel->mLastClickedElement = NULL; + } + else + { + mCloseOtherButton_2->setEnabled(FALSE); + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } } void append_view_tooltip(LLView* tooltip_view, std::string *tooltip_msg) { - LLRect rect = tooltip_view->getRect(); - LLRect parent_rect = tooltip_view->getParent()->getRect(); - S32 left = rect.mLeft; - // invert coordinate system for XUI top-left layout - S32 top = parent_rect.getHeight() - rect.mTop; - if (!tooltip_msg->empty()) - { - tooltip_msg->append("\n"); - } - std::string msg = llformat("%s %d, %d (%d x %d)", - tooltip_view->getName().c_str(), - left, - top, - rect.getWidth(), - rect.getHeight() ); - tooltip_msg->append( msg ); + LLRect rect = tooltip_view->getRect(); + LLRect parent_rect = tooltip_view->getParent()->getRect(); + S32 left = rect.mLeft; + // invert coordinate system for XUI top-left layout + S32 top = parent_rect.getHeight() - rect.mTop; + if (!tooltip_msg->empty()) + { + tooltip_msg->append("\n"); + } + std::string msg = llformat("%s %d, %d (%d x %d)", + tooltip_view->getName().c_str(), + left, + top, + rect.getWidth(), + rect.getHeight() ); + tooltip_msg->append( msg ); } BOOL LLPreviewedFloater::handleToolTip(S32 x, S32 y, MASK mask) { - if (!sShowRectangles) - { - return LLFloater::handleToolTip(x, y, mask); - } - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - std::string tooltip_msg; - LLView* tooltip_view = this; - LLView::tree_iterator_t end_it = endTreeDFS(); - for (LLView::tree_iterator_t it = beginTreeDFS(); it != end_it; ++it) - { - LLView* viewp = *it; - LLRect screen_rect; - viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect); - if (!(viewp->getVisible() - && screen_rect.pointInRect(screen_x, screen_y))) - { - it.skipDescendants(); - } - // only report xui names for LLUICtrls, not the various container LLViews - - else if (dynamic_cast<LLUICtrl*>(viewp)) - { - // if we are in a new part of the tree (not a descendent of current tooltip_view) - // then push the results for tooltip_view and start with a new potential view - // NOTE: this emulates visiting only the leaf nodes that meet our criteria - - if (tooltip_view != this - && !viewp->hasAncestor(tooltip_view)) - { - append_view_tooltip(tooltip_view, &tooltip_msg); - } - tooltip_view = viewp; - } - } - - append_view_tooltip(tooltip_view, &tooltip_msg); - - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tooltip_msg) - .max_width(400)); - return TRUE; + if (!sShowRectangles) + { + return LLFloater::handleToolTip(x, y, mask); + } + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + std::string tooltip_msg; + LLView* tooltip_view = this; + LLView::tree_iterator_t end_it = endTreeDFS(); + for (LLView::tree_iterator_t it = beginTreeDFS(); it != end_it; ++it) + { + LLView* viewp = *it; + LLRect screen_rect; + viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect); + if (!(viewp->getVisible() + && screen_rect.pointInRect(screen_x, screen_y))) + { + it.skipDescendants(); + } + // only report xui names for LLUICtrls, not the various container LLViews + + else if (dynamic_cast<LLUICtrl*>(viewp)) + { + // if we are in a new part of the tree (not a descendent of current tooltip_view) + // then push the results for tooltip_view and start with a new potential view + // NOTE: this emulates visiting only the leaf nodes that meet our criteria + + if (tooltip_view != this + && !viewp->hasAncestor(tooltip_view)) + { + append_view_tooltip(tooltip_view, &tooltip_msg); + } + tooltip_view = viewp; + } + } + + append_view_tooltip(tooltip_view, &tooltip_msg); + + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(tooltip_msg) + .max_width(400)); + return TRUE; } BOOL LLPreviewedFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) { - selectElement(this,x,y,0); - return TRUE; + selectElement(this,x,y,0); + return TRUE; } // *NOTE: In order to hide all of the overlapping elements of the selected element so as to see it in context, here is what you would need to do: @@ -1433,131 +1433,131 @@ BOOL LLPreviewedFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) // ~Jacob, 8/08 BOOL LLPreviewedFloater::selectElement(LLView* parent, int x, int y, int depth) { - if(getVisible()) - { - BOOL handled = FALSE; - if(LLFloaterUIPreview::containerType(parent)) - { - for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) - { - LLView* child = *child_it; - S32 local_x = x - child->getRect().mLeft; - S32 local_y = y - child->getRect().mBottom; - if (child->pointInView(local_x, local_y) && - child->getVisible() && - selectElement(child, x, y, ++depth)) - { - handled = TRUE; - break; - } - } - } - - if(!handled) - { - LLView::sPreviewClickedElement = parent; - } - return TRUE; - } - else - { - return FALSE; - } + if(getVisible()) + { + BOOL handled = FALSE; + if(LLFloaterUIPreview::containerType(parent)) + { + for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) + { + LLView* child = *child_it; + S32 local_x = x - child->getRect().mLeft; + S32 local_y = y - child->getRect().mBottom; + if (child->pointInView(local_x, local_y) && + child->getVisible() && + selectElement(child, x, y, ++depth)) + { + handled = TRUE; + break; + } + } + } + + if(!handled) + { + LLView::sPreviewClickedElement = parent; + } + return TRUE; + } + else + { + return FALSE; + } } void LLPreviewedFloater::draw() { - if(NULL != mFloaterUIPreview) - { - // Set and unset sDrawPreviewHighlights flag so as to avoid using two flags - if(mFloaterUIPreview->mHighlightingOverlaps) - { - LLView::sDrawPreviewHighlights = TRUE; - } - - // If we're looking for truncations, draw debug rects for the displayed - // floater only. - bool old_debug_rects = LLView::sDebugRects; - bool old_show_names = LLView::sDebugRectsShowNames; - if (sShowRectangles) - { - LLView::sDebugRects = true; - LLView::sDebugRectsShowNames = false; - } - - LLFloater::draw(); - - LLView::sDebugRects = old_debug_rects; - LLView::sDebugRectsShowNames = old_show_names; - - if(mFloaterUIPreview->mHighlightingOverlaps) - { - LLView::sDrawPreviewHighlights = FALSE; - } - } + if(NULL != mFloaterUIPreview) + { + // Set and unset sDrawPreviewHighlights flag so as to avoid using two flags + if(mFloaterUIPreview->mHighlightingOverlaps) + { + LLView::sDrawPreviewHighlights = TRUE; + } + + // If we're looking for truncations, draw debug rects for the displayed + // floater only. + bool old_debug_rects = LLView::sDebugRects; + bool old_show_names = LLView::sDebugRectsShowNames; + if (sShowRectangles) + { + LLView::sDebugRects = true; + LLView::sDebugRectsShowNames = false; + } + + LLFloater::draw(); + + LLView::sDebugRects = old_debug_rects; + LLView::sDebugRectsShowNames = old_show_names; + + if(mFloaterUIPreview->mHighlightingOverlaps) + { + LLView::sDrawPreviewHighlights = FALSE; + } + } } void LLFloaterUIPreview::onClickToggleOverlapping() { - if(LLView::sHighlightingDiffs) - { - onClickToggleDiffHighlighting(); - mToggleHighlightButton->toggleState(); - } - LLView::sPreviewHighlightedElements.clear(); // clear lists first - - S32 width, height; - getResizeLimits(&width, &height); // illegal call of non-static member function - if(mHighlightingOverlaps) - { - mHighlightingOverlaps = !mHighlightingOverlaps; - // reset list of preview highlighted elements - setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight - mOverlapPanel->getRect().getWidth(),getRect().mBottom)); - setResizeLimits(width - mOverlapPanel->getRect().getWidth(), height); - } - else - { - mHighlightingOverlaps = !mHighlightingOverlaps; - displayFloater(FALSE,1); - setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight + mOverlapPanel->getRect().getWidth(),getRect().mBottom)); - setResizeLimits(width + mOverlapPanel->getRect().getWidth(), height); - } - getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); + if(LLView::sHighlightingDiffs) + { + onClickToggleDiffHighlighting(); + mToggleHighlightButton->toggleState(); + } + LLView::sPreviewHighlightedElements.clear(); // clear lists first + + S32 width, height; + getResizeLimits(&width, &height); // illegal call of non-static member function + if(mHighlightingOverlaps) + { + mHighlightingOverlaps = !mHighlightingOverlaps; + // reset list of preview highlighted elements + setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight - mOverlapPanel->getRect().getWidth(),getRect().mBottom)); + setResizeLimits(width - mOverlapPanel->getRect().getWidth(), height); + } + else + { + mHighlightingOverlaps = !mHighlightingOverlaps; + displayFloater(FALSE,1); + setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight + mOverlapPanel->getRect().getWidth(),getRect().mBottom)); + setResizeLimits(width + mOverlapPanel->getRect().getWidth(), height); + } + getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); } void LLFloaterUIPreview::findOverlapsInChildren(LLView* parent) { - if(parent->getChildCount() == 0 || !containerType(parent)) // if it has no children or isn't a container type, skip it - { - return; - } - - // for every child of the parent - for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) - { - LLView* child = *child_it; - if(overlapIgnorable(child)) - { - continue; - } - - // for every sibling - for(child_list_const_iter_t sibling_it = parent->getChildList()->begin(); sibling_it != parent->getChildList()->end(); ++sibling_it) // for each sibling - { - LLView* sibling = *sibling_it; - if(overlapIgnorable(sibling)) - { - continue; - } - - // if they overlap... (we don't care if they're visible or enabled -- we want to check those anyway, i.e. hidden tabs that can be later shown) - if(sibling != child && elementOverlap(child, sibling)) - { - mOverlapPanel->mOverlapMap[child].push_back(sibling); // add to the map - } - } - findOverlapsInChildren(child); // recur - } + if(parent->getChildCount() == 0 || !containerType(parent)) // if it has no children or isn't a container type, skip it + { + return; + } + + // for every child of the parent + for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) + { + LLView* child = *child_it; + if(overlapIgnorable(child)) + { + continue; + } + + // for every sibling + for(child_list_const_iter_t sibling_it = parent->getChildList()->begin(); sibling_it != parent->getChildList()->end(); ++sibling_it) // for each sibling + { + LLView* sibling = *sibling_it; + if(overlapIgnorable(sibling)) + { + continue; + } + + // if they overlap... (we don't care if they're visible or enabled -- we want to check those anyway, i.e. hidden tabs that can be later shown) + if(sibling != child && elementOverlap(child, sibling)) + { + mOverlapPanel->mOverlapMap[child].push_back(sibling); // add to the map + } + } + findOverlapsInChildren(child); // recur + } } // *HACK: don't overlap with the drag handle and various other elements @@ -1565,153 +1565,153 @@ void LLFloaterUIPreview::findOverlapsInChildren(LLView* parent) // *NOTE: If a list of elements which have localizable content were created, this function should return false if viewp's class is in that list. BOOL LLFloaterUIPreview::overlapIgnorable(LLView* viewp) { - return NULL != dynamic_cast<LLDragHandle*>(viewp) || - NULL != dynamic_cast<LLViewBorder*>(viewp) || - NULL != dynamic_cast<LLResizeBar*>(viewp); + return NULL != dynamic_cast<LLDragHandle*>(viewp) || + NULL != dynamic_cast<LLViewBorder*>(viewp) || + NULL != dynamic_cast<LLResizeBar*>(viewp); } // *HACK: these are the only two container types as of 8/08, per Richard // This is using dynamic casts because there is no object-oriented way to tell which elements are containers. BOOL LLFloaterUIPreview::containerType(LLView* viewp) { - return NULL != dynamic_cast<LLPanel*>(viewp) || NULL != dynamic_cast<LLLayoutStack*>(viewp); + return NULL != dynamic_cast<LLPanel*>(viewp) || NULL != dynamic_cast<LLLayoutStack*>(viewp); } // Check if two llview's rectangles overlap, with some tolerance BOOL LLFloaterUIPreview::elementOverlap(LLView* view1, LLView* view2) { - LLSD rec1 = view1->getRect().getValue(); - LLSD rec2 = view2->getRect().getValue(); - int tolerance = 2; - return (int)rec1[0] <= (int)rec2[2] - tolerance && - (int)rec2[0] <= (int)rec1[2] - tolerance && - (int)rec1[3] <= (int)rec2[1] - tolerance && - (int)rec2[3] <= (int)rec1[1] - tolerance; + LLSD rec1 = view1->getRect().getValue(); + LLSD rec2 = view2->getRect().getValue(); + int tolerance = 2; + return (int)rec1[0] <= (int)rec2[2] - tolerance && + (int)rec2[0] <= (int)rec1[2] - tolerance && + (int)rec1[3] <= (int)rec2[1] - tolerance && + (int)rec2[3] <= (int)rec1[1] - tolerance; } void LLOverlapPanel::draw() { - static const std::string current_selection_text("Current selection: "); - static const std::string overlapper_text("Overlapper: "); - LLColor4 text_color = LLColor4::grey; - gGL.color4fv(text_color.mV); - - if(!LLView::sPreviewClickedElement) - { - LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 - LLView::sDrawPreviewHighlights = FALSE; - LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - } - else - { - OverlapMap::iterator iterExists = mOverlapMap.find(LLView::sPreviewClickedElement); - if(iterExists == mOverlapMap.end()) - { - return; - } - - std::list<LLView*> overlappers = mOverlapMap[LLView::sPreviewClickedElement]; - if(overlappers.size() == 0) - { - LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 - LLView::sDrawPreviewHighlights = FALSE; - std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)"); - S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10; - LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - // widen panel enough to fit this text - LLRect rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); - return; - } - - // recalculate required with and height; otherwise use cached - BOOL need_to_recalculate_bounds = FALSE; - if(mLastClickedElement == NULL) - { - need_to_recalculate_bounds = TRUE; - } - - if(NULL == mLastClickedElement) - { - mLastClickedElement = LLView::sPreviewClickedElement; - } - - // recalculate bounds for scroll panel - if(need_to_recalculate_bounds || LLView::sPreviewClickedElement->getName() != mLastClickedElement->getName()) - { - // reset panel's rectangle to its default width and height (300x600) - LLRect panel_rect = getRect(); - setRect(LLRect(panel_rect.mLeft,panel_rect.mTop,panel_rect.mLeft+getRect().getWidth(),panel_rect.mTop-getRect().getHeight())); - - LLRect rect; - - // change bounds for selected element - int height_sum = mLastClickedElement->getRect().getHeight() + mSpacing + 80; - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > mLastClickedElement->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + mLastClickedElement->getRect().getWidth() + 5, rect.mBottom)); - - // and widen to accomodate text if that's wider - std::string display_text = current_selection_text + LLView::sPreviewClickedElement->getName(); - S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); - - std::list<LLView*> overlappers = mOverlapMap[LLView::sPreviewClickedElement]; - for(std::list<LLView*>::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) - { - LLView* viewp = *overlap_it; - height_sum += viewp->getRect().getHeight() + mSpacing*3; - - // widen panel's rectangle to accommodate widest overlapping element of this floater - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > viewp->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + viewp->getRect().getWidth() + 5, rect.mBottom)); - - // and widen to accomodate text if that's wider - std::string display_text = overlapper_text + viewp->getName(); - S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); - } - // change panel's height to accommodate all element heights plus spacing between them - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.mRight,rect.mTop-height_sum)); - } - - LLUI::translate(5,getRect().getHeight()-10); // translate to top left - LLView::sDrawPreviewHighlights = FALSE; - - // draw currently-selected element at top of overlappers - LLUI::translate(0,-mSpacing); - LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height - LLView::sPreviewClickedElement->draw(); - - for(std::list<LLView*>::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) - { - LLView* viewp = *overlap_it; - - // draw separating line - LLUI::translate(0,-mSpacing); - gl_line_2d(0,0,getRect().getWidth()-10,0,LLColor4(192.0f/255.0f,192.0f/255.0f,192.0f/255.0f)); - - // draw name - LLUI::translate(0,-mSpacing); - LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - - // draw element - LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height - viewp->draw(); - } - mLastClickedElement = LLView::sPreviewClickedElement; - } + static const std::string current_selection_text("Current selection: "); + static const std::string overlapper_text("Overlapper: "); + LLColor4 text_color = LLColor4::grey; + gGL.color4fv(text_color.mV); + + if(!LLView::sPreviewClickedElement) + { + LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 + LLView::sDrawPreviewHighlights = FALSE; + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + } + else + { + OverlapMap::iterator iterExists = mOverlapMap.find(LLView::sPreviewClickedElement); + if(iterExists == mOverlapMap.end()) + { + return; + } + + std::list<LLView*> overlappers = mOverlapMap[LLView::sPreviewClickedElement]; + if(overlappers.size() == 0) + { + LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 + LLView::sDrawPreviewHighlights = FALSE; + std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)"); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10; + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + // widen panel enough to fit this text + LLRect rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + return; + } + + // recalculate required with and height; otherwise use cached + BOOL need_to_recalculate_bounds = FALSE; + if(mLastClickedElement == NULL) + { + need_to_recalculate_bounds = TRUE; + } + + if(NULL == mLastClickedElement) + { + mLastClickedElement = LLView::sPreviewClickedElement; + } + + // recalculate bounds for scroll panel + if(need_to_recalculate_bounds || LLView::sPreviewClickedElement->getName() != mLastClickedElement->getName()) + { + // reset panel's rectangle to its default width and height (300x600) + LLRect panel_rect = getRect(); + setRect(LLRect(panel_rect.mLeft,panel_rect.mTop,panel_rect.mLeft+getRect().getWidth(),panel_rect.mTop-getRect().getHeight())); + + LLRect rect; + + // change bounds for selected element + int height_sum = mLastClickedElement->getRect().getHeight() + mSpacing + 80; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > mLastClickedElement->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + mLastClickedElement->getRect().getWidth() + 5, rect.mBottom)); + + // and widen to accomodate text if that's wider + std::string display_text = current_selection_text + LLView::sPreviewClickedElement->getName(); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + + std::list<LLView*> overlappers = mOverlapMap[LLView::sPreviewClickedElement]; + for(std::list<LLView*>::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) + { + LLView* viewp = *overlap_it; + height_sum += viewp->getRect().getHeight() + mSpacing*3; + + // widen panel's rectangle to accommodate widest overlapping element of this floater + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > viewp->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + viewp->getRect().getWidth() + 5, rect.mBottom)); + + // and widen to accomodate text if that's wider + std::string display_text = overlapper_text + viewp->getName(); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + } + // change panel's height to accommodate all element heights plus spacing between them + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.mRight,rect.mTop-height_sum)); + } + + LLUI::translate(5,getRect().getHeight()-10); // translate to top left + LLView::sDrawPreviewHighlights = FALSE; + + // draw currently-selected element at top of overlappers + LLUI::translate(0,-mSpacing); + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height + LLView::sPreviewClickedElement->draw(); + + for(std::list<LLView*>::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) + { + LLView* viewp = *overlap_it; + + // draw separating line + LLUI::translate(0,-mSpacing); + gl_line_2d(0,0,getRect().getWidth()-10,0,LLColor4(192.0f/255.0f,192.0f/255.0f,192.0f/255.0f)); + + // draw name + LLUI::translate(0,-mSpacing); + LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + + // draw element + LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height + viewp->draw(); + } + mLastClickedElement = LLView::sPreviewClickedElement; + } } void LLFloaterUIPreviewUtil::registerFloater() { - LLFloaterReg::add("ui_preview", "floater_ui_preview.xml", - &LLFloaterReg::build<LLFloaterUIPreview>); + LLFloaterReg::add("ui_preview", "floater_ui_preview.xml", + &LLFloaterReg::build<LLFloaterUIPreview>); } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0144f13f24..df543ecbc7 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -28,7 +28,7 @@ #include "llimview.h" -#include "llavatarnamecache.h" // IDEVO +#include "llavatarnamecache.h" // IDEVO #include "llavataractions.h" #include "llfloaterconversationlog.h" #include "llfloaterreg.h" @@ -101,14 +101,14 @@ LLIMMgr* gIMMgr = NULL; bool LLSessionTimeoutTimer::tick() { - if (mSessionId.isNull()) return true; + if (mSessionId.isNull()) return true; - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); - if (session && !session->mSessionInitialized) - { - gIMMgr->showSessionStartError("session_initialization_timed_out_error", mSessionId); - } - return true; + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); + if (session && !session->mSessionInitialized) + { + gIMMgr->showSessionStartError("session_initialization_timed_out_error", mSessionId); + } + return true; } @@ -146,25 +146,25 @@ void process_dnd_im(const LLSD& notification) static void on_avatar_name_cache_toast(const LLUUID& agent_id, - const LLAvatarName& av_name, - LLSD msg) + const LLAvatarName& av_name, + LLSD msg) { - LLSD args; - args["MESSAGE"] = msg["message"]; - args["TIME"] = msg["time"]; - // *TODO: Can this ever be an object name or group name? - args["FROM"] = av_name.getCompleteName(); - args["FROM_ID"] = msg["from_id"]; - args["SESSION_ID"] = msg["session_id"]; - args["SESSION_TYPE"] = msg["session_type"]; - LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); + LLSD args; + args["MESSAGE"] = msg["message"]; + args["TIME"] = msg["time"]; + // *TODO: Can this ever be an object name or group name? + args["FROM"] = av_name.getCompleteName(); + args["FROM_ID"] = msg["from_id"]; + args["SESSION_ID"] = msg["session_id"]; + args["SESSION_TYPE"] = msg["session_type"]; + LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); } void notify_of_message(const LLSD& msg, bool is_dnd_msg) { std::string user_preferences; - LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID(); - LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID(); + LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID(); + LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID(); LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); // do not show notification which goes from agent @@ -178,222 +178,222 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"); - LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); - bool store_dnd_message = false; // flag storage of a dnd message - bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus(); - if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) - { - conversations_floater_status = CLOSED; - } - else if (!im_box->hasFocus() && - !(session_floater && LLFloater::isVisible(session_floater) - && !session_floater->isMinimized() && session_floater->hasFocus())) - { - conversations_floater_status = NOT_ON_TOP; - } - else if (im_box->getSelectedSession() != session_id) - { - conversations_floater_status = ON_TOP; - } - else - { - conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED; - } + LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); + bool store_dnd_message = false; // flag storage of a dnd message + bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus(); + if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) + { + conversations_floater_status = CLOSED; + } + else if (!im_box->hasFocus() && + !(session_floater && LLFloater::isVisible(session_floater) + && !session_floater->isMinimized() && session_floater->hasFocus())) + { + conversations_floater_status = NOT_ON_TOP; + } + else if (im_box->getSelectedSession() != session_id) + { + conversations_floater_status = ON_TOP; + } + else + { + conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED; + } // determine user prefs for this session if (session_id.isNull()) { - if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT) - { - user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundObjectIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } - } - else - { - user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } - } - } + if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT) + { + user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundObjectIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else + { + user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + } else if(session->isP2PSessionType()) { if (LLAvatarTracker::instance().isBuddy(participant_id)) { - user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } + user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } } else { - user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); + user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); } } - } + } else if(session->isAdHocSessionType()) { - user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); + user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } } - } else if(session->isGroupSessionType()) { - user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } + user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } } // actions: // 0. nothing - exit if (("noaction" == user_preferences || - ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) - && session_floater->isMessagePaneExpanded()) + ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) + && session_floater->isMessagePaneExpanded()) { - return; + return; } // 1. open floater and [optional] surface it if ("openconversations" == user_preferences && - (CLOSED == conversations_floater_status - || NOT_ON_TOP == conversations_floater_status)) + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) { - if(!gAgent.isDoNotDisturb()) + if(!gAgent.isDoNotDisturb()) { - if(!LLAppViewer::instance()->quitRequested() && !LLFloater::isVisible(im_box)) - { - // Open conversations floater - LLFloaterReg::showInstance("im_container"); - } - im_box->collapseMessagesPane(false); - if (session_floater) - { - if (session_floater->getHost()) - { - if (NULL != im_box && im_box->isMinimized()) - { - LLFloater::onClickMinimize(im_box); - } - } - else - { - if (session_floater->isMinimized()) - { - LLFloater::onClickMinimize(session_floater); - } - } - } - } + if(!LLAppViewer::instance()->quitRequested() && !LLFloater::isVisible(im_box)) + { + // Open conversations floater + LLFloaterReg::showInstance("im_container"); + } + im_box->collapseMessagesPane(false); + if (session_floater) + { + if (session_floater->getHost()) + { + if (NULL != im_box && im_box->isMinimized()) + { + LLFloater::onClickMinimize(im_box); + } + } + else + { + if (session_floater->isMinimized()) + { + LLFloater::onClickMinimize(session_floater); + } + } + } + } else { - store_dnd_message = true; - } + store_dnd_message = true; + } } // 2. Flash line item if ("openconversations" == user_preferences - || ON_TOP == conversations_floater_status - || ("toast" == user_preferences && ON_TOP != conversations_floater_status) - || ("flash" == user_preferences && (CLOSED == conversations_floater_status - || NOT_ON_TOP == conversations_floater_status)) - || is_dnd_msg) - { - if(!LLMuteList::getInstance()->isMuted(participant_id)) - { - if(gAgent.isDoNotDisturb()) - { - store_dnd_message = true; - } - else - { - if (is_dnd_msg && (ON_TOP == conversations_floater_status || - NOT_ON_TOP == conversations_floater_status || - CLOSED == conversations_floater_status)) - { - im_box->highlightConversationItemWidget(session_id, true); - } - else - { - im_box->flashConversationItemWidget(session_id, true); - } - } - } - } + || ON_TOP == conversations_floater_status + || ("toast" == user_preferences && ON_TOP != conversations_floater_status) + || ("flash" == user_preferences && (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) + || is_dnd_msg) + { + if(!LLMuteList::getInstance()->isMuted(participant_id)) + { + if(gAgent.isDoNotDisturb()) + { + store_dnd_message = true; + } + else + { + if (is_dnd_msg && (ON_TOP == conversations_floater_status || + NOT_ON_TOP == conversations_floater_status || + CLOSED == conversations_floater_status)) + { + im_box->highlightConversationItemWidget(session_id, true); + } + else + { + im_box->flashConversationItemWidget(session_id, true); + } + } + } + } // 3. Flash FUI button if (("toast" == user_preferences || "flash" == user_preferences) && - (CLOSED == conversations_floater_status - || NOT_ON_TOP == conversations_floater_status) - && !is_session_focused - && !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened - { - if(!LLMuteList::getInstance()->isMuted(participant_id)) - { - if(!gAgent.isDoNotDisturb()) - { - gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized()); - } - else - { - store_dnd_message = true; - } - } - } + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status) + && !is_session_focused + && !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened + { + if(!LLMuteList::getInstance()->isMuted(participant_id)) + { + if(!gAgent.isDoNotDisturb()) + { + gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized()); + } + else + { + store_dnd_message = true; + } + } + } // 4. Toast if ((("toast" == user_preferences) && - (ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) && - (!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) - || !session_floater->isMessagePaneExpanded()) + (ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) && + (!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) + || !session_floater->isMessagePaneExpanded()) { //Show IM toasts (upper right toasts) // Skip toasting for system messages and for nearby chat if(session_id.notNull() && participant_id.notNull()) { - if(!is_dnd_msg) - { - if(gAgent.isDoNotDisturb()) - { - store_dnd_message = true; - } - else - { + if(!is_dnd_msg) + { + if(gAgent.isDoNotDisturb()) + { + store_dnd_message = true; + } + else + { LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); } } } - } - if (store_dnd_message) - { - // If in DND mode, allow notification to be stored so upon DND exit - // the user will be notified with some limitations (see 'is_dnd_msg' flag checks) - if(session_id.notNull() - && participant_id.notNull() - && !session_floater->isShown()) - { - LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); - } - } + } + if (store_dnd_message) + { + // If in DND mode, allow notification to be stored so upon DND exit + // the user will be notified with some limitations (see 'is_dnd_msg' flag checks) + if(session_id.notNull() + && participant_id.notNull() + && !session_floater->isShown()) + { + LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); + } + } } void on_new_message(const LLSD& msg) { - notify_of_message(msg, false); + notify_of_message(msg, false); } void startConfrenceCoro(std::string url, @@ -638,251 +638,251 @@ void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from, LLIMModel::LLIMModel() { - addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); - addNewMsgCallback(boost::bind(&on_new_message, _1)); - LLCallDialogManager::instance(); + addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); + addNewMsgCallback(boost::bind(&on_new_message, _1)); + LLCallDialogManager::instance(); } LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) -: mSessionID(session_id), - mName(name), - mType(type), - mHasOfflineMessage(has_offline_msg), - mParticipantUnreadMessageCount(0), - mNumUnread(0), - mOtherParticipantID(other_participant_id), - mInitialTargetIDs(ids), - mVoiceChannel(NULL), - mSpeakers(NULL), - mSessionInitialized(false), - mCallBackEnabled(true), - mTextIMPossible(true), - mStartCallOnInitialize(false), - mStartedAsIMCall(voice), - mIsDNDsend(false), - mAvatarNameCacheConnection() -{ - // set P2P type by default - mSessionType = P2P_SESSION; - - if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) - { - mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); - } - else - { - mVoiceChannel = new LLVoiceChannelGroup(session_id, name); - - // determine whether it is group or conference session - if (gAgent.isInGroup(mSessionID)) - { - mSessionType = GROUP_SESSION; - } - else - { - mSessionType = ADHOC_SESSION; - } - } - - if(mVoiceChannel) - { - mVoiceChannelStateChangeConnection = mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2, _3)); - } - - mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); - - // All participants will be added to the list of people we've recently interacted with. - - // we need to add only _active_ speakers...so comment this. - // may delete this later on cleanup - //mSpeakers->addListener(&LLRecentPeople::instance(), "add"); - - //we need to wait for session initialization for outgoing ad-hoc and group chat session - //correct session id for initiated ad-hoc chat will be received from the server - if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, - mInitialTargetIDs, mType)) - { - //we don't need to wait for any responses - //so we're already initialized - mSessionInitialized = true; - } - else - { - //tick returns TRUE - timer will be deleted after the tick - new LLSessionTimeoutTimer(mSessionID, SESSION_INITIALIZATION_TIMEOUT); - } - - if (IM_NOTHING_SPECIAL == mType) - { - mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); - mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); - } - - buildHistoryFileName(); - loadHistory(); - - // Localizing name of ad-hoc session. STORM-153 - // Changing name should happen here- after the history file was created, so that - // history files have consistent (English) names in different locales. - if (isAdHocSessionType() && IM_SESSION_INVITE == mType) - { - mAvatarNameCacheConnection = LLAvatarNameCache::get(mOtherParticipantID,boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,this, _2)); - } +: mSessionID(session_id), + mName(name), + mType(type), + mHasOfflineMessage(has_offline_msg), + mParticipantUnreadMessageCount(0), + mNumUnread(0), + mOtherParticipantID(other_participant_id), + mInitialTargetIDs(ids), + mVoiceChannel(NULL), + mSpeakers(NULL), + mSessionInitialized(false), + mCallBackEnabled(true), + mTextIMPossible(true), + mStartCallOnInitialize(false), + mStartedAsIMCall(voice), + mIsDNDsend(false), + mAvatarNameCacheConnection() +{ + // set P2P type by default + mSessionType = P2P_SESSION; + + if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) + { + mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); + } + else + { + mVoiceChannel = new LLVoiceChannelGroup(session_id, name); + + // determine whether it is group or conference session + if (gAgent.isInGroup(mSessionID)) + { + mSessionType = GROUP_SESSION; + } + else + { + mSessionType = ADHOC_SESSION; + } + } + + if(mVoiceChannel) + { + mVoiceChannelStateChangeConnection = mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2, _3)); + } + + mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); + + // All participants will be added to the list of people we've recently interacted with. + + // we need to add only _active_ speakers...so comment this. + // may delete this later on cleanup + //mSpeakers->addListener(&LLRecentPeople::instance(), "add"); + + //we need to wait for session initialization for outgoing ad-hoc and group chat session + //correct session id for initiated ad-hoc chat will be received from the server + if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, + mInitialTargetIDs, mType)) + { + //we don't need to wait for any responses + //so we're already initialized + mSessionInitialized = true; + } + else + { + //tick returns TRUE - timer will be deleted after the tick + new LLSessionTimeoutTimer(mSessionID, SESSION_INITIALIZATION_TIMEOUT); + } + + if (IM_NOTHING_SPECIAL == mType) + { + mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); + mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); + } + + buildHistoryFileName(); + loadHistory(); + + // Localizing name of ad-hoc session. STORM-153 + // Changing name should happen here- after the history file was created, so that + // history files have consistent (English) names in different locales. + if (isAdHocSessionType() && IM_SESSION_INVITE == mType) + { + mAvatarNameCacheConnection = LLAvatarNameCache::get(mOtherParticipantID,boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,this, _2)); + } } void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name) { - mAvatarNameCacheConnection.disconnect(); - - if (!av_name.isValidName()) - { - S32 separator_index = mName.rfind(" "); - std::string name = mName.substr(0, separator_index); - ++separator_index; - std::string conference_word = mName.substr(separator_index, mName.length()); - - // additional check that session name is what we expected - if ("Conference" == conference_word) - { - LLStringUtil::format_map_t args; - args["[AGENT_NAME]"] = name; - LLTrans::findString(mName, "conference-title-incoming", args); - } - } - else - { - LLStringUtil::format_map_t args; - args["[AGENT_NAME]"] = av_name.getCompleteName(); - LLTrans::findString(mName, "conference-title-incoming", args); - } + mAvatarNameCacheConnection.disconnect(); + + if (!av_name.isValidName()) + { + S32 separator_index = mName.rfind(" "); + std::string name = mName.substr(0, separator_index); + ++separator_index; + std::string conference_word = mName.substr(separator_index, mName.length()); + + // additional check that session name is what we expected + if ("Conference" == conference_word) + { + LLStringUtil::format_map_t args; + args["[AGENT_NAME]"] = name; + LLTrans::findString(mName, "conference-title-incoming", args); + } + } + else + { + LLStringUtil::format_map_t args; + args["[AGENT_NAME]"] = av_name.getCompleteName(); + LLTrans::findString(mName, "conference-title-incoming", args); + } } void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction) { - std::string you_joined_call = LLTrans::getString("you_joined_call"); - std::string you_started_call = LLTrans::getString("you_started_call"); - std::string other_avatar_name = ""; - LLAvatarName av_name; - - std::string message; - - switch(mSessionType) - { - case P2P_SESSION: - LLAvatarNameCache::get(mOtherParticipantID, &av_name); - other_avatar_name = av_name.getUserName(); - - if(direction == LLVoiceChannel::INCOMING_CALL) - { - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - { - LLStringUtil::format_map_t string_args; - string_args["[NAME]"] = other_avatar_name; - message = LLTrans::getString("name_started_call", string_args); - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); - break; - } - case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); - default: - break; - } - } - else // outgoing call - { - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); - break; - case LLVoiceChannel::STATE_CONNECTED : - message = LLTrans::getString("answered_call"); - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); - default: - break; - } - } - break; - - case GROUP_SESSION: - case ADHOC_SESSION: - if(direction == LLVoiceChannel::INCOMING_CALL) - { - switch(new_state) - { - case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); - default: - break; - } - } - else // outgoing call - { - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); - break; - default: - break; - } - } - default: - break; - } - // Update speakers list when connected - if (LLVoiceChannel::STATE_CONNECTED == new_state) - { - mSpeakers->update(true); - } + std::string you_joined_call = LLTrans::getString("you_joined_call"); + std::string you_started_call = LLTrans::getString("you_started_call"); + std::string other_avatar_name = ""; + LLAvatarName av_name; + + std::string message; + + switch(mSessionType) + { + case P2P_SESSION: + LLAvatarNameCache::get(mOtherParticipantID, &av_name); + other_avatar_name = av_name.getUserName(); + + if(direction == LLVoiceChannel::INCOMING_CALL) + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + { + LLStringUtil::format_map_t string_args; + string_args["[NAME]"] = other_avatar_name; + message = LLTrans::getString("name_started_call", string_args); + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); + break; + } + case LLVoiceChannel::STATE_CONNECTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); + default: + break; + } + } + else // outgoing call + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); + break; + case LLVoiceChannel::STATE_CONNECTED : + message = LLTrans::getString("answered_call"); + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); + default: + break; + } + } + break; + + case GROUP_SESSION: + case ADHOC_SESSION: + if(direction == LLVoiceChannel::INCOMING_CALL) + { + switch(new_state) + { + case LLVoiceChannel::STATE_CONNECTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); + default: + break; + } + } + else // outgoing call + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); + break; + default: + break; + } + } + default: + break; + } + // Update speakers list when connected + if (LLVoiceChannel::STATE_CONNECTED == new_state) + { + mSpeakers->update(true); + } } LLIMModel::LLIMSession::~LLIMSession() { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - - delete mSpeakers; - mSpeakers = NULL; + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } - // End the text IM session if necessary - if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull()) - { - switch(mType) - { - case IM_NOTHING_SPECIAL: - case IM_SESSION_P2P_INVITE: - LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID); - break; + delete mSpeakers; + mSpeakers = NULL; - default: - // Appease the linux compiler - break; - } - } + // End the text IM session if necessary + if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull()) + { + switch(mType) + { + case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: + LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID); + break; + + default: + // Appease the linux compiler + break; + } + } - mVoiceChannelStateChangeConnection.disconnect(); + mVoiceChannelStateChangeConnection.disconnect(); - // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). - mVoiceChannel->deactivate(); + // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). + mVoiceChannel->deactivate(); - delete mVoiceChannel; - mVoiceChannel = NULL; + delete mVoiceChannel; + mVoiceChannel = NULL; } void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id) { - mSessionInitialized = true; + mSessionInitialized = true; - if (new_session_id != mSessionID) - { - mSessionID = new_session_id; - mVoiceChannel->updateSessionID(new_session_id); - } + if (new_session_id != mSessionID) + { + mSessionID = new_session_id; + mVoiceChannel->updateSessionID(new_session_id); + } } void LLIMModel::LLIMSession::addMessage(const std::string& from, @@ -893,40 +893,40 @@ void LLIMModel::LLIMSession::addMessage(const std::string& from, const bool is_region_msg, const U32 timestamp) // may be zero { - LLSD message; - message["from"] = from; - message["from_id"] = from_id; - message["message"] = utf8_text; - message["time"] = time; // string used in display, may be full data YYYY/MM/DD HH:MM or just HH:MM + LLSD message; + message["from"] = from; + message["from_id"] = from_id; + message["message"] = utf8_text; + message["time"] = time; // string used in display, may be full data YYYY/MM/DD HH:MM or just HH:MM message["timestamp"] = (S32)timestamp; // use string? LLLogChat::timestamp2LogString(timestamp, true); - message["index"] = (LLSD::Integer)mMsgs.size(); - message["is_history"] = is_history; - message["is_region_msg"] = is_region_msg; - - LL_DEBUGS("UIUsage") << "addMessage " << " from " << from << " from_id " << from_id << " utf8_text " << utf8_text << " time " << time << " is_history " << is_history << " session mType " << mType << LL_ENDL; - if (from_id == gAgent.getID()) - { - if (mType == IM_SESSION_GROUP_START) - { - LLUIUsage::instance().logCommand("Chat.SendGroup"); - } - else if (mType == IM_NOTHING_SPECIAL) - { - LLUIUsage::instance().logCommand("Chat.SendIM"); - } - else - { - LLUIUsage::instance().logCommand("Chat.SendOther"); - } - } - - mMsgs.push_front(message); // Add most recent messages to the front of mMsgs - - if (mSpeakers && from_id.notNull()) - { - mSpeakers->speakerChatted(from_id); - mSpeakers->setSpeakerTyping(from_id, FALSE); - } + message["index"] = (LLSD::Integer)mMsgs.size(); + message["is_history"] = is_history; + message["is_region_msg"] = is_region_msg; + + LL_DEBUGS("UIUsage") << "addMessage " << " from " << from << " from_id " << from_id << " utf8_text " << utf8_text << " time " << time << " is_history " << is_history << " session mType " << mType << LL_ENDL; + if (from_id == gAgent.getID()) + { + if (mType == IM_SESSION_GROUP_START) + { + LLUIUsage::instance().logCommand("Chat.SendGroup"); + } + else if (mType == IM_NOTHING_SPECIAL) + { + LLUIUsage::instance().logCommand("Chat.SendIM"); + } + else + { + LLUIUsage::instance().logCommand("Chat.SendOther"); + } + } + + mMsgs.push_front(message); // Add most recent messages to the front of mMsgs + + if (mSpeakers && from_id.notNull()) + { + mSpeakers->speakerChatted(from_id); + mSpeakers->setSpeakerTyping(from_id, FALSE); + } } void LLIMModel::LLIMSession::addMessagesFromHistoryCache(const chat_message_list_t& history) @@ -1206,329 +1206,329 @@ void LLIMModel::LLIMSession::addMessagesFromServerHistory(const LLSD& history, void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata) { - if (!userdata) return; + if (!userdata) return; - LLIMSession* self = (LLIMSession*) userdata; + LLIMSession* self = (LLIMSession*) userdata; - if (type == LLLogChat::LOG_LINE) - { + if (type == LLLogChat::LOG_LINE) + { LL_DEBUGS("ChatHistory") << "chatFromLogFile() adding LOG_LINE message from " << msg << LL_ENDL; self->addMessage("", LLSD(), msg["message"].asString(), "", true, false, 0); // from history data, not region message, no timestamp - } - else if (type == LLLogChat::LOG_LLSD) - { + } + else if (type == LLLogChat::LOG_LLSD) + { LL_DEBUGS("ChatHistory") << "chatFromLogFile() adding LOG_LLSD message from " << msg << LL_ENDL; self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString(), true, false, 0); // from history data, not region message, no timestamp - } + } } void LLIMModel::LLIMSession::loadHistory() { - mMsgs.clear(); + mMsgs.clear(); mLastHistoryCacheMsgs.clear(); mLastHistoryCacheDateTime.clear(); - if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) - { + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) + { // read and parse chat history from local file chat_message_list_t chat_history; - LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); + LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); addMessagesFromHistoryCache(chat_history); } } LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const { - return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); + return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); } //*TODO consider switching to using std::set instead of std::list for holding LLUUIDs across the whole code LLIMModel::LLIMSession* LLIMModel::findAdHocIMSession(const uuid_vec_t& ids) { - S32 num = ids.size(); - if (!num) return NULL; + S32 num = ids.size(); + if (!num) return NULL; - if (mId2SessionMap.empty()) return NULL; + if (mId2SessionMap.empty()) return NULL; - std::map<LLUUID, LLIMSession*>::const_iterator it = mId2SessionMap.begin(); - for (; it != mId2SessionMap.end(); ++it) - { - LLIMSession* session = (*it).second; + std::map<LLUUID, LLIMSession*>::const_iterator it = mId2SessionMap.begin(); + for (; it != mId2SessionMap.end(); ++it) + { + LLIMSession* session = (*it).second; - if (!session->isAdHoc()) continue; - if (session->mInitialTargetIDs.size() != num) continue; + if (!session->isAdHoc()) continue; + if (session->mInitialTargetIDs.size() != num) continue; - std::list<LLUUID> tmp_list(session->mInitialTargetIDs.begin(), session->mInitialTargetIDs.end()); + std::list<LLUUID> tmp_list(session->mInitialTargetIDs.begin(), session->mInitialTargetIDs.end()); - uuid_vec_t::const_iterator iter = ids.begin(); - while (iter != ids.end()) - { - tmp_list.remove(*iter); - ++iter; + uuid_vec_t::const_iterator iter = ids.begin(); + while (iter != ids.end()) + { + tmp_list.remove(*iter); + ++iter; - if (tmp_list.empty()) - { - break; - } - } + if (tmp_list.empty()) + { + break; + } + } - if (tmp_list.empty() && iter == ids.end()) - { - return session; - } - } + if (tmp_list.empty() && iter == ids.end()) + { + return session; + } + } - return NULL; + return NULL; } bool LLIMModel::LLIMSession::isOutgoingAdHoc() const { - return IM_SESSION_CONFERENCE_START == mType; + return IM_SESSION_CONFERENCE_START == mType; } bool LLIMModel::LLIMSession::isAdHoc() { - return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID, TRUE)); + return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID, TRUE)); } bool LLIMModel::LLIMSession::isP2P() { - return IM_NOTHING_SPECIAL == mType; + return IM_NOTHING_SPECIAL == mType; } bool LLIMModel::LLIMSession::isGroupChat() { - return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE)); + return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE)); } LLUUID LLIMModel::LLIMSession::generateOutgoingAdHocHash() const { - LLUUID hash = LLUUID::null; + LLUUID hash = LLUUID::null; - if (mInitialTargetIDs.size()) - { - std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); - hash = generateHash(sorted_uuids); - } + if (mInitialTargetIDs.size()) + { + std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); + hash = generateHash(sorted_uuids); + } - return hash; + return hash; } void LLIMModel::LLIMSession::buildHistoryFileName() { - mHistoryFileName = mName; - - //ad-hoc requires sophisticated chat history saving schemes - if (isAdHoc()) - { - /* in case of outgoing ad-hoc sessions we need to make specilized names - * if this naming system is ever changed then the filtering definitions in - * lllogchat.cpp need to be change acordingly so that the filtering for the - * date stamp code introduced in STORM-102 will work properly and not add - * a date stamp to the Ad-hoc conferences. - */ - if (mInitialTargetIDs.size()) - { - std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); - mHistoryFileName = mName + " hash" + generateHash(sorted_uuids).asString(); - } - else - { - //in case of incoming ad-hoc sessions - mHistoryFileName = mName + " " + LLLogChat::timestamp2LogString(0, true) + " " + mSessionID.asString().substr(0, 4); - } - } - else if (isP2P()) // look up username to use as the log name - { - LLAvatarName av_name; - // For outgoing sessions we already have a cached name - // so no need for a callback in LLAvatarNameCache::get() - if (LLAvatarNameCache::get(mOtherParticipantID, &av_name)) - { - mHistoryFileName = LLCacheName::buildUsername(av_name.getUserName()); - } - else - { - // Incoming P2P sessions include a name that we can use to build a history file name - mHistoryFileName = LLCacheName::buildUsername(mName); - } + mHistoryFileName = mName; + + //ad-hoc requires sophisticated chat history saving schemes + if (isAdHoc()) + { + /* in case of outgoing ad-hoc sessions we need to make specilized names + * if this naming system is ever changed then the filtering definitions in + * lllogchat.cpp need to be change acordingly so that the filtering for the + * date stamp code introduced in STORM-102 will work properly and not add + * a date stamp to the Ad-hoc conferences. + */ + if (mInitialTargetIDs.size()) + { + std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); + mHistoryFileName = mName + " hash" + generateHash(sorted_uuids).asString(); + } + else + { + //in case of incoming ad-hoc sessions + mHistoryFileName = mName + " " + LLLogChat::timestamp2LogString(0, true) + " " + mSessionID.asString().substr(0, 4); + } + } + else if (isP2P()) // look up username to use as the log name + { + LLAvatarName av_name; + // For outgoing sessions we already have a cached name + // so no need for a callback in LLAvatarNameCache::get() + if (LLAvatarNameCache::get(mOtherParticipantID, &av_name)) + { + mHistoryFileName = LLCacheName::buildUsername(av_name.getUserName()); + } + else + { + // Incoming P2P sessions include a name that we can use to build a history file name + mHistoryFileName = LLCacheName::buildUsername(mName); + } // user's account name can change, but filenames and session names are account name based LLConversationLog::getInstance()->verifyFilename(mSessionID, mHistoryFileName, av_name.getCompleteName()); - } - else if (isGroupChat()) - { - mHistoryFileName = mName + GROUP_CHAT_SUFFIX; - } + } + else if (isGroupChat()) + { + mHistoryFileName = mName + GROUP_CHAT_SUFFIX; + } } //static LLUUID LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_uuids) { - LLMD5 md5_uuid; + LLMD5 md5_uuid; - std::set<LLUUID>::const_iterator it = sorted_uuids.begin(); - while (it != sorted_uuids.end()) - { - md5_uuid.update((unsigned char*)(*it).mData, 16); - it++; - } - md5_uuid.finalize(); + std::set<LLUUID>::const_iterator it = sorted_uuids.begin(); + while (it != sorted_uuids.end()) + { + md5_uuid.update((unsigned char*)(*it).mData, 16); + it++; + } + md5_uuid.finalize(); - LLUUID participants_md5_hash; - md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData); - return participants_md5_hash; + LLUUID participants_md5_hash; + md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData); + return participants_md5_hash; } void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) { - LLIMSession* session = findIMSession(old_session_id); - if (session) - { - session->sessionInitReplyReceived(new_session_id); + LLIMSession* session = findIMSession(old_session_id); + if (session) + { + session->sessionInitReplyReceived(new_session_id); - if (old_session_id != new_session_id) - { - mId2SessionMap.erase(old_session_id); - mId2SessionMap[new_session_id] = session; - } + if (old_session_id != new_session_id) + { + mId2SessionMap.erase(old_session_id); + mId2SessionMap[new_session_id] = session; + } - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(old_session_id); - if (im_floater) - { - im_floater->sessionInitReplyReceived(new_session_id); - } + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(old_session_id); + if (im_floater) + { + im_floater->sessionInitReplyReceived(new_session_id); + } - if (old_session_id != new_session_id) - { - gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); - } + if (old_session_id != new_session_id) + { + gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); + } - // auto-start the call on session initialization? - if (session->mStartCallOnInitialize) - { - gIMMgr->startCall(new_session_id); - } - } + // auto-start the call on session initialization? + if (session->mStartCallOnInitialize) + { + gIMMgr->startCall(new_session_id); + } + } } void LLIMModel::testMessages() { - LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); - LLUUID bot1_session_id; - std::string from = "IM Tester"; + LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); + LLUUID bot1_session_id; + std::string from = "IM Tester"; - bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); - newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); - addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); + bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); + newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); + addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); - LLUUID bot2_id; - std::string firstname[] = {"Roflcopter", "Joe"}; - std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; + LLUUID bot2_id; + std::string firstname[] = {"Roflcopter", "Joe"}; + std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; - S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); - S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); + S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); + S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); - from = firstname[rand1] + " " + lastname[rand2]; - bot2_id.generate(from); - LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); - newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); - addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? "); - addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); + from = firstname[rand1] + " " + lastname[rand2]; + bot2_id.generate(from); + LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); + newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); + addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? "); + addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); } //session name should not be empty bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, - const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) + const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) { - if (name.empty()) - { - LL_WARNS() << "Attempt to create a new session with empty name; id = " << session_id << LL_ENDL; - return false; - } + if (name.empty()) + { + LL_WARNS() << "Attempt to create a new session with empty name; id = " << session_id << LL_ENDL; + return false; + } - if (findIMSession(session_id)) - { - LL_WARNS() << "IM Session " << session_id << " already exists" << LL_ENDL; - return false; - } + if (findIMSession(session_id)) + { + LL_WARNS() << "IM Session " << session_id << " already exists" << LL_ENDL; + return false; + } - LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); - mId2SessionMap[session_id] = session; + LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); + mId2SessionMap[session_id] = session; - // When notifying observer, name of session is used instead of "name", because they may not be the - // same if it is an adhoc session (in this case name is localized in LLIMSession constructor). - std::string session_name = LLIMModel::getInstance()->getName(session_id); - LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, session_name, other_participant_id,has_offline_msg); + // When notifying observer, name of session is used instead of "name", because they may not be the + // same if it is an adhoc session (in this case name is localized in LLIMSession constructor). + std::string session_name = LLIMModel::getInstance()->getName(session_id); + LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, session_name, other_participant_id,has_offline_msg); - return true; + return true; } bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, bool voice, bool has_offline_msg) { - uuid_vec_t ids; - ids.push_back(other_participant_id); - return newSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); + uuid_vec_t ids; + ids.push_back(other_participant_id); + return newSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); } bool LLIMModel::clearSession(const LLUUID& session_id) { - if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false; - delete (mId2SessionMap[session_id]); - mId2SessionMap.erase(session_id); - return true; + if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false; + delete (mId2SessionMap[session_id]); + mId2SessionMap.erase(session_id); + return true; } void LLIMModel::getMessages(const LLUUID& session_id, chat_message_list_t& messages, int start_index, const bool sendNoUnreadMsgs) { - getMessagesSilently(session_id, messages, start_index); + getMessagesSilently(session_id, messages, start_index); - if (sendNoUnreadMsgs) - { - sendNoUnreadMessages(session_id); - } + if (sendNoUnreadMsgs) + { + sendNoUnreadMessages(session_id); + } } void LLIMModel::getMessagesSilently(const LLUUID& session_id, chat_message_list_t& messages, int start_index) { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return; + } - int i = session->mMsgs.size() - start_index; + int i = session->mMsgs.size() - start_index; - for (chat_message_list_t::iterator iter = session->mMsgs.begin(); - iter != session->mMsgs.end() && i > 0; - iter++) - { - LLSD msg; - msg = *iter; - messages.push_back(*iter); - i--; - } + for (chat_message_list_t::iterator iter = session->mMsgs.begin(); + iter != session->mMsgs.end() && i > 0; + iter++) + { + LLSD msg; + msg = *iter; + messages.push_back(*iter); + i--; + } } void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id) { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return; + } - session->mNumUnread = 0; - session->mParticipantUnreadMessageCount = 0; + session->mNumUnread = 0; + session->mParticipantUnreadMessageCount = 0; - LLSD arg; - arg["session_id"] = session_id; - arg["num_unread"] = 0; - arg["participant_unread"] = session->mParticipantUnreadMessageCount; - mNoUnreadMsgsSignal(arg); + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = 0; + arg["participant_unread"] = session->mParticipantUnreadMessageCount; + mNoUnreadMsgsSignal(arg); } bool LLIMModel::addToHistory(const LLUUID& session_id, @@ -1538,54 +1538,54 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, bool is_region_msg, U32 timestamp) { - LLIMSession* session = findIMSession(session_id); + LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return false; - } + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return false; + } // This is where a normal arriving message is added to the session. Note that the time string created here is without the full date - session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp2LogString(timestamp, false), false, is_region_msg, timestamp); + session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp2LogString(timestamp, false), false, is_region_msg, timestamp); - return true; + return true; } bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { - if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1) - { - std::string from_name = from; + if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1) + { + std::string from_name = from; - LLAvatarName av_name; - if (!from_id.isNull() && - LLAvatarNameCache::get(from_id, &av_name) && - !av_name.isDisplayNameDefault()) - { - from_name = av_name.getCompleteName(); - } + LLAvatarName av_name; + if (!from_id.isNull() && + LLAvatarNameCache::get(from_id, &av_name) && + !av_name.isDisplayNameDefault()) + { + from_name = av_name.getCompleteName(); + } - LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text); - LLConversationLog::instance().cache(); // update the conversation log too - return true; - } - else - { - return false; - } + LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text); + LLConversationLog::instance().cache(); // update the conversation log too + return true; + } + else + { + return false; + } } void LLIMModel::proccessOnlineOfflineNotification( - const LLUUID& session_id, + const LLUUID& session_id, const std::string& utf8_text) { - // Add system message to history - addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); + // Add system message to history + addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); } void LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* = false */ U32 time_stamp /* = 0 */) + const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* = false */ U32 time_stamp /* = 0 */) { if (gSavedSettings.getBOOL("TranslateChat") && (from != SYSTEM_FROM)) { @@ -1631,442 +1631,442 @@ void LLIMModel::processAddingMessage(const LLUUID& session_id, const std::string } LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* false */ + const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* false */ U32 timestamp /* = 0 */) { - LLIMSession* session = findIMSession(session_id); + LLIMSession* session = findIMSession(session_id); - if (!session) - { - return NULL; - } + if (!session) + { + return NULL; + } - // replace interactive system message marker with correct from string value - std::string from_name = from; - if (INTERACTIVE_SYSTEM_FROM == from) - { - from_name = SYSTEM_FROM; - } + // replace interactive system message marker with correct from string value + std::string from_name = from; + if (INTERACTIVE_SYSTEM_FROM == from) + { + from_name = SYSTEM_FROM; + } - addToHistory(session_id, from_name, from_id, utf8_text, is_region_msg, timestamp); - if (log2file) - { - logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text); - } + addToHistory(session_id, from_name, from_id, utf8_text, is_region_msg, timestamp); + if (log2file) + { + logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text); + } - session->mNumUnread++; + session->mNumUnread++; - //update count of unread messages from real participant - if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from) - // we should increment counter for interactive system messages() - || INTERACTIVE_SYSTEM_FROM == from) - { - ++(session->mParticipantUnreadMessageCount); - } + //update count of unread messages from real participant + if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from) + // we should increment counter for interactive system messages() + || INTERACTIVE_SYSTEM_FROM == from) + { + ++(session->mParticipantUnreadMessageCount); + } - return session; + return session; } const std::string LLIMModel::getName(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); + LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return LLTrans::getString("no_session_message"); - } + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return LLTrans::getString("no_session_message"); + } - return session->mName; + return session->mName; } const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return -1; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return -1; + } - return session->mNumUnread; + return session->mNumUnread; } const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; - return LLUUID::null; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; + return LLUUID::null; + } - return session->mOtherParticipantID; + return session->mOtherParticipantID; } EInstantMessage LLIMModel::getType(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return IM_COUNT; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return IM_COUNT; + } - return session->mType; + return session->mType; } LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return NULL; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return NULL; + } - return session->mVoiceChannel; + return session->mVoiceChannel; } LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; - return NULL; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; + return NULL; + } - return session->mSpeakers; + return session->mSpeakers; } const std::string& LLIMModel::getHistoryFileName(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; - return LLStringUtil::null; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; + return LLStringUtil::null; + } - return session->mHistoryFileName; + return session->mHistoryFileName; } // TODO get rid of other participant ID void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) { - std::string name; - LLAgentUI::buildFullname(name); + std::string name; + LLAgentUI::buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name, - std::string("typing"), - IM_ONLINE, - (typing ? IM_TYPING_START : IM_TYPING_STOP), - session_id); - gAgent.sendReliableMessage(); + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + std::string("typing"), + IM_ONLINE, + (typing ? IM_TYPING_START : IM_TYPING_STOP), + session_id); + gAgent.sendReliableMessage(); } void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id) { - if(session_id.notNull()) - { - std::string name; - LLAgentUI::buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name, - LLStringUtil::null, - IM_ONLINE, - IM_SESSION_LEAVE, - session_id); - gAgent.sendReliableMessage(); - } + if(session_id.notNull()) + { + std::string name; + LLAgentUI::buildFullname(name); + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + LLStringUtil::null, + IM_ONLINE, + IM_SESSION_LEAVE, + session_id); + gAgent.sendReliableMessage(); + } } //*TODO this method is better be moved to the LLIMMgr void LLIMModel::sendMessage(const std::string& utf8_text, - const LLUUID& im_session_id, - const LLUUID& other_participant_id, - EInstantMessage dialog) -{ - std::string name; - bool sent = false; - LLAgentUI::buildFullname(name); - - const LLRelationship* info = NULL; - info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); - - U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; - // Old call to send messages to SLim client, no longer supported. - //if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) - //{ - // // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. - // sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); - //} - - if(!sent) - { - // Send message normally. - - // default to IM_SESSION_SEND unless it's nothing special - in - // which case it's probably an IM to everyone. - U8 new_dialog = dialog; - - if ( dialog != IM_NOTHING_SPECIAL ) - { - new_dialog = IM_SESSION_SEND; - } - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name.c_str(), - utf8_text.c_str(), - offline, - (EInstantMessage)new_dialog, - im_session_id); - gAgent.sendReliableMessage(); - } - - bool is_group_chat = false; - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(im_session_id); - if(session) - { - is_group_chat = session->isGroupSessionType(); - } - - // If there is a mute list and this is not a group chat... - if ( LLMuteList::getInstance() && !is_group_chat) - { - // ... the target should not be in our mute list for some message types. - // Auto-remove them if present. - switch( dialog ) - { - case IM_NOTHING_SPECIAL: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. - case IM_LURE_USER: - case IM_GODLIKE_LURE_USER: - case IM_FRIENDSHIP_OFFERED: - LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); - break; - default: ; // do nothing - } - } - - if((dialog == IM_NOTHING_SPECIAL) && - (other_participant_id.notNull())) - { - // Do we have to replace the /me's here? - std::string from; - LLAgentUI::buildFullname(from); - LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text); - - //local echo for the legacy communicate panel - std::string history_echo; - LLAgentUI::buildFullname(history_echo); - - history_echo += ": " + utf8_text; - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); - if (speaker_mgr) - { - speaker_mgr->speakerChatted(gAgentID); - speaker_mgr->setSpeakerTyping(gAgentID, FALSE); - } - } - - // Add the recipient to the recent people list. - bool is_not_group_id = LLGroupMgr::getInstance()->getGroupData(other_participant_id) == NULL; - - if (is_not_group_id) - { - if( session == 0)//??? shouldn't really happen - { - LLRecentPeople::instance().add(other_participant_id); - return; - } - // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat - // (it can be also Group chat but it is checked above) - // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added - // to Recent People to prevent showing of an item with (?? ?)(?? ?), sans the spaces. See EXT-8246. - // Concrete participants will be added into this list once they sent message in chat. - if (IM_SESSION_INVITE == dialog) return; - - if (IM_SESSION_CONFERENCE_START == dialog) // outgoing ad-hoc session - { - // Add only online members of conference to recent list (EXT-8658) - addSpeakersToRecent(im_session_id); - } - else // outgoing P2P session - { - // Add the recepient of the session. - if (!session->mInitialTargetIDs.empty()) - { - LLRecentPeople::instance().add(*(session->mInitialTargetIDs.begin())); - } - } - } + const LLUUID& im_session_id, + const LLUUID& other_participant_id, + EInstantMessage dialog) +{ + std::string name; + bool sent = false; + LLAgentUI::buildFullname(name); + + const LLRelationship* info = NULL; + info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); + + U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; + // Old call to send messages to SLim client, no longer supported. + //if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) + //{ + // // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. + // sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); + //} + + if(!sent) + { + // Send message normally. + + // default to IM_SESSION_SEND unless it's nothing special - in + // which case it's probably an IM to everyone. + U8 new_dialog = dialog; + + if ( dialog != IM_NOTHING_SPECIAL ) + { + new_dialog = IM_SESSION_SEND; + } + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name.c_str(), + utf8_text.c_str(), + offline, + (EInstantMessage)new_dialog, + im_session_id); + gAgent.sendReliableMessage(); + } + + bool is_group_chat = false; + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(im_session_id); + if(session) + { + is_group_chat = session->isGroupSessionType(); + } + + // If there is a mute list and this is not a group chat... + if ( LLMuteList::getInstance() && !is_group_chat) + { + // ... the target should not be in our mute list for some message types. + // Auto-remove them if present. + switch( dialog ) + { + case IM_NOTHING_SPECIAL: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. + case IM_LURE_USER: + case IM_GODLIKE_LURE_USER: + case IM_FRIENDSHIP_OFFERED: + LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); + break; + default: ; // do nothing + } + } + + if((dialog == IM_NOTHING_SPECIAL) && + (other_participant_id.notNull())) + { + // Do we have to replace the /me's here? + std::string from; + LLAgentUI::buildFullname(from); + LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text); + + //local echo for the legacy communicate panel + std::string history_echo; + LLAgentUI::buildFullname(history_echo); + + history_echo += ": " + utf8_text; + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } + } + + // Add the recipient to the recent people list. + bool is_not_group_id = LLGroupMgr::getInstance()->getGroupData(other_participant_id) == NULL; + + if (is_not_group_id) + { + if( session == 0)//??? shouldn't really happen + { + LLRecentPeople::instance().add(other_participant_id); + return; + } + // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat + // (it can be also Group chat but it is checked above) + // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added + // to Recent People to prevent showing of an item with (?? ?)(?? ?), sans the spaces. See EXT-8246. + // Concrete participants will be added into this list once they sent message in chat. + if (IM_SESSION_INVITE == dialog) return; + + if (IM_SESSION_CONFERENCE_START == dialog) // outgoing ad-hoc session + { + // Add only online members of conference to recent list (EXT-8658) + addSpeakersToRecent(im_session_id); + } + else // outgoing P2P session + { + // Add the recepient of the session. + if (!session->mInitialTargetIDs.empty()) + { + LLRecentPeople::instance().add(*(session->mInitialTargetIDs.begin())); + } + } + } } void LLIMModel::addSpeakersToRecent(const LLUUID& im_session_id) { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); - LLSpeakerMgr::speaker_list_t speaker_list; - if(speaker_mgr != NULL) - { - speaker_mgr->getSpeakerList(&speaker_list, true); - } - for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) - { - const LLPointer<LLSpeaker>& speakerp = *it; - LLRecentPeople::instance().add(speakerp->mID); - } + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + LLSpeakerMgr::speaker_list_t speaker_list; + if(speaker_mgr != NULL) + { + speaker_mgr->getSpeakerList(&speaker_list, true); + } + for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) + { + const LLPointer<LLSpeaker>& speakerp = *it; + LLRecentPeople::instance().add(speakerp->mID); + } } void session_starter_helper( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - EInstantMessage im_type) + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + EInstantMessage im_type) { - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->newMessageFast(_PREHASH_ImprovedInstantMessage); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addU8Fast(_PREHASH_Dialog, im_type); - msg->addUUIDFast(_PREHASH_ID, temp_session_id); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary + msg->nextBlockFast(_PREHASH_MessageBlock); + msg->addBOOLFast(_PREHASH_FromGroup, FALSE); + msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); + msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); + msg->addU8Fast(_PREHASH_Dialog, im_type); + msg->addUUIDFast(_PREHASH_ID, temp_session_id); + msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); + std::string name; + LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, LLStringUtil::null); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); + msg->addStringFast(_PREHASH_FromAgentName, name); + msg->addStringFast(_PREHASH_Message, LLStringUtil::null); + msg->addU32Fast(_PREHASH_ParentEstateID, 0); + msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); + msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); } void start_deprecated_conference_chat( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) -{ - U8* bucket; - U8* pos; - S32 count; - S32 bucket_size; - - // *FIX: this could suffer from endian issues - count = agents_to_invite.size(); - bucket_size = UUID_BYTES * count; - bucket = new U8[bucket_size]; - pos = bucket; - - for(S32 i = 0; i < count; ++i) - { - LLUUID agent_id = agents_to_invite[i].asUUID(); + const LLUUID& temp_session_id, + const LLUUID& creator_id, + const LLUUID& other_participant_id, + const LLSD& agents_to_invite) +{ + U8* bucket; + U8* pos; + S32 count; + S32 bucket_size; + + // *FIX: this could suffer from endian issues + count = agents_to_invite.size(); + bucket_size = UUID_BYTES * count; + bucket = new U8[bucket_size]; + pos = bucket; + + for(S32 i = 0; i < count; ++i) + { + LLUUID agent_id = agents_to_invite[i].asUUID(); - memcpy(pos, &agent_id, UUID_BYTES); - pos += UUID_BYTES; - } + memcpy(pos, &agent_id, UUID_BYTES); + pos += UUID_BYTES; + } - session_starter_helper( - temp_session_id, - other_participant_id, - IM_SESSION_CONFERENCE_START); + session_starter_helper( + temp_session_id, + other_participant_id, + IM_SESSION_CONFERENCE_START); - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - bucket, - bucket_size); + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + bucket, + bucket_size); - gAgent.sendReliableMessage(); + gAgent.sendReliableMessage(); - delete[] bucket; + delete[] bucket; } // Returns true if any messages were sent, false otherwise. // Is sort of equivalent to "does the server need to do anything?" bool LLIMModel::sendStartSession( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - const uuid_vec_t& ids, - EInstantMessage dialog) -{ - if ( dialog == IM_SESSION_GROUP_START ) - { - session_starter_helper( - temp_session_id, - other_participant_id, - dialog); - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); - gAgent.sendReliableMessage(); - - return true; - } - else if ( dialog == IM_SESSION_CONFERENCE_START ) - { - LLSD agents; - for (int i = 0; i < (S32) ids.size(); i++) - { - agents.append(ids[i]); - } - - //we have a new way of starting conference calls now - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string url = region->getCapability( - "ChatSessionRequest"); + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + const uuid_vec_t& ids, + EInstantMessage dialog) +{ + if ( dialog == IM_SESSION_GROUP_START ) + { + session_starter_helper( + temp_session_id, + other_participant_id, + dialog); + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); + gAgent.sendReliableMessage(); + + return true; + } + else if ( dialog == IM_SESSION_CONFERENCE_START ) + { + LLSD agents; + for (int i = 0; i < (S32) ids.size(); i++) + { + agents.append(ids[i]); + } + + //we have a new way of starting conference calls now + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string url = region->getCapability( + "ChatSessionRequest"); LLCoros::instance().launch("startConfrenceCoro", boost::bind(&startConfrenceCoro, url, temp_session_id, gAgent.getID(), other_participant_id, agents)); - } - else - { - start_deprecated_conference_chat( - temp_session_id, - gAgent.getID(), - other_participant_id, - agents); - } + } + else + { + start_deprecated_conference_chat( + temp_session_id, + gAgent.getID(), + other_participant_id, + agents); + } - //we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id) - return true; - } + //we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id) + return true; + } - return false; + return false; } @@ -2075,126 +2075,126 @@ bool LLIMModel::sendStartSession( // static LLUUID LLIMMgr::computeSessionID( - EInstantMessage dialog, - const LLUUID& other_participant_id) -{ - LLUUID session_id; - if (IM_SESSION_GROUP_START == dialog) - { - // slam group session_id to the group_id (other_participant_id) - session_id = other_participant_id; - } - else if (IM_SESSION_CONFERENCE_START == dialog) - { - session_id.generate(); - } - else if (IM_SESSION_INVITE == dialog) - { - // use provided session id for invites - session_id = other_participant_id; - } - else - { - LLUUID agent_id = gAgent.getID(); - if (other_participant_id == agent_id) - { - // if we try to send an IM to ourselves then the XOR would be null - // so we just make the session_id the same as the agent_id - session_id = agent_id; - } - else - { - // peer-to-peer or peer-to-asset session_id is the XOR - session_id = other_participant_id ^ agent_id; - } - } - - if (gAgent.isInGroup(session_id, TRUE) && (session_id != other_participant_id)) - { - LL_WARNS() << "Group session id different from group id: IM type = " << dialog << ", session id = " << session_id << ", group id = " << other_participant_id << LL_ENDL; - } - return session_id; + EInstantMessage dialog, + const LLUUID& other_participant_id) +{ + LLUUID session_id; + if (IM_SESSION_GROUP_START == dialog) + { + // slam group session_id to the group_id (other_participant_id) + session_id = other_participant_id; + } + else if (IM_SESSION_CONFERENCE_START == dialog) + { + session_id.generate(); + } + else if (IM_SESSION_INVITE == dialog) + { + // use provided session id for invites + session_id = other_participant_id; + } + else + { + LLUUID agent_id = gAgent.getID(); + if (other_participant_id == agent_id) + { + // if we try to send an IM to ourselves then the XOR would be null + // so we just make the session_id the same as the agent_id + session_id = agent_id; + } + else + { + // peer-to-peer or peer-to-asset session_id is the XOR + session_id = other_participant_id ^ agent_id; + } + } + + if (gAgent.isInGroup(session_id, TRUE) && (session_id != other_participant_id)) + { + LL_WARNS() << "Group session id different from group id: IM type = " << dialog << ", session id = " << session_id << ", group id = " << other_participant_id << LL_ENDL; + } + return session_id; } void LLIMMgr::showSessionStartError( - const std::string& error_string, - const LLUUID session_id) + const std::string& error_string, + const LLUUID session_id) { - if (!hasSession(session_id)) return; + if (!hasSession(session_id)) return; - LLSD args; - args["REASON"] = LLTrans::getString(error_string); - args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); + LLSD args; + args["REASON"] = LLTrans::getString(error_string); + args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); - LLSD payload; - payload["session_id"] = session_id; + LLSD payload; + payload["session_id"] = session_id; - LLNotificationsUtil::add( - "ChatterBoxSessionStartError", - args, - payload, - LLIMMgr::onConfirmForceCloseError); + LLNotificationsUtil::add( + "ChatterBoxSessionStartError", + args, + payload, + LLIMMgr::onConfirmForceCloseError); } void LLIMMgr::showSessionEventError( - const std::string& event_string, - const std::string& error_string, - const LLUUID session_id) + const std::string& event_string, + const std::string& error_string, + const LLUUID session_id) { - LLSD args; - LLStringUtil::format_map_t event_args; + LLSD args; + LLStringUtil::format_map_t event_args; - event_args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); + event_args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); - args["REASON"] = - LLTrans::getString(error_string); - args["EVENT"] = - LLTrans::getString(event_string, event_args); + args["REASON"] = + LLTrans::getString(error_string); + args["EVENT"] = + LLTrans::getString(event_string, event_args); - LLNotificationsUtil::add( - "ChatterBoxSessionEventError", - args); + LLNotificationsUtil::add( + "ChatterBoxSessionEventError", + args); } void LLIMMgr::showSessionForceClose( - const std::string& reason_string, - const LLUUID session_id) + const std::string& reason_string, + const LLUUID session_id) { - if (!hasSession(session_id)) return; + if (!hasSession(session_id)) return; - LLSD args; + LLSD args; - args["NAME"] = LLIMModel::getInstance()->getName(session_id); - args["REASON"] = LLTrans::getString(reason_string); + args["NAME"] = LLIMModel::getInstance()->getName(session_id); + args["REASON"] = LLTrans::getString(reason_string); - LLSD payload; - payload["session_id"] = session_id; + LLSD payload; + payload["session_id"] = session_id; - LLNotificationsUtil::add( - "ForceCloseChatterBoxSession", - args, - payload, - LLIMMgr::onConfirmForceCloseError); + LLNotificationsUtil::add( + "ForceCloseChatterBoxSession", + args, + payload, + LLIMMgr::onConfirmForceCloseError); } //static bool LLIMMgr::onConfirmForceCloseError( - const LLSD& notification, - const LLSD& response) + const LLSD& notification, + const LLSD& response) { - //only 1 option really - LLUUID session_id = notification["payload"]["session_id"]; + //only 1 option really + LLUUID session_id = notification["payload"]["session_id"]; - LLFloater* floater = LLFloaterIMSession::findInstance(session_id); - if ( floater ) - { - floater->closeFloater(FALSE); - } - return false; + LLFloater* floater = LLFloaterIMSession::findInstance(session_id); + if ( floater ) + { + floater->closeFloater(FALSE); + } + return false; } @@ -2216,7 +2216,7 @@ LLCallDialogManager::~LLCallDialogManager() void LLCallDialogManager::initSingleton() { - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(LLCallDialogManager::onVoiceChannelChanged); + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(LLCallDialogManager::onVoiceChannelChanged); } // static @@ -2227,48 +2227,48 @@ void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id) void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id) { - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); - if(!session) - { - mPreviousSessionlName = mCurrentSessionlName; - mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution - return; - } - - mSession = session; - - static boost::signals2::connection prev_channel_state_changed_connection; - // disconnect previously connected callback to avoid have invalid sSession in onVoiceChannelStateChanged() - prev_channel_state_changed_connection.disconnect(); - prev_channel_state_changed_connection = - mSession->mVoiceChannel->setStateChangedCallback(boost::bind(LLCallDialogManager::onVoiceChannelStateChanged, _1, _2, _3, _4)); - - if(mCurrentSessionlName != session->mName) - { - mPreviousSessionlName = mCurrentSessionlName; - mCurrentSessionlName = session->mName; - } - - if (LLVoiceChannel::getCurrentVoiceChannel()->getState() == LLVoiceChannel::STATE_CALL_STARTED && - LLVoiceChannel::getCurrentVoiceChannel()->getCallDirection() == LLVoiceChannel::OUTGOING_CALL) - { - - //*TODO get rid of duplicated code - LLSD mCallDialogPayload; - mCallDialogPayload["session_id"] = mSession->mSessionID; - mCallDialogPayload["session_name"] = mSession->mName; - mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; - mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; - mCallDialogPayload["state"] = LLVoiceChannel::STATE_CALL_STARTED; - mCallDialogPayload["disconnected_channel_name"] = mSession->mName; - mCallDialogPayload["session_type"] = mSession->mSessionType; - - LLOutgoingCallDialog* ocd = LLFloaterReg::getTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if(ocd) - { - ocd->show(mCallDialogPayload); - } - } + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if(!session) + { + mPreviousSessionlName = mCurrentSessionlName; + mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution + return; + } + + mSession = session; + + static boost::signals2::connection prev_channel_state_changed_connection; + // disconnect previously connected callback to avoid have invalid sSession in onVoiceChannelStateChanged() + prev_channel_state_changed_connection.disconnect(); + prev_channel_state_changed_connection = + mSession->mVoiceChannel->setStateChangedCallback(boost::bind(LLCallDialogManager::onVoiceChannelStateChanged, _1, _2, _3, _4)); + + if(mCurrentSessionlName != session->mName) + { + mPreviousSessionlName = mCurrentSessionlName; + mCurrentSessionlName = session->mName; + } + + if (LLVoiceChannel::getCurrentVoiceChannel()->getState() == LLVoiceChannel::STATE_CALL_STARTED && + LLVoiceChannel::getCurrentVoiceChannel()->getCallDirection() == LLVoiceChannel::OUTGOING_CALL) + { + + //*TODO get rid of duplicated code + LLSD mCallDialogPayload; + mCallDialogPayload["session_id"] = mSession->mSessionID; + mCallDialogPayload["session_name"] = mSession->mName; + mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; + mCallDialogPayload["state"] = LLVoiceChannel::STATE_CALL_STARTED; + mCallDialogPayload["disconnected_channel_name"] = mSession->mName; + mCallDialogPayload["session_type"] = mSession->mSessionType; + + LLOutgoingCallDialog* ocd = LLFloaterReg::getTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if(ocd) + { + ocd->show(mCallDialogPayload); + } + } } @@ -2280,116 +2280,116 @@ void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EStat void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent) { - LLSD mCallDialogPayload; - LLOutgoingCallDialog* ocd = NULL; - - if(mOldState == new_state) - { - return; - } - - mOldState = new_state; - - mCallDialogPayload["session_id"] = mSession->mSessionID; - mCallDialogPayload["session_name"] = mSession->mName; - mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; - mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; - mCallDialogPayload["state"] = new_state; - mCallDialogPayload["disconnected_channel_name"] = mSession->mName; - mCallDialogPayload["session_type"] = mSession->mSessionType; - mCallDialogPayload["ended_by_agent"] = ended_by_agent; - - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - // do not show "Calling to..." if it is incoming call - if(direction == LLVoiceChannel::INCOMING_CALL) - { - return; - } - break; - - case LLVoiceChannel::STATE_HUNG_UP: - // this state is coming before session is changed - break; - - case LLVoiceChannel::STATE_CONNECTED : - ocd = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if (ocd) - { - ocd->closeFloater(); - } - return; - - default: - break; - } - - ocd = LLFloaterReg::getTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if(ocd) - { - ocd->show(mCallDialogPayload); - } + LLSD mCallDialogPayload; + LLOutgoingCallDialog* ocd = NULL; + + if(mOldState == new_state) + { + return; + } + + mOldState = new_state; + + mCallDialogPayload["session_id"] = mSession->mSessionID; + mCallDialogPayload["session_name"] = mSession->mName; + mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; + mCallDialogPayload["state"] = new_state; + mCallDialogPayload["disconnected_channel_name"] = mSession->mName; + mCallDialogPayload["session_type"] = mSession->mSessionType; + mCallDialogPayload["ended_by_agent"] = ended_by_agent; + + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + // do not show "Calling to..." if it is incoming call + if(direction == LLVoiceChannel::INCOMING_CALL) + { + return; + } + break; + + case LLVoiceChannel::STATE_HUNG_UP: + // this state is coming before session is changed + break; + + case LLVoiceChannel::STATE_CONNECTED : + ocd = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if (ocd) + { + ocd->closeFloater(); + } + return; + + default: + break; + } + + ocd = LLFloaterReg::getTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if(ocd) + { + ocd->show(mCallDialogPayload); + } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LLCallDialog::LLCallDialog(const LLSD& payload) - : LLDockableFloater(NULL, false, payload), + : LLDockableFloater(NULL, false, payload), - mPayload(payload), - mLifetime(DEFAULT_LIFETIME) + mPayload(payload), + mLifetime(DEFAULT_LIFETIME) { - setAutoFocus(FALSE); - // force docked state since this floater doesn't save it between recreations - setDocked(true); + setAutoFocus(FALSE); + // force docked state since this floater doesn't save it between recreations + setDocked(true); } LLCallDialog::~LLCallDialog() { - LLUI::getInstance()->removePopup(this); + LLUI::getInstance()->removePopup(this); } BOOL LLCallDialog::postBuild() { - if (!LLDockableFloater::postBuild() || !gToolBarView) - return FALSE; + if (!LLDockableFloater::postBuild() || !gToolBarView) + return FALSE; - dockToToolbarButton("speak"); + dockToToolbarButton("speak"); - return TRUE; + return TRUE; } void LLCallDialog::dockToToolbarButton(const std::string& toolbarButtonName) { - LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName); - LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName); + LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName); + LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName); - setUseTongue(anchor_panel); + setUseTongue(anchor_panel); - setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos)); + setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos)); } LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarButtonName) { - LLCommandId command_id(toolbarButtonName); - S32 toolbar_loc = gToolBarView->hasCommand(command_id); + LLCommandId command_id(toolbarButtonName); + S32 toolbar_loc = gToolBarView->hasCommand(command_id); - LLDockControl::DocAt doc_at = LLDockControl::TOP; + LLDockControl::DocAt doc_at = LLDockControl::TOP; - switch (toolbar_loc) - { - case LLToolBarEnums::TOOLBAR_LEFT: - doc_at = LLDockControl::RIGHT; - break; + switch (toolbar_loc) + { + case LLToolBarEnums::TOOLBAR_LEFT: + doc_at = LLDockControl::RIGHT; + break; - case LLToolBarEnums::TOOLBAR_RIGHT: - doc_at = LLDockControl::LEFT; - break; - } + case LLToolBarEnums::TOOLBAR_RIGHT: + doc_at = LLDockControl::LEFT; + break; + } - return doc_at; + return doc_at; } @@ -2399,237 +2399,237 @@ LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarB LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : LLCallDialog(payload) { - LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if(instance && instance->getVisible()) - { - instance->onCancel(instance); - } + LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if(instance && instance->getVisible()) + { + instance->onCancel(instance); + } } void LLCallDialog::draw() { - if (lifetimeHasExpired()) - { - onLifetimeExpired(); - } + if (lifetimeHasExpired()) + { + onLifetimeExpired(); + } - if (getDockControl() != NULL) - { - LLDockableFloater::draw(); - } + if (getDockControl() != NULL) + { + LLDockableFloater::draw(); + } } // virtual void LLCallDialog::onOpen(const LLSD& key) { - LLDockableFloater::onOpen(key); + LLDockableFloater::onOpen(key); - // it should be over the all floaters. EXT-5116 - LLUI::getInstance()->addPopup(this); + // it should be over the all floaters. EXT-5116 + LLUI::getInstance()->addPopup(this); } void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id) { - bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); + bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); - bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE); + bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE); - LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon"); - LLGroupIconCtrl* group_icon = getChild<LLGroupIconCtrl>("group_icon"); + LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon"); + LLGroupIconCtrl* group_icon = getChild<LLGroupIconCtrl>("group_icon"); - avatar_icon->setVisible(!is_group); - group_icon->setVisible(is_group); + avatar_icon->setVisible(!is_group); + group_icon->setVisible(is_group); - if (is_group) - { - group_icon->setValue(session_id); - } - else if (participant_is_avatar) - { - avatar_icon->setValue(participant_id); - } - else - { + if (is_group) + { + group_icon->setValue(session_id); + } + else if (participant_is_avatar) + { + avatar_icon->setValue(participant_id); + } + else + { LL_WARNS() << "Participant neither avatar nor group" << LL_ENDL; group_icon->setValue(session_id); - } + } } bool LLCallDialog::lifetimeHasExpired() { - if (mLifetimeTimer.getStarted()) - { - F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); - if (elapsed_time > mLifetime) - { - return true; - } - } - return false; + if (mLifetimeTimer.getStarted()) + { + F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); + if (elapsed_time > mLifetime) + { + return true; + } + } + return false; } void LLCallDialog::onLifetimeExpired() { - mLifetimeTimer.stop(); - closeFloater(); + mLifetimeTimer.stop(); + closeFloater(); } void LLOutgoingCallDialog::show(const LLSD& key) { - mPayload = key; - - //will be false only if voice in parcel is disabled and channel we leave is nearby(checked further) - bool show_oldchannel = LLViewerParcelMgr::getInstance()->allowAgentVoice(); - - // hide all text at first - hideAllText(); - - // init notification's lifetime - std::istringstream ss( getString("lifetime") ); - if (!(ss >> mLifetime)) - { - mLifetime = DEFAULT_LIFETIME; - } - - // customize text strings - // tell the user which voice channel they are leaving - if (!mPayload["old_channel_name"].asString().empty()) - { - std::string old_caller_name = mPayload["old_channel_name"].asString(); - - getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", old_caller_name); - show_oldchannel = true; - } - else - { - getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", getString("localchat")); - } - - if (!mPayload["disconnected_channel_name"].asString().empty()) - { - std::string channel_name = mPayload["disconnected_channel_name"].asString(); - getChild<LLUICtrl>("nearby")->setTextArg("[VOICE_CHANNEL_NAME]", channel_name); - - // skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice, - // so no reconnection to nearby chat happens (EXT-4397) - bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); - std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string(); - getChild<LLUICtrl>("nearby")->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); - - const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; - getChild<LLUICtrl>(nearby_str)->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); - } - - std::string callee_name = mPayload["session_name"].asString(); - - if (callee_name == "anonymous") // obsolete? Likely was part of avaline support - { - callee_name = getString("anonymous"); - } - - LLSD callee_id = mPayload["other_user_id"]; - // Beautification: Since you know who you called, just show display name - std::string title = callee_name; - std::string final_callee_name = callee_name; - if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(callee_id, &av_name)) - { - final_callee_name = av_name.getDisplayName(); - title = av_name.getCompleteName(); - } - } - getChild<LLUICtrl>("calling")->setTextArg("[CALLEE_NAME]", final_callee_name); - getChild<LLUICtrl>("connecting")->setTextArg("[CALLEE_NAME]", final_callee_name); - - setTitle(title); - - // for outgoing group calls callee_id == group id == session id - setIcon(callee_id, callee_id); - - // stop timer by default - mLifetimeTimer.stop(); - - // show only necessary strings and controls - switch(mPayload["state"].asInteger()) - { - case LLVoiceChannel::STATE_CALL_STARTED : - getChild<LLTextBox>("calling")->setVisible(true); - getChild<LLButton>("Cancel")->setVisible(true); - if(show_oldchannel) - { - getChild<LLTextBox>("leaving")->setVisible(true); - } - break; - // STATE_READY is here to show appropriate text for ad-hoc and group calls when floater is shown(EXT-6893) - case LLVoiceChannel::STATE_READY : - case LLVoiceChannel::STATE_RINGING : - if(show_oldchannel) - { - getChild<LLTextBox>("leaving")->setVisible(true); - } - getChild<LLTextBox>("connecting")->setVisible(true); - break; - case LLVoiceChannel::STATE_ERROR : - getChild<LLTextBox>("noanswer")->setVisible(true); - getChild<LLButton>("Cancel")->setVisible(false); - setCanClose(true); - mLifetimeTimer.start(); - break; - case LLVoiceChannel::STATE_HUNG_UP : - if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) - { - const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; - getChild<LLTextBox>(nearby_str)->setVisible(true); - } - else - { - getChild<LLTextBox>("nearby")->setVisible(true); - } - getChild<LLButton>("Cancel")->setVisible(false); - setCanClose(true); - mLifetimeTimer.start(); - } - - openFloater(LLOutgoingCallDialog::OCD_KEY); + mPayload = key; + + //will be false only if voice in parcel is disabled and channel we leave is nearby(checked further) + bool show_oldchannel = LLViewerParcelMgr::getInstance()->allowAgentVoice(); + + // hide all text at first + hideAllText(); + + // init notification's lifetime + std::istringstream ss( getString("lifetime") ); + if (!(ss >> mLifetime)) + { + mLifetime = DEFAULT_LIFETIME; + } + + // customize text strings + // tell the user which voice channel they are leaving + if (!mPayload["old_channel_name"].asString().empty()) + { + std::string old_caller_name = mPayload["old_channel_name"].asString(); + + getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", old_caller_name); + show_oldchannel = true; + } + else + { + getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", getString("localchat")); + } + + if (!mPayload["disconnected_channel_name"].asString().empty()) + { + std::string channel_name = mPayload["disconnected_channel_name"].asString(); + getChild<LLUICtrl>("nearby")->setTextArg("[VOICE_CHANNEL_NAME]", channel_name); + + // skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice, + // so no reconnection to nearby chat happens (EXT-4397) + bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); + std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string(); + getChild<LLUICtrl>("nearby")->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); + + const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; + getChild<LLUICtrl>(nearby_str)->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); + } + + std::string callee_name = mPayload["session_name"].asString(); + + if (callee_name == "anonymous") // obsolete? Likely was part of avaline support + { + callee_name = getString("anonymous"); + } + + LLSD callee_id = mPayload["other_user_id"]; + // Beautification: Since you know who you called, just show display name + std::string title = callee_name; + std::string final_callee_name = callee_name; + if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(callee_id, &av_name)) + { + final_callee_name = av_name.getDisplayName(); + title = av_name.getCompleteName(); + } + } + getChild<LLUICtrl>("calling")->setTextArg("[CALLEE_NAME]", final_callee_name); + getChild<LLUICtrl>("connecting")->setTextArg("[CALLEE_NAME]", final_callee_name); + + setTitle(title); + + // for outgoing group calls callee_id == group id == session id + setIcon(callee_id, callee_id); + + // stop timer by default + mLifetimeTimer.stop(); + + // show only necessary strings and controls + switch(mPayload["state"].asInteger()) + { + case LLVoiceChannel::STATE_CALL_STARTED : + getChild<LLTextBox>("calling")->setVisible(true); + getChild<LLButton>("Cancel")->setVisible(true); + if(show_oldchannel) + { + getChild<LLTextBox>("leaving")->setVisible(true); + } + break; + // STATE_READY is here to show appropriate text for ad-hoc and group calls when floater is shown(EXT-6893) + case LLVoiceChannel::STATE_READY : + case LLVoiceChannel::STATE_RINGING : + if(show_oldchannel) + { + getChild<LLTextBox>("leaving")->setVisible(true); + } + getChild<LLTextBox>("connecting")->setVisible(true); + break; + case LLVoiceChannel::STATE_ERROR : + getChild<LLTextBox>("noanswer")->setVisible(true); + getChild<LLButton>("Cancel")->setVisible(false); + setCanClose(true); + mLifetimeTimer.start(); + break; + case LLVoiceChannel::STATE_HUNG_UP : + if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) + { + const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; + getChild<LLTextBox>(nearby_str)->setVisible(true); + } + else + { + getChild<LLTextBox>("nearby")->setVisible(true); + } + getChild<LLButton>("Cancel")->setVisible(false); + setCanClose(true); + mLifetimeTimer.start(); + } + + openFloater(LLOutgoingCallDialog::OCD_KEY); } void LLOutgoingCallDialog::hideAllText() { - getChild<LLTextBox>("calling")->setVisible(false); - getChild<LLTextBox>("leaving")->setVisible(false); - getChild<LLTextBox>("connecting")->setVisible(false); - getChild<LLTextBox>("nearby_P2P_by_other")->setVisible(false); - getChild<LLTextBox>("nearby_P2P_by_agent")->setVisible(false); - getChild<LLTextBox>("nearby")->setVisible(false); - getChild<LLTextBox>("noanswer")->setVisible(false); + getChild<LLTextBox>("calling")->setVisible(false); + getChild<LLTextBox>("leaving")->setVisible(false); + getChild<LLTextBox>("connecting")->setVisible(false); + getChild<LLTextBox>("nearby_P2P_by_other")->setVisible(false); + getChild<LLTextBox>("nearby_P2P_by_agent")->setVisible(false); + getChild<LLTextBox>("nearby")->setVisible(false); + getChild<LLTextBox>("noanswer")->setVisible(false); } //static void LLOutgoingCallDialog::onCancel(void* user_data) { - LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; + LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; - if (!gIMMgr) - return; + if (!gIMMgr) + return; - LLUUID session_id = self->mPayload["session_id"].asUUID(); - gIMMgr->endCall(session_id); + LLUUID session_id = self->mPayload["session_id"].asUUID(); + gIMMgr->endCall(session_id); - self->closeFloater(); + self->closeFloater(); } BOOL LLOutgoingCallDialog::postBuild() { - BOOL success = LLCallDialog::postBuild(); + BOOL success = LLCallDialog::postBuild(); - childSetAction("Cancel", onCancel, this); + childSetAction("Cancel", onCancel, this); - setCanDrag(FALSE); + setCanDrag(FALSE); - return success; + return success; } @@ -2658,26 +2658,26 @@ mAvatarNameCacheConnection() void LLIncomingCallDialog::onLifetimeExpired() { - std::string session_handle = mPayload["session_handle"].asString(); - if (LLVoiceClient::getInstance()->isValidChannel(session_handle)) - { - // restart notification's timer if call is still valid - mLifetimeTimer.start(); - } - else - { - // close invitation if call is already not valid - mLifetimeTimer.stop(); - LLUUID session_id = mPayload["session_id"].asUUID(); - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - closeFloater(); - } + std::string session_handle = mPayload["session_handle"].asString(); + if (LLVoiceClient::getInstance()->isValidChannel(session_handle)) + { + // restart notification's timer if call is still valid + mLifetimeTimer.start(); + } + else + { + // close invitation if call is already not valid + mLifetimeTimer.stop(); + LLUUID session_id = mPayload["session_id"].asUUID(); + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + closeFloater(); + } } BOOL LLIncomingCallDialog::postBuild() { - LLCallDialog::postBuild(); + LLCallDialog::postBuild(); if (!mPayload.isMap() || mPayload.size() == 0) { @@ -2685,9 +2685,9 @@ BOOL LLIncomingCallDialog::postBuild() return TRUE; } - LLUUID session_id = mPayload["session_id"].asUUID(); - LLSD caller_id = mPayload["caller_id"]; - std::string caller_name = mPayload["caller_name"].asString(); + LLUUID session_id = mPayload["session_id"].asUUID(); + LLSD caller_id = mPayload["caller_id"]; + std::string caller_name = mPayload["caller_name"].asString(); if (session_id.isNull() && caller_id.asUUID().isNull()) { @@ -2702,347 +2702,347 @@ BOOL LLIncomingCallDialog::postBuild() return TRUE; } - // init notification's lifetime - std::istringstream ss( getString("lifetime") ); - if (!(ss >> mLifetime)) - { - mLifetime = DEFAULT_LIFETIME; - } - - std::string call_type; - if (gAgent.isInGroup(session_id, TRUE)) - { - LLStringUtil::format_map_t args; - LLGroupData data; - if (gAgent.getGroupData(session_id, data)) - { - args["[GROUP]"] = data.mName; - call_type = getString(notify_box_type, args); - } - } - else - { - call_type = getString(notify_box_type); - } - - if (caller_name == "anonymous") // obsolete? Likely was part of avaline support - { - caller_name = getString("anonymous"); - setCallerName(caller_name, caller_name, call_type); - } - else - { - // Get the full name information - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - mAvatarNameCacheConnection = LLAvatarNameCache::get(caller_id, boost::bind(&LLIncomingCallDialog::onAvatarNameCache, this, _1, _2, call_type)); - } - - setIcon(session_id, caller_id); - - childSetAction("Accept", onAccept, this); - childSetAction("Reject", onReject, this); - childSetAction("Start IM", onStartIM, this); - setDefaultBtn("Accept"); - - if(notify_box_type != "VoiceInviteGroup" && notify_box_type != "VoiceInviteAdHoc") - { - // starting notification's timer for P2P invitations - mLifetimeTimer.start(); - } - else - { - mLifetimeTimer.stop(); - } - - //it's not possible to connect to existing Ad-Hoc/Group chat through incoming ad-hoc call - bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); - getChildView("Start IM")->setVisible( is_avatar && notify_box_type != "VoiceInviteAdHoc" && notify_box_type != "VoiceInviteGroup"); - - setCanDrag(FALSE); - return TRUE; + // init notification's lifetime + std::istringstream ss( getString("lifetime") ); + if (!(ss >> mLifetime)) + { + mLifetime = DEFAULT_LIFETIME; + } + + std::string call_type; + if (gAgent.isInGroup(session_id, TRUE)) + { + LLStringUtil::format_map_t args; + LLGroupData data; + if (gAgent.getGroupData(session_id, data)) + { + args["[GROUP]"] = data.mName; + call_type = getString(notify_box_type, args); + } + } + else + { + call_type = getString(notify_box_type); + } + + if (caller_name == "anonymous") // obsolete? Likely was part of avaline support + { + caller_name = getString("anonymous"); + setCallerName(caller_name, caller_name, call_type); + } + else + { + // Get the full name information + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + mAvatarNameCacheConnection = LLAvatarNameCache::get(caller_id, boost::bind(&LLIncomingCallDialog::onAvatarNameCache, this, _1, _2, call_type)); + } + + setIcon(session_id, caller_id); + + childSetAction("Accept", onAccept, this); + childSetAction("Reject", onReject, this); + childSetAction("Start IM", onStartIM, this); + setDefaultBtn("Accept"); + + if(notify_box_type != "VoiceInviteGroup" && notify_box_type != "VoiceInviteAdHoc") + { + // starting notification's timer for P2P invitations + mLifetimeTimer.start(); + } + else + { + mLifetimeTimer.stop(); + } + + //it's not possible to connect to existing Ad-Hoc/Group chat through incoming ad-hoc call + bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); + getChildView("Start IM")->setVisible( is_avatar && notify_box_type != "VoiceInviteAdHoc" && notify_box_type != "VoiceInviteGroup"); + + setCanDrag(FALSE); + return TRUE; } void LLIncomingCallDialog::setCallerName(const std::string& ui_title, - const std::string& ui_label, - const std::string& call_type) + const std::string& ui_label, + const std::string& call_type) { - // call_type may be a string like " is calling." - LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); - caller_name_widget->setValue(ui_label + " " + call_type); + // call_type may be a string like " is calling." + LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); + caller_name_widget->setValue(ui_label + " " + call_type); } void LLIncomingCallDialog::onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name, - const std::string& call_type) + const LLAvatarName& av_name, + const std::string& call_type) { - mAvatarNameCacheConnection.disconnect(); - std::string title = av_name.getCompleteName(); - setCallerName(title, av_name.getCompleteName(), call_type); + mAvatarNameCacheConnection.disconnect(); + std::string title = av_name.getCompleteName(); + setCallerName(title, av_name.getCompleteName(), call_type); } void LLIncomingCallDialog::onOpen(const LLSD& key) { - LLCallDialog::onOpen(key); + LLCallDialog::onOpen(key); - if (gSavedSettings.getBOOL("PlaySoundIncomingVoiceCall")) - { - // play a sound for incoming voice call if respective property is set - make_ui_sound("UISndStartIM"); - } + if (gSavedSettings.getBOOL("PlaySoundIncomingVoiceCall")) + { + // play a sound for incoming voice call if respective property is set + make_ui_sound("UISndStartIM"); + } - LLStringUtil::format_map_t args; - LLGroupData data; - // if it's a group call, retrieve group name to use it in question - if (gAgent.getGroupData(key["session_id"].asUUID(), data)) - { - args["[GROUP]"] = data.mName; - } + LLStringUtil::format_map_t args; + LLGroupData data; + // if it's a group call, retrieve group name to use it in question + if (gAgent.getGroupData(key["session_id"].asUUID(), data)) + { + args["[GROUP]"] = data.mName; + } } //static void LLIncomingCallDialog::onAccept(void* user_data) { - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - processCallResponse(0, self->mPayload); - self->closeFloater(); + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + processCallResponse(0, self->mPayload); + self->closeFloater(); } //static void LLIncomingCallDialog::onReject(void* user_data) { - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - processCallResponse(1, self->mPayload); - self->closeFloater(); + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + processCallResponse(1, self->mPayload); + self->closeFloater(); } //static void LLIncomingCallDialog::onStartIM(void* user_data) { - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - processCallResponse(2, self->mPayload); - self->closeFloater(); + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + processCallResponse(2, self->mPayload); + self->closeFloater(); } // static void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload) { - if (!gIMMgr || gDisconnected) - return; - - LLUUID session_id = payload["session_id"].asUUID(); - LLUUID caller_id = payload["caller_id"].asUUID(); - std::string session_name = payload["session_name"].asString(); - EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); - LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); - bool voice = true; - switch(response) - { - case 2: // start IM: just don't start the voice chat - { - voice = false; - /* FALLTHROUGH */ - } - case 0: // accept - { - if (type == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - session_id = gIMMgr->addP2PSession( - session_name, - caller_id, - payload["session_handle"].asString(), - payload["session_uri"].asString()); - - if (voice) - { - gIMMgr->startCall(session_id, LLVoiceChannel::INCOMING_CALL); - } - else - { - LLAvatarActions::startIM(caller_id); - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } - else - { - //session name should not be empty, but it can contain spaces so we don't trim - std::string correct_session_name = session_name; - if (session_name.empty()) - { - LL_WARNS() << "Received an empty session name from a server" << LL_ENDL; - - switch(type){ - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_GROUP_START: - case IM_SESSION_INVITE: - if (gAgent.isInGroup(session_id, TRUE)) - { - LLGroupData data; - if (!gAgent.getGroupData(session_id, data)) break; - correct_session_name = data.mName; - } - else - { - // *NOTE: really should be using callbacks here - LLAvatarName av_name; - if (LLAvatarNameCache::get(caller_id, &av_name)) - { - correct_session_name = av_name.getCompleteName(); - correct_session_name.append(ADHOC_NAME_SUFFIX); - } - } - LL_INFOS("IMVIEW") << "Corrected session name is " << correct_session_name << LL_ENDL; - break; - default: - LL_WARNS("IMVIEW") << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; - break; - } - } - - gIMMgr->addSession(correct_session_name, type, session_id, true); - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - if (voice) - { - LLCoros::instance().launch("chatterBoxInvitationCoro", - boost::bind(&chatterBoxInvitationCoro, url, - session_id, inv_type)); - - // send notification message to the corresponding chat - if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") - { - LLStringUtil::format_map_t string_args; - string_args["[NAME]"] = payload["caller_name"].asString(); - std::string message = LLTrans::getString("name_started_call", string_args); - LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message); - } - } - } - if (voice) - { - break; - } - } - case 1: // decline - { - if (type == IM_SESSION_P2P_INVITE) - { - if(LLVoiceClient::getInstance()) - { - std::string s = payload["session_handle"].asString(); - LLVoiceClient::getInstance()->declineInvite(s); - } - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = session_id; + if (!gIMMgr || gDisconnected) + return; - LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, - "Invitation declined", - "Invitation decline failed."); - } - } + LLUUID session_id = payload["session_id"].asUUID(); + LLUUID caller_id = payload["caller_id"].asUUID(); + std::string session_name = payload["session_name"].asString(); + EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); + bool voice = true; + switch(response) + { + case 2: // start IM: just don't start the voice chat + { + voice = false; + /* FALLTHROUGH */ + } + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + session_name, + caller_id, + payload["session_handle"].asString(), + payload["session_uri"].asString()); + + if (voice) + { + gIMMgr->startCall(session_id, LLVoiceChannel::INCOMING_CALL); + } + else + { + LLAvatarActions::startIM(caller_id); + } - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + //session name should not be empty, but it can contain spaces so we don't trim + std::string correct_session_name = session_name; + if (session_name.empty()) + { + LL_WARNS() << "Received an empty session name from a server" << LL_ENDL; + + switch(type){ + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_GROUP_START: + case IM_SESSION_INVITE: + if (gAgent.isInGroup(session_id, TRUE)) + { + LLGroupData data; + if (!gAgent.getGroupData(session_id, data)) break; + correct_session_name = data.mName; + } + else + { + // *NOTE: really should be using callbacks here + LLAvatarName av_name; + if (LLAvatarNameCache::get(caller_id, &av_name)) + { + correct_session_name = av_name.getCompleteName(); + correct_session_name.append(ADHOC_NAME_SUFFIX); + } + } + LL_INFOS("IMVIEW") << "Corrected session name is " << correct_session_name << LL_ENDL; + break; + default: + LL_WARNS("IMVIEW") << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; + break; + } + } + + gIMMgr->addSession(correct_session_name, type, session_id, true); + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + if (voice) + { + LLCoros::instance().launch("chatterBoxInvitationCoro", + boost::bind(&chatterBoxInvitationCoro, url, + session_id, inv_type)); + + // send notification message to the corresponding chat + if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") + { + LLStringUtil::format_map_t string_args; + string_args["[NAME]"] = payload["caller_name"].asString(); + std::string message = LLTrans::getString("name_started_call", string_args); + LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message); + } + } + } + if (voice) + { + break; + } + } + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + if(LLVoiceClient::getInstance()) + { + std::string s = payload["session_handle"].asString(); + LLVoiceClient::getInstance()->declineInvite(s); + } + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, + "Invitation declined", + "Invitation decline failed."); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } } bool inviteUserResponse(const LLSD& notification, const LLSD& response) { - if (!gIMMgr) - return false; - - const LLSD& payload = notification["payload"]; - LLUUID session_id = payload["session_id"].asUUID(); - EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); - LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - switch(option) - { - case 0: // accept - { - if (type == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - session_id = gIMMgr->addP2PSession( - payload["session_name"].asString(), - payload["caller_id"].asUUID(), - payload["session_handle"].asString(), - payload["session_uri"].asString()); - - gIMMgr->startCall(session_id); - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } - else - { - gIMMgr->addSession( - payload["session_name"].asString(), - type, - session_id, true); - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); + if (!gIMMgr) + return false; + + const LLSD& payload = notification["payload"]; + LLUUID session_id = payload["session_id"].asUUID(); + EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + payload["session_name"].asString(), + payload["caller_id"].asUUID(), + payload["session_handle"].asString(), + payload["session_uri"].asString()); + + gIMMgr->startCall(session_id); + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + gIMMgr->addSession( + payload["session_name"].asString(), + type, + session_id, true); + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); LLCoros::instance().launch("chatterBoxInvitationCoro", boost::bind(&chatterBoxInvitationCoro, url, session_id, inv_type)); - } - } - break; - case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) - { - // mute the sender of this invite - if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) - { - LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); - LLMuteList::getInstance()->add(mute); - } - } - /* FALLTHROUGH */ - - case 1: // decline - { - if (type == IM_SESSION_P2P_INVITE) - { - std::string s = payload["session_handle"].asString(); - LLVoiceClient::getInstance()->declineInvite(s); - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = session_id; + } + } + break; + case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) + { + // mute the sender of this invite + if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) + { + LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); + LLMuteList::getInstance()->add(mute); + } + } + /* FALLTHROUGH */ + + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + std::string s = payload["session_handle"].asString(); + LLVoiceClient::getInstance()->declineInvite(s); + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, "Invitation declined.", "Invitation decline failed."); - } - } + } + } - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - break; - } + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + break; + } - return false; + return false; } // @@ -3051,113 +3051,113 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLIMMgr::LLIMMgr() { - mPendingInvitations = LLSD::emptyMap(); - mPendingAgentListUpdates = LLSD::emptyMap(); + mPendingInvitations = LLSD::emptyMap(); + mPendingAgentListUpdates = LLSD::emptyMap(); - LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLFloaterIMSession::sRemoveTypingIndicator, _1)); + LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLFloaterIMSession::sRemoveTypingIndicator, _1)); - gSavedPerAccountSettings.declareBOOL("FetchGroupChatHistory", TRUE, "Fetch recent messages from group chat servers when a group window opens", LLControlVariable::PERSIST_ALWAYS); + gSavedPerAccountSettings.declareBOOL("FetchGroupChatHistory", TRUE, "Fetch recent messages from group chat servers when a group window opens", LLControlVariable::PERSIST_ALWAYS); } // Add a message to a session. void LLIMMgr::addMessage( - const LLUUID& session_id, - const LLUUID& target_id, - const std::string& from, - const std::string& msg, - bool is_offline_msg, - const std::string& session_name, - EInstantMessage dialog, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, + const LLUUID& session_id, + const LLUUID& target_id, + const std::string& from, + const std::string& msg, + bool is_offline_msg, + const std::string& session_name, + EInstantMessage dialog, + U32 parent_estate_id, + const LLUUID& region_id, + const LLVector3& position, bool is_region_msg, U32 timestamp) // May be zero { - LLUUID other_participant_id = target_id; - - LLUUID new_session_id = session_id; - if (new_session_id.isNull()) - { - //no session ID...compute new one - new_session_id = computeSessionID(dialog, other_participant_id); - } - - //*NOTE session_name is empty in case of incoming P2P sessions - std::string fixed_session_name = from; - bool name_is_setted = false; - if(!session_name.empty() && session_name.size()>1) - { - fixed_session_name = session_name; - name_is_setted = true; - } - bool skip_message = false; - bool from_linden = LLMuteList::isLinden(from); + LLUUID other_participant_id = target_id; + + LLUUID new_session_id = session_id; + if (new_session_id.isNull()) + { + //no session ID...compute new one + new_session_id = computeSessionID(dialog, other_participant_id); + } + + //*NOTE session_name is empty in case of incoming P2P sessions + std::string fixed_session_name = from; + bool name_is_setted = false; + if(!session_name.empty() && session_name.size()>1) + { + fixed_session_name = session_name; + name_is_setted = true; + } + bool skip_message = false; + bool from_linden = LLMuteList::isLinden(from); if (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && !from_linden) - { - // Evaluate if we need to skip this message when that setting is true (default is false) - skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... - skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself - } - - bool new_session = !hasSession(new_session_id); - if (new_session) - { - // Group chat session was initiated by muted resident, do not start this session viewerside - // do not send leave msg either, so we are able to get group messages from other participants - if ((IM_SESSION_INVITE == dialog) && gAgent.isInGroup(new_session_id) && - LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) - { - return; - } - - LLAvatarName av_name; - if (LLAvatarNameCache::get(other_participant_id, &av_name) && !name_is_setted) - { - fixed_session_name = av_name.getDisplayName(); - } - LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); - - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); - if (session) - { - skip_message &= !session->isGroupSessionType(); // Do not skip group chats... - if (skip_message) - { - gIMMgr->leaveSession(new_session_id); - } - // When we get a new IM, and if you are a god, display a bit - // of information about the source. This is to help liaisons - // when answering questions. - if (gAgent.isGodlike()) - { - // *TODO:translate (low priority, god ability) - std::ostringstream bonus_info; - bonus_info << LLTrans::getString("***") + " " + LLTrans::getString("IMParentEstate") + ":" + " " - << parent_estate_id - << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") - << ((parent_estate_id == 5) ? "," + LLTrans::getString("IMTeen") : ""); - - // once we have web-services (or something) which returns - // information about a region id, we can print this out - // and even have it link to map-teleport or something. - //<< "*** region_id: " << region_id << std::endl - //<< "*** position: " << position << std::endl; - - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str(), true, is_region_msg); - } - - // Logically it would make more sense to reject the session sooner, in another area of the - // code, but the session has to be established inside the server before it can be left. - if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) - { - LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; - if (!gIMMgr->leaveSession(new_session_id)) - { - LL_INFOS("IMVIEW") << "Session " << new_session_id << " does not exist." << LL_ENDL; - } - return; - } + { + // Evaluate if we need to skip this message when that setting is true (default is false) + skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... + skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself + } + + bool new_session = !hasSession(new_session_id); + if (new_session) + { + // Group chat session was initiated by muted resident, do not start this session viewerside + // do not send leave msg either, so we are able to get group messages from other participants + if ((IM_SESSION_INVITE == dialog) && gAgent.isInGroup(new_session_id) && + LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + return; + } + + LLAvatarName av_name; + if (LLAvatarNameCache::get(other_participant_id, &av_name) && !name_is_setted) + { + fixed_session_name = av_name.getDisplayName(); + } + LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); + + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); + if (session) + { + skip_message &= !session->isGroupSessionType(); // Do not skip group chats... + if (skip_message) + { + gIMMgr->leaveSession(new_session_id); + } + // When we get a new IM, and if you are a god, display a bit + // of information about the source. This is to help liaisons + // when answering questions. + if (gAgent.isGodlike()) + { + // *TODO:translate (low priority, god ability) + std::ostringstream bonus_info; + bonus_info << LLTrans::getString("***") + " " + LLTrans::getString("IMParentEstate") + ":" + " " + << parent_estate_id + << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") + << ((parent_estate_id == 5) ? "," + LLTrans::getString("IMTeen") : ""); + + // once we have web-services (or something) which returns + // information about a region id, we can print this out + // and even have it link to map-teleport or something. + //<< "*** region_id: " << region_id << std::endl + //<< "*** position: " << position << std::endl; + + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str(), true, is_region_msg); + } + + // Logically it would make more sense to reject the session sooner, in another area of the + // code, but the session has to be established inside the server before it can be left. + if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; + if (!gIMMgr->leaveSession(new_session_id)) + { + LL_INFOS("IMVIEW") << "Session " << new_session_id << " does not exist." << LL_ENDL; + } + return; + } // Fetch group chat history, enabled by default. if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) @@ -3169,131 +3169,131 @@ void LLIMMgr::addMessage( } } - //Play sound for new conversations - if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } - } - else - { - // Failed to create a session, most likely due to empty name (name cache failed?) - LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL; - } - } - - if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) - { - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp); - } - - // Open conversation floater if offline messages are present - if (is_offline_msg && !skip_message) + //Play sound for new conversations + if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else + { + // Failed to create a session, most likely due to empty name (name cache failed?) + LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL; + } + } + + if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) + { + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp); + } + + // Open conversation floater if offline messages are present + if (is_offline_msg && !skip_message) { LLFloaterReg::showInstance("im_container"); - LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")-> - flashConversationItemWidget(new_session_id, true); + LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")-> + flashConversationItemWidget(new_session_id, true); } } void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args) { - LLUIString message; - - // null session id means near me (chat history) - if (session_id.isNull()) - { - message = LLTrans::getString(message_name); - message.setArgs(args); - - LLChat chat(message); - chat.mSourceType = CHAT_SOURCE_SYSTEM; - - LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); - if (nearby_chat) - { - nearby_chat->addMessage(chat); - } - } - else // going to IM session - { - message = LLTrans::getString(message_name + "-im"); - message.setArgs(args); - if (hasSession(session_id)) - { - gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); - } - // log message to file - - else - { - LLAvatarName av_name; - // since we select user to share item with - his name is already in cache - LLAvatarNameCache::get(args["user_id"], &av_name); - std::string session_name = LLCacheName::buildUsername(av_name.getUserName()); - LLIMModel::instance().logToFile(session_name, SYSTEM_FROM, LLUUID::null, message.getString()); - } - } + LLUIString message; + + // null session id means near me (chat history) + if (session_id.isNull()) + { + message = LLTrans::getString(message_name); + message.setArgs(args); + + LLChat chat(message); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if (nearby_chat) + { + nearby_chat->addMessage(chat); + } + } + else // going to IM session + { + message = LLTrans::getString(message_name + "-im"); + message.setArgs(args); + if (hasSession(session_id)) + { + gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); + } + // log message to file + + else + { + LLAvatarName av_name; + // since we select user to share item with - his name is already in cache + LLAvatarNameCache::get(args["user_id"], &av_name); + std::string session_name = LLCacheName::buildUsername(av_name.getUserName()); + LLIMModel::instance().logToFile(session_name, SYSTEM_FROM, LLUUID::null, message.getString()); + } + } } S32 LLIMMgr::getNumberOfUnreadIM() { - std::map<LLUUID, LLIMModel::LLIMSession*>::iterator it; + std::map<LLUUID, LLIMModel::LLIMSession*>::iterator it; - S32 num = 0; - for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - num += (*it).second->mNumUnread; - } + S32 num = 0; + for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + num += (*it).second->mNumUnread; + } - return num; + return num; } S32 LLIMMgr::getNumberOfUnreadParticipantMessages() { - std::map<LLUUID, LLIMModel::LLIMSession*>::iterator it; + std::map<LLUUID, LLIMModel::LLIMSession*>::iterator it; - S32 num = 0; - for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - num += (*it).second->mParticipantUnreadMessageCount; - } + S32 num = 0; + for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + num += (*it).second->mParticipantUnreadMessageCount; + } - return num; + return num; } void LLIMMgr::autoStartCallOnStartup(const LLUUID& session_id) { - LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id); - if (!session) return; + LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id); + if (!session) return; - if (session->mSessionInitialized) - { - startCall(session_id); - } - else - { - session->mStartCallOnInitialize = true; - } + if (session->mSessionInitialized) + { + startCall(session_id); + } + else + { + session->mStartCallOnInitialize = true; + } } LLUUID LLIMMgr::addP2PSession(const std::string& name, - const LLUUID& other_participant_id, - const std::string& voice_session_handle, - const std::string& caller_uri) + const LLUUID& other_participant_id, + const std::string& voice_session_handle, + const std::string& caller_uri) { - LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id, true); + LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id, true); - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - LLVoiceChannelP2P* voice_channel = dynamic_cast<LLVoiceChannelP2P*>(speaker_mgr->getVoiceChannel()); - if (voice_channel) - { - voice_channel->setSessionHandle(voice_session_handle, caller_uri); - } - } - return session_id; + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + LLVoiceChannelP2P* voice_channel = dynamic_cast<LLVoiceChannelP2P*>(speaker_mgr->getVoiceChannel()); + if (voice_channel) + { + voice_channel->setSessionHandle(voice_session_handle, caller_uri); + } + } + return session_id; } // This adds a session to the talk view. The name is the local name of @@ -3301,70 +3301,70 @@ LLUUID LLIMMgr::addP2PSession(const std::string& name, // exists, it is brought forward. Specifying id = NULL results in an // im session to everyone. Returns the uuid of the session. LLUUID LLIMMgr::addSession( - const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, bool voice) + const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, bool voice) { - std::vector<LLUUID> ids; - ids.push_back(other_participant_id); - LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice); - return session_id; + std::vector<LLUUID> ids; + ids.push_back(other_participant_id); + LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice); + return session_id; } // Adds a session using the given session_id. If the session already exists // the dialog type is assumed correct. Returns the uuid of the session. LLUUID LLIMMgr::addSession( - const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, - const std::vector<LLUUID>& ids, bool voice, - const LLUUID& floater_id) -{ - if (ids.empty()) - { - return LLUUID::null; - } - - if (name.empty()) - { - LL_WARNS() << "Session name cannot be null!" << LL_ENDL; - return LLUUID::null; - } - - LLUUID session_id = computeSessionID(dialog,other_participant_id); - - if (floater_id.notNull()) - { - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(floater_id); - - if (im_floater) - { - // The IM floater should be initialized with a new session_id - // so that it is found by that id when creating a chiclet in LLFloaterIMSession::onIMChicletCreated, - // and a new floater is not created. - im_floater->initIMSession(session_id); + const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, + const std::vector<LLUUID>& ids, bool voice, + const LLUUID& floater_id) +{ + if (ids.empty()) + { + return LLUUID::null; + } + + if (name.empty()) + { + LL_WARNS() << "Session name cannot be null!" << LL_ENDL; + return LLUUID::null; + } + + LLUUID session_id = computeSessionID(dialog,other_participant_id); + + if (floater_id.notNull()) + { + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(floater_id); + + if (im_floater) + { + // The IM floater should be initialized with a new session_id + // so that it is found by that id when creating a chiclet in LLFloaterIMSession::onIMChicletCreated, + // and a new floater is not created. + im_floater->initIMSession(session_id); im_floater->reloadMessages(); - } - } - - bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); - - //works only for outgoing ad-hoc sessions - if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) - { - LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids); - if (ad_hoc_found) - { - new_session = false; - session_id = ad_hoc_found->mSessionID; - } - } + } + } + + bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); + + //works only for outgoing ad-hoc sessions + if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) + { + LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids); + if (ad_hoc_found) + { + new_session = false; + session_id = ad_hoc_found->mSessionID; + } + } //Notify observers that a session was added - if (new_session) - { - LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice); - } + if (new_session) + { + LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice); + } //Notifies observers that the session was already added else { @@ -3372,334 +3372,334 @@ LLUUID LLIMMgr::addSession( LLIMMgr::getInstance()->notifyObserverSessionActivated(session_id, session_name, other_participant_id); } - //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions - if (!new_session) return session_id; + //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions + if (!new_session) return session_id; LL_INFOS("IMVIEW") << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << LL_ENDL; - //Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609) - //*TODO After February 2010 remove this commented out line if no one will be missing that warning - //noteOfflineUsers(session_id, floater, ids); + //Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609) + //*TODO After February 2010 remove this commented out line if no one will be missing that warning + //noteOfflineUsers(session_id, floater, ids); - // Only warn for regular IMs - not group IMs - if( dialog == IM_NOTHING_SPECIAL ) - { - noteMutedUsers(session_id, ids); - } + // Only warn for regular IMs - not group IMs + if( dialog == IM_NOTHING_SPECIAL ) + { + noteMutedUsers(session_id, ids); + } - notifyObserverSessionVoiceOrIMStarted(session_id); + notifyObserverSessionVoiceOrIMStarted(session_id); - return session_id; + return session_id; } bool LLIMMgr::leaveSession(const LLUUID& session_id) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; - LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID); - gIMMgr->removeSession(session_id); - return true; + LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID); + gIMMgr->removeSession(session_id); + return true; } // Removes data associated with a particular session specified by session_id void LLIMMgr::removeSession(const LLUUID& session_id) { - llassert_always(hasSession(session_id)); + llassert_always(hasSession(session_id)); - clearPendingInvitation(session_id); - clearPendingAgentListUpdates(session_id); + clearPendingInvitation(session_id); + clearPendingAgentListUpdates(session_id); - LLIMModel::getInstance()->clearSession(session_id); + LLIMModel::getInstance()->clearSession(session_id); LL_INFOS("IMVIEW") << "LLIMMgr::removeSession, session removed, session id = " << session_id << LL_ENDL; - notifyObserverSessionRemoved(session_id); + notifyObserverSessionRemoved(session_id); } void LLIMMgr::inviteToSession( - const LLUUID& session_id, - const std::string& session_name, - const LLUUID& caller_id, - const std::string& caller_name, - EInstantMessage type, - EInvitationType inv_type, - const std::string& session_handle, - const std::string& session_uri) -{ - std::string notify_box_type; - // voice invite question is different from default only for group call (EXT-7118) - std::string question_type = "VoiceInviteQuestionDefault"; - - BOOL voice_invite = FALSE; - bool is_linden = LLMuteList::isLinden(caller_name); - - - if(type == IM_SESSION_P2P_INVITE) - { - //P2P is different...they only have voice invitations - notify_box_type = "VoiceInviteP2P"; - voice_invite = TRUE; - } - else if ( gAgent.isInGroup(session_id, TRUE) ) - { - //only really old school groups have voice invitations - notify_box_type = "VoiceInviteGroup"; - question_type = "VoiceInviteQuestionGroup"; - voice_invite = TRUE; - } - else if ( inv_type == INVITATION_TYPE_VOICE ) - { - //else it's an ad-hoc - //and a voice ad-hoc - notify_box_type = "VoiceInviteAdHoc"; - voice_invite = TRUE; - } - else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) - { - notify_box_type = "InviteAdHoc"; - } - - LLSD payload; - payload["session_id"] = session_id; - payload["session_name"] = session_name; - payload["caller_id"] = caller_id; - payload["caller_name"] = caller_name; - payload["type"] = type; - payload["inv_type"] = inv_type; - payload["session_handle"] = session_handle; - payload["session_uri"] = session_uri; - payload["notify_box_type"] = notify_box_type; - payload["question_type"] = question_type; - - //ignore invites from muted residents - if (!is_linden) - { - if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagVoiceChat) - && voice_invite && "VoiceInviteQuestionDefault" == question_type) - { - LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; - LLIncomingCallDialog::processCallResponse(1, payload); - return; - } - else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite) - { - LL_INFOS("IMVIEW") << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; - return; - } - } - - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); - if (channelp && channelp->callStarted()) - { - // you have already started a call to the other user, so just accept the invite - LLIncomingCallDialog::processCallResponse(0, payload); - return; - } - - if (voice_invite) - { - bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup")); + const LLUUID& session_id, + const std::string& session_name, + const LLUUID& caller_id, + const std::string& caller_name, + EInstantMessage type, + EInvitationType inv_type, + const std::string& session_handle, + const std::string& session_uri) +{ + std::string notify_box_type; + // voice invite question is different from default only for group call (EXT-7118) + std::string question_type = "VoiceInviteQuestionDefault"; + + BOOL voice_invite = FALSE; + bool is_linden = LLMuteList::isLinden(caller_name); + + + if(type == IM_SESSION_P2P_INVITE) + { + //P2P is different...they only have voice invitations + notify_box_type = "VoiceInviteP2P"; + voice_invite = TRUE; + } + else if ( gAgent.isInGroup(session_id, TRUE) ) + { + //only really old school groups have voice invitations + notify_box_type = "VoiceInviteGroup"; + question_type = "VoiceInviteQuestionGroup"; + voice_invite = TRUE; + } + else if ( inv_type == INVITATION_TYPE_VOICE ) + { + //else it's an ad-hoc + //and a voice ad-hoc + notify_box_type = "VoiceInviteAdHoc"; + voice_invite = TRUE; + } + else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) + { + notify_box_type = "InviteAdHoc"; + } + + LLSD payload; + payload["session_id"] = session_id; + payload["session_name"] = session_name; + payload["caller_id"] = caller_id; + payload["caller_name"] = caller_name; + payload["type"] = type; + payload["inv_type"] = inv_type; + payload["session_handle"] = session_handle; + payload["session_uri"] = session_uri; + payload["notify_box_type"] = notify_box_type; + payload["question_type"] = question_type; + + //ignore invites from muted residents + if (!is_linden) + { + if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagVoiceChat) + && voice_invite && "VoiceInviteQuestionDefault" == question_type) + { + LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; + LLIncomingCallDialog::processCallResponse(1, payload); + return; + } + else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite) + { + LL_INFOS("IMVIEW") << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; + return; + } + } + + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); + if (channelp && channelp->callStarted()) + { + // you have already started a call to the other user, so just accept the invite + LLIncomingCallDialog::processCallResponse(0, payload); + return; + } + + if (voice_invite) + { + bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup")); bool isRejectNonFriendCall = (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)); - if (isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb()) - { - if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall) - { - if (!hasSession(session_id) && (type == IM_SESSION_P2P_INVITE)) - { - std::string fixed_session_name = caller_name; - if(!session_name.empty() && session_name.size()>1) - { - fixed_session_name = session_name; - } - else - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(caller_id, &av_name)) - { - fixed_session_name = av_name.getDisplayName(); - } - } - LLIMModel::getInstance()->newSession(session_id, fixed_session_name, IM_NOTHING_SPECIAL, caller_id, false, false); - } - - LLSD args; - addSystemMessage(session_id, "you_auto_rejected_call", args); - send_do_not_disturb_message(gMessageSystem, caller_id, session_id); - } - // silently decline the call - LLIncomingCallDialog::processCallResponse(1, payload); - return; - } - } - - if ( !mPendingInvitations.has(session_id.asString()) ) - { - if (caller_name.empty()) - { - LLAvatarNameCache::get(caller_id, - boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2)); - } - else - { - LLFloaterReg::showInstance("incoming_call", payload, FALSE); - } - - // Add the caller to the Recent List here (at this point - // "incoming_call" floater is shown and the recipient can - // reject the call), because even if a recipient will reject - // the call, the caller should be added to the recent list - // anyway. STORM-507. - if(type == IM_SESSION_P2P_INVITE) - LLRecentPeople::instance().add(caller_id); - - mPendingInvitations[session_id.asString()] = LLSD(); - } + if (isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb()) + { + if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall) + { + if (!hasSession(session_id) && (type == IM_SESSION_P2P_INVITE)) + { + std::string fixed_session_name = caller_name; + if(!session_name.empty() && session_name.size()>1) + { + fixed_session_name = session_name; + } + else + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(caller_id, &av_name)) + { + fixed_session_name = av_name.getDisplayName(); + } + } + LLIMModel::getInstance()->newSession(session_id, fixed_session_name, IM_NOTHING_SPECIAL, caller_id, false, false); + } + + LLSD args; + addSystemMessage(session_id, "you_auto_rejected_call", args); + send_do_not_disturb_message(gMessageSystem, caller_id, session_id); + } + // silently decline the call + LLIncomingCallDialog::processCallResponse(1, payload); + return; + } + } + + if ( !mPendingInvitations.has(session_id.asString()) ) + { + if (caller_name.empty()) + { + LLAvatarNameCache::get(caller_id, + boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2)); + } + else + { + LLFloaterReg::showInstance("incoming_call", payload, FALSE); + } + + // Add the caller to the Recent List here (at this point + // "incoming_call" floater is shown and the recipient can + // reject the call), because even if a recipient will reject + // the call, the caller should be added to the recent list + // anyway. STORM-507. + if(type == IM_SESSION_P2P_INVITE) + LLRecentPeople::instance().add(caller_id); + + mPendingInvitations[session_id.asString()] = LLSD(); + } } void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const LLAvatarName& av_name) { - payload["caller_name"] = av_name.getUserName(); - payload["session_name"] = payload["caller_name"].asString(); + payload["caller_name"] = av_name.getUserName(); + payload["session_name"] = payload["caller_name"].asString(); - std::string notify_box_type = payload["notify_box_type"].asString(); + std::string notify_box_type = payload["notify_box_type"].asString(); - LLFloaterReg::showInstance("incoming_call", payload, FALSE); + LLFloaterReg::showInstance("incoming_call", payload, FALSE); } //*TODO disconnects all sessions void LLIMMgr::disconnectAllSessions() { - //*TODO disconnects all IM sessions + //*TODO disconnects all IM sessions } BOOL LLIMMgr::hasSession(const LLUUID& session_id) { - return LLIMModel::getInstance()->findIMSession(session_id) != NULL; + return LLIMModel::getInstance()->findIMSession(session_id) != NULL; } void LLIMMgr::clearPendingInvitation(const LLUUID& session_id) { - if ( mPendingInvitations.has(session_id.asString()) ) - { - mPendingInvitations.erase(session_id.asString()); - } + if ( mPendingInvitations.has(session_id.asString()) ) + { + mPendingInvitations.erase(session_id.asString()); + } } void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body) { - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - im_floater->processAgentListUpdates(body); - } - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - speaker_mgr->updateSpeakers(body); - - // also the same call is added into LLVoiceClient::participantUpdatedEvent because - // sometimes it is called AFTER LLViewerChatterBoxSessionAgentListUpdates::post() - // when moderation state changed too late. See EXT-3544. - speaker_mgr->update(true); - } - else - { - //we don't have a speaker manager yet..something went wrong - //we are probably receiving an update here before - //a start or an acceptance of an invitation. Race condition. - gIMMgr->addPendingAgentListUpdates( - session_id, - body); - } + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + im_floater->processAgentListUpdates(body); + } + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->updateSpeakers(body); + + // also the same call is added into LLVoiceClient::participantUpdatedEvent because + // sometimes it is called AFTER LLViewerChatterBoxSessionAgentListUpdates::post() + // when moderation state changed too late. See EXT-3544. + speaker_mgr->update(true); + } + else + { + //we don't have a speaker manager yet..something went wrong + //we are probably receiving an update here before + //a start or an acceptance of an invitation. Race condition. + gIMMgr->addPendingAgentListUpdates( + session_id, + body); + } } LLSD LLIMMgr::getPendingAgentListUpdates(const LLUUID& session_id) { - if ( mPendingAgentListUpdates.has(session_id.asString()) ) - { - return mPendingAgentListUpdates[session_id.asString()]; - } - else - { - return LLSD(); - } + if ( mPendingAgentListUpdates.has(session_id.asString()) ) + { + return mPendingAgentListUpdates[session_id.asString()]; + } + else + { + return LLSD(); + } } void LLIMMgr::addPendingAgentListUpdates( - const LLUUID& session_id, - const LLSD& updates) -{ - LLSD::map_const_iterator iter; - - if ( !mPendingAgentListUpdates.has(session_id.asString()) ) - { - //this is a new agent list update for this session - mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap(); - } - - if ( - updates.has("agent_updates") && - updates["agent_updates"].isMap() && - updates.has("updates") && - updates["updates"].isMap() ) - { - //new school update - LLSD update_types = LLSD::emptyArray(); - LLSD::array_iterator array_iter; - - update_types.append("agent_updates"); - update_types.append("updates"); - - for ( - array_iter = update_types.beginArray(); - array_iter != update_types.endArray(); - ++array_iter) - { - //we only want to include the last update for a given agent - for ( - iter = updates[array_iter->asString()].beginMap(); - iter != updates[array_iter->asString()].endMap(); - ++iter) - { - mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] = - iter->second; - } - } - } - else if ( - updates.has("updates") && - updates["updates"].isMap() ) - { - //old school update where the SD contained just mappings - //of agent_id -> "LEAVE"/"ENTER" - - //only want to keep last update for each agent - for ( - iter = updates["updates"].beginMap(); - iter != updates["updates"].endMap(); - ++iter) - { - mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] = - iter->second; - } - } + const LLUUID& session_id, + const LLSD& updates) +{ + LLSD::map_const_iterator iter; + + if ( !mPendingAgentListUpdates.has(session_id.asString()) ) + { + //this is a new agent list update for this session + mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap(); + } + + if ( + updates.has("agent_updates") && + updates["agent_updates"].isMap() && + updates.has("updates") && + updates["updates"].isMap() ) + { + //new school update + LLSD update_types = LLSD::emptyArray(); + LLSD::array_iterator array_iter; + + update_types.append("agent_updates"); + update_types.append("updates"); + + for ( + array_iter = update_types.beginArray(); + array_iter != update_types.endArray(); + ++array_iter) + { + //we only want to include the last update for a given agent + for ( + iter = updates[array_iter->asString()].beginMap(); + iter != updates[array_iter->asString()].endMap(); + ++iter) + { + mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] = + iter->second; + } + } + } + else if ( + updates.has("updates") && + updates["updates"].isMap() ) + { + //old school update where the SD contained just mappings + //of agent_id -> "LEAVE"/"ENTER" + + //only want to keep last update for each agent + for ( + iter = updates["updates"].beginMap(); + iter != updates["updates"].endMap(); + ++iter) + { + mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] = + iter->second; + } + } } void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id) { - if ( mPendingAgentListUpdates.has(session_id.asString()) ) - { - mPendingAgentListUpdates.erase(session_id.asString()); - } + if ( mPendingAgentListUpdates.has(session_id.asString()) ) + { + mPendingAgentListUpdates.erase(session_id.asString()); + } } void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionAdded(session_id, name, other_participant_id, has_offline_msg); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionAdded(session_id, name, other_participant_id, has_offline_msg); + } } void LLIMMgr::notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) @@ -3712,239 +3712,239 @@ void LLIMMgr::notifyObserverSessionActivated(const LLUUID& session_id, const std void LLIMMgr::notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionVoiceOrIMStarted(session_id); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionVoiceOrIMStarted(session_id); + } } void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionRemoved(session_id); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionRemoved(session_id); + } } void LLIMMgr::notifyObserverSessionIDUpdated( const LLUUID& old_session_id, const LLUUID& new_session_id ) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionIDUpdated(old_session_id, new_session_id); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionIDUpdated(old_session_id, new_session_id); + } } void LLIMMgr::addSessionObserver(LLIMSessionObserver *observer) { - mSessionObservers.push_back(observer); + mSessionObservers.push_back(observer); } void LLIMMgr::removeSessionObserver(LLIMSessionObserver *observer) { - mSessionObservers.remove(observer); + mSessionObservers.remove(observer); } bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection direction) { - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); - if (!voice_channel) return false; + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); + if (!voice_channel) return false; - voice_channel->setCallDirection(direction); - voice_channel->activate(); - return true; + voice_channel->setCallDirection(direction); + voice_channel->activate(); + return true; } bool LLIMMgr::endCall(const LLUUID& session_id) { - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); - if (!voice_channel) return false; + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); + if (!voice_channel) return false; - voice_channel->deactivate(); - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (im_session) - { - // need to update speakers' state - im_session->mSpeakers->update(FALSE); - } - return true; + voice_channel->deactivate(); + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (im_session) + { + // need to update speakers' state + im_session->mSpeakers->update(FALSE); + } + return true; } bool LLIMMgr::isVoiceCall(const LLUUID& session_id) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; - return im_session->mStartedAsIMCall; + return im_session->mStartedAsIMCall; } void LLIMMgr::updateDNDMessageStatus() { - if (LLIMModel::getInstance()->mId2SessionMap.empty()) return; + if (LLIMModel::getInstance()->mId2SessionMap.empty()) return; - std::map<LLUUID, LLIMModel::LLIMSession*>::const_iterator it = LLIMModel::getInstance()->mId2SessionMap.begin(); - for (; it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - LLIMModel::LLIMSession* session = (*it).second; + std::map<LLUUID, LLIMModel::LLIMSession*>::const_iterator it = LLIMModel::getInstance()->mId2SessionMap.begin(); + for (; it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + LLIMModel::LLIMSession* session = (*it).second; - if (session->isP2P()) - { - setDNDMessageSent(session->mSessionID,false); - } - } + if (session->isP2P()) + { + setDNDMessageSent(session->mSessionID,false); + } + } } bool LLIMMgr::isDNDMessageSend(const LLUUID& session_id) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; - return im_session->mIsDNDsend; + return im_session->mIsDNDsend; } void LLIMMgr::setDNDMessageSent(const LLUUID& session_id, bool is_send) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return; - im_session->mIsDNDsend = is_send; + im_session->mIsDNDsend = is_send; } void LLIMMgr::addNotifiedNonFriendSessionID(const LLUUID& session_id) { - mNotifiedNonFriendSessions.insert(session_id); + mNotifiedNonFriendSessions.insert(session_id); } bool LLIMMgr::isNonFriendSessionNotified(const LLUUID& session_id) { - return mNotifiedNonFriendSessions.end() != mNotifiedNonFriendSessions.find(session_id); + return mNotifiedNonFriendSessions.end() != mNotifiedNonFriendSessions.find(session_id); } void LLIMMgr::noteOfflineUsers( - const LLUUID& session_id, - const std::vector<LLUUID>& ids) -{ - S32 count = ids.size(); - if(count == 0) - { - const std::string& only_user = LLTrans::getString("only_user_message"); - LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, only_user); - } - else - { - const LLRelationship* info = NULL; - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLIMModel& im_model = LLIMModel::instance(); - for(S32 i = 0; i < count; ++i) - { - info = at.getBuddyInfo(ids.at(i)); - LLAvatarName av_name; - if (info - && !info->isOnline() - && LLAvatarNameCache::get(ids.at(i), &av_name)) - { - LLUIString offline = LLTrans::getString("offline_message"); - // Use display name only because this user is your friend - offline.setArg("[NAME]", av_name.getDisplayName()); - im_model.proccessOnlineOfflineNotification(session_id, offline); - } - } - } + const LLUUID& session_id, + const std::vector<LLUUID>& ids) +{ + S32 count = ids.size(); + if(count == 0) + { + const std::string& only_user = LLTrans::getString("only_user_message"); + LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, only_user); + } + else + { + const LLRelationship* info = NULL; + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLIMModel& im_model = LLIMModel::instance(); + for(S32 i = 0; i < count; ++i) + { + info = at.getBuddyInfo(ids.at(i)); + LLAvatarName av_name; + if (info + && !info->isOnline() + && LLAvatarNameCache::get(ids.at(i), &av_name)) + { + LLUIString offline = LLTrans::getString("offline_message"); + // Use display name only because this user is your friend + offline.setArg("[NAME]", av_name.getDisplayName()); + im_model.proccessOnlineOfflineNotification(session_id, offline); + } + } + } } void LLIMMgr::noteMutedUsers(const LLUUID& session_id, - const std::vector<LLUUID>& ids) + const std::vector<LLUUID>& ids) { - // Don't do this if we don't have a mute list. - LLMuteList *ml = LLMuteList::getInstance(); - if( !ml ) - { - return; - } + // Don't do this if we don't have a mute list. + LLMuteList *ml = LLMuteList::getInstance(); + if( !ml ) + { + return; + } - S32 count = ids.size(); - if(count > 0) - { - LLIMModel* im_model = LLIMModel::getInstance(); + S32 count = ids.size(); + if(count > 0) + { + LLIMModel* im_model = LLIMModel::getInstance(); - for(S32 i = 0; i < count; ++i) - { - if( ml->isMuted(ids.at(i)) ) - { - LLUIString muted = LLTrans::getString("muted_message"); + for(S32 i = 0; i < count; ++i) + { + if( ml->isMuted(ids.at(i)) ) + { + LLUIString muted = LLTrans::getString("muted_message"); - im_model->addMessage(session_id, SYSTEM_FROM, LLUUID::null, muted); - break; - } - } - } + im_model->addMessage(session_id, SYSTEM_FROM, LLUUID::null, muted); + break; + } + } + } } void LLIMMgr::processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(from_id, im_type, TRUE); + processIMTypingCore(from_id, im_type, TRUE); } void LLIMMgr::processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(from_id, im_type, FALSE); + processIMTypingCore(from_id, im_type, FALSE); } void LLIMMgr::processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing) { - LLUUID session_id = computeSessionID(im_type, from_id); - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - im_floater->processIMTyping(from_id, typing); - } + LLUUID session_id = computeSessionID(im_type, from_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + im_floater->processIMTyping(from_id, typing); + } } class LLViewerChatterBoxSessionStartReply : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); - desc.postAPI(); - desc.input( - "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLSD body; - LLUUID temp_session_id; - LLUUID session_id; - bool success; - - body = input["body"]; - success = body["success"].asBoolean(); - temp_session_id = body["temp_session_id"].asUUID(); - - if ( success ) - { - session_id = body["session_id"].asUUID(); - - LLIMModel::getInstance()->processSessionInitializedReply(temp_session_id, session_id); - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - speaker_mgr->setSpeakers(body); - speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); - } - - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - if ( body.has("session_info") ) - { - im_floater->processSessionUpdate(body["session_info"]); + virtual void describe(Description& desc) const + { + desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); + desc.postAPI(); + desc.input( + "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string"); + desc.source(__FILE__, __LINE__); + } + + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLSD body; + LLUUID temp_session_id; + LLUUID session_id; + bool success; + + body = input["body"]; + success = body["success"].asBoolean(); + temp_session_id = body["temp_session_id"].asUUID(); + + if ( success ) + { + session_id = body["session_id"].asUUID(); + + LLIMModel::getInstance()->processSessionInitializedReply(temp_session_id, session_id); + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->setSpeakers(body); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); + } + + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + if ( body.has("session_info") ) + { + im_floater->processSessionUpdate(body["session_info"]); // Send request for chat history, if enabled. if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) @@ -3954,104 +3954,104 @@ public: boost::bind(&chatterBoxHistoryCoro, url, session_id, "", "", 0)); } } - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - } - else - { - //throw an error dialog and close the temp session's floater - gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id); - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + } + else + { + //throw an error dialog and close the temp session's floater + gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id); + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + } }; class LLViewerChatterBoxSessionEventReply : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); - desc.postAPI(); - desc.input( - "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id; - bool success; - - LLSD body = input["body"]; - success = body["success"].asBoolean(); - session_id = body["session_id"].asUUID(); - - if ( !success ) - { - //throw an error dialog - gIMMgr->showSessionEventError( - body["event"].asString(), - body["error"].asString(), - session_id); - } - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); + desc.postAPI(); + desc.input( + "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID"); + desc.source(__FILE__, __LINE__); + } + + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id; + bool success; + + LLSD body = input["body"]; + success = body["success"].asBoolean(); + session_id = body["session_id"].asUUID(); + + if ( !success ) + { + //throw an error dialog + gIMMgr->showSessionEventError( + body["event"].asString(), + body["error"].asString(), + session_id); + } + } }; class LLViewerForceCloseChatterBoxSession: public LLHTTPNode { public: - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id; - std::string reason; - - session_id = input["body"]["session_id"].asUUID(); - reason = input["body"]["reason"].asString(); - - gIMMgr->showSessionForceClose(reason, session_id); - } + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id; + std::string reason; + + session_id = input["body"]["session_id"].asUUID(); + reason = input["body"]["reason"].asString(); + + gIMMgr->showSessionForceClose(reason, session_id); + } }; class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode { public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - const LLUUID& session_id = input["body"]["session_id"].asUUID(); - gIMMgr->processAgentListUpdates(session_id, input["body"]); - } + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + const LLUUID& session_id = input["body"]["session_id"].asUUID(); + gIMMgr->processAgentListUpdates(session_id, input["body"]); + } }; class LLViewerChatterBoxSessionUpdate : public LLHTTPNode { public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id = input["body"]["session_id"].asUUID(); - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - im_floater->processSessionUpdate(input["body"]["info"]); - } - LLIMSpeakerMgr* im_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (im_mgr) - { - im_mgr->processSessionUpdate(input["body"]["info"]); - } - } + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id = input["body"]["session_id"].asUUID(); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + im_floater->processSessionUpdate(input["body"]["info"]); + } + LLIMSpeakerMgr* im_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (im_mgr) + { + im_mgr->processSessionUpdate(input["body"]["info"]); + } + } }; @@ -4059,135 +4059,135 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode { public: - virtual void post( - ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - //for backwards compatiblity reasons...we need to still - //check for 'text' or 'voice' invitations...bleh - if ( input["body"].has("instantmessage") ) - { - LLSD message_params = - input["body"]["instantmessage"]["message_params"]; - - //do something here to have the IM invite behave - //just like a normal IM - //this is just replicated code from process_improved_im - //and should really go in it's own function -jwolk - - std::string message = message_params["message"].asString(); - std::string name = message_params["from_name"].asString(); - LLUUID from_id = message_params["from_id"].asUUID(); - LLUUID session_id = message_params["id"].asUUID(); - std::vector<U8> bin_bucket = message_params["data"]["binary_bucket"].asBinary(); - U8 offline = (U8)message_params["offline"].asInteger(); - - time_t timestamp = - (time_t) message_params["timestamp"].asInteger(); - - BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - - //don't return if user is muted b/c proper way to ignore a muted user who - //initiated an adhoc/group conference is to create then leave the session (see STORM-1731) - if (is_do_not_disturb) - { - return; - } - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - std::string buffer = saved + message; - - if(from_id == gAgentID) - { - return; - } - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - IM_OFFLINE == offline, - std::string((char*)&bin_bucket[0]), - IM_SESSION_INVITE, - message_params["parent_estate_id"].asInteger(), - message_params["region_id"].asUUID(), - ll_vector3_from_sd(message_params["position"]), + virtual void post( + ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + //for backwards compatiblity reasons...we need to still + //check for 'text' or 'voice' invitations...bleh + if ( input["body"].has("instantmessage") ) + { + LLSD message_params = + input["body"]["instantmessage"]["message_params"]; + + //do something here to have the IM invite behave + //just like a normal IM + //this is just replicated code from process_improved_im + //and should really go in it's own function -jwolk + + std::string message = message_params["message"].asString(); + std::string name = message_params["from_name"].asString(); + LLUUID from_id = message_params["from_id"].asUUID(); + LLUUID session_id = message_params["id"].asUUID(); + std::vector<U8> bin_bucket = message_params["data"]["binary_bucket"].asBinary(); + U8 offline = (U8)message_params["offline"].asInteger(); + + time_t timestamp = + (time_t) message_params["timestamp"].asInteger(); + + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); + + //don't return if user is muted b/c proper way to ignore a muted user who + //initiated an adhoc/group conference is to create then leave the session (see STORM-1731) + if (is_do_not_disturb) + { + return; + } + + // standard message, not from system + std::string saved; + if(offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + std::string buffer = saved + message; + + if(from_id == gAgentID) + { + return; + } + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + IM_OFFLINE == offline, + std::string((char*)&bin_bucket[0]), + IM_SESSION_INVITE, + message_params["parent_estate_id"].asInteger(), + message_params["region_id"].asUUID(), + ll_vector3_from_sd(message_params["position"]), false, // is_region_message timestamp); - if (LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat)) - { - return; - } + if (LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat)) + { + return; + } - //K now we want to accept the invitation - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + //K now we want to accept the invitation + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - if ( url != "" ) - { + if ( url != "" ) + { LLCoros::instance().launch("chatterBoxInvitationCoro", boost::bind(&chatterBoxInvitationCoro, url, session_id, LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); - } - } //end if invitation has instant message - else if ( input["body"].has("voice") ) - { - if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking()) - { - // Don't display voice invites unless the user has voice enabled. - return; - } - - gIMMgr->inviteToSession( - input["body"]["session_id"].asUUID(), - input["body"]["session_name"].asString(), - input["body"]["from_id"].asUUID(), - input["body"]["from_name"].asString(), - IM_SESSION_INVITE, - LLIMMgr::INVITATION_TYPE_VOICE); - } - else if ( input["body"].has("immediate") ) - { - gIMMgr->inviteToSession( - input["body"]["session_id"].asUUID(), - input["body"]["session_name"].asString(), - input["body"]["from_id"].asUUID(), - input["body"]["from_name"].asString(), - IM_SESSION_INVITE, - LLIMMgr::INVITATION_TYPE_IMMEDIATE); - } - } + } + } //end if invitation has instant message + else if ( input["body"].has("voice") ) + { + if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking()) + { + // Don't display voice invites unless the user has voice enabled. + return; + } + + gIMMgr->inviteToSession( + input["body"]["session_id"].asUUID(), + input["body"]["session_name"].asString(), + input["body"]["from_id"].asUUID(), + input["body"]["from_name"].asString(), + IM_SESSION_INVITE, + LLIMMgr::INVITATION_TYPE_VOICE); + } + else if ( input["body"].has("immediate") ) + { + gIMMgr->inviteToSession( + input["body"]["session_id"].asUUID(), + input["body"]["session_name"].asString(), + input["body"]["from_id"].asUUID(), + input["body"]["from_name"].asString(), + IM_SESSION_INVITE, + LLIMMgr::INVITATION_TYPE_IMMEDIATE); + } + } }; LLHTTPRegistration<LLViewerChatterBoxSessionStartReply> gHTTPRegistrationMessageChatterboxsessionstartreply( - "/message/ChatterBoxSessionStartReply"); + "/message/ChatterBoxSessionStartReply"); LLHTTPRegistration<LLViewerChatterBoxSessionEventReply> gHTTPRegistrationMessageChatterboxsessioneventreply( - "/message/ChatterBoxSessionEventReply"); + "/message/ChatterBoxSessionEventReply"); LLHTTPRegistration<LLViewerForceCloseChatterBoxSession> gHTTPRegistrationMessageForceclosechatterboxsession( - "/message/ForceCloseChatterBoxSession"); + "/message/ForceCloseChatterBoxSession"); LLHTTPRegistration<LLViewerChatterBoxSessionAgentListUpdates> gHTTPRegistrationMessageChatterboxsessionagentlistupdates( - "/message/ChatterBoxSessionAgentListUpdates"); + "/message/ChatterBoxSessionAgentListUpdates"); LLHTTPRegistration<LLViewerChatterBoxSessionUpdate> gHTTPRegistrationMessageChatterBoxSessionUpdate( - "/message/ChatterBoxSessionUpdate"); + "/message/ChatterBoxSessionUpdate"); LLHTTPRegistration<LLViewerChatterBoxInvitation> gHTTPRegistrationMessageChatterBoxInvitation( - "/message/ChatterBoxInvitation"); + "/message/ChatterBoxInvitation"); diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index f0e3e26a86..a8c1f28ad5 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -1,25 +1,25 @@ -/** +/** * @file LLIMMgr.h * @brief Container for Instant Messaging * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,7 +40,7 @@ class LLAvatarName; class LLFriendObserver; -class LLCallDialogManager; +class LLCallDialogManager; class LLIMSpeakerMgr; /** @@ -49,12 +49,12 @@ class LLIMSpeakerMgr; class LLSessionTimeoutTimer : public LLEventTimer { public: - LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {} - virtual ~LLSessionTimeoutTimer() {}; - bool tick() override; + LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {} + virtual ~LLSessionTimeoutTimer() {}; + bool tick() override; private: - LLUUID mSessionId; + LLUUID mSessionId; }; @@ -63,30 +63,30 @@ private: */ class LLIMModel : public LLSingleton<LLIMModel> { - LLSINGLETON(LLIMModel); + LLSINGLETON(LLIMModel); public: typedef std::list<LLSD> chat_message_list_t; struct LLIMSession : public boost::signals2::trackable - { + { typedef enum e_session_type - { // for now we have 4 predefined types for a session - P2P_SESSION, - GROUP_SESSION, - ADHOC_SESSION, - NONE_SESSION, - } SType; - - LLIMSession(const LLUUID& session_id, const std::string& name, - const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg); - virtual ~LLIMSession(); - - void sessionInitReplyReceived(const LLUUID& new_session_id); - void addMessagesFromHistoryCache(const std::list<LLSD>& history); // From local file + { // for now we have 4 predefined types for a session + P2P_SESSION, + GROUP_SESSION, + ADHOC_SESSION, + NONE_SESSION, + } SType; + + LLIMSession(const LLUUID& session_id, const std::string& name, + const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg); + virtual ~LLIMSession(); + + void sessionInitReplyReceived(const LLUUID& new_session_id); + void addMessagesFromHistoryCache(const std::list<LLSD>& history); // From local file void addMessagesFromServerHistory(const LLSD& history, const std::string& target_from, const std::string& target_message, U32 timestamp); // From chat server - void addMessage(const std::string& from, + void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time, @@ -96,135 +96,135 @@ public: void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction); - /** @deprecated */ - static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); + /** @deprecated */ + static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); - bool isOutgoingAdHoc() const; - bool isAdHoc(); - bool isP2P(); - bool isGroupChat(); + bool isOutgoingAdHoc() const; + bool isAdHoc(); + bool isP2P(); + bool isGroupChat(); - bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} - bool isAdHocSessionType() const { return mSessionType == ADHOC_SESSION;} - bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;} + bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} + bool isAdHocSessionType() const { return mSessionType == ADHOC_SESSION;} + bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;} - LLUUID generateOutgoingAdHocHash() const; + LLUUID generateOutgoingAdHocHash() const; - //*TODO make private - /** ad-hoc sessions involve sophisticated chat history file naming schemes */ - void buildHistoryFileName(); + //*TODO make private + /** ad-hoc sessions involve sophisticated chat history file naming schemes */ + void buildHistoryFileName(); - void loadHistory(); + void loadHistory(); - LLUUID mSessionID; - std::string mName; - EInstantMessage mType; - SType mSessionType; - LLUUID mOtherParticipantID; - uuid_vec_t mInitialTargetIDs; - std::string mHistoryFileName; + LLUUID mSessionID; + std::string mName; + EInstantMessage mType; + SType mSessionType; + LLUUID mOtherParticipantID; + uuid_vec_t mInitialTargetIDs; + std::string mHistoryFileName; // Saved messages from the last minute of history read from the local group chat cache file std::string mLastHistoryCacheDateTime; chat_message_list_t mLastHistoryCacheMsgs; - // connection to voice channel state change signal - boost::signals2::connection mVoiceChannelStateChangeConnection; + // connection to voice channel state change signal + boost::signals2::connection mVoiceChannelStateChangeConnection; - //does NOT include system messages and agent's messages - S32 mParticipantUnreadMessageCount; + //does NOT include system messages and agent's messages + S32 mParticipantUnreadMessageCount; - // does include all incoming messages - S32 mNumUnread; + // does include all incoming messages + S32 mNumUnread; chat_message_list_t mMsgs; - LLVoiceChannel* mVoiceChannel; - LLIMSpeakerMgr* mSpeakers; + LLVoiceChannel* mVoiceChannel; + LLIMSpeakerMgr* mSpeakers; + + bool mSessionInitialized; + + //true if calling back the session URI after the session has closed is possible. + //Currently this will be false only for PSTN P2P calls. + bool mCallBackEnabled; - bool mSessionInitialized; + bool mTextIMPossible; + bool mStartCallOnInitialize; - //true if calling back the session URI after the session has closed is possible. - //Currently this will be false only for PSTN P2P calls. - bool mCallBackEnabled; + //if IM session is created for a voice call + bool mStartedAsIMCall; - bool mTextIMPossible; - bool mStartCallOnInitialize; + bool mHasOfflineMessage; - //if IM session is created for a voice call - bool mStartedAsIMCall; + bool mIsDNDsend; - bool mHasOfflineMessage; + private: + void onAdHocNameCache(const LLAvatarName& av_name); - bool mIsDNDsend; + static LLUUID generateHash(const std::set<LLUUID>& sorted_uuids); + boost::signals2::connection mAvatarNameCacheConnection; + }; - private: - void onAdHocNameCache(const LLAvatarName& av_name); - static LLUUID generateHash(const std::set<LLUUID>& sorted_uuids); - boost::signals2::connection mAvatarNameCacheConnection; - }; - + /** Session id to session object */ + std::map<LLUUID, LLIMSession*> mId2SessionMap; - /** Session id to session object */ - std::map<LLUUID, LLIMSession*> mId2SessionMap; + typedef boost::signals2::signal<void(const LLSD&)> session_signal_t; + session_signal_t mNewMsgSignal; + session_signal_t mNoUnreadMsgsSignal; - typedef boost::signals2::signal<void(const LLSD&)> session_signal_t; - session_signal_t mNewMsgSignal; - session_signal_t mNoUnreadMsgsSignal; - - /** - * Find an IM Session corresponding to session_id - * Returns NULL if the session does not exist - */ - LLIMSession* findIMSession(const LLUUID& session_id) const; + /** + * Find an IM Session corresponding to session_id + * Returns NULL if the session does not exist + */ + LLIMSession* findIMSession(const LLUUID& session_id) const; - /** - * Find an Ad-Hoc IM Session with specified participants - * @return first found Ad-Hoc session or NULL if the session does not exist - */ - LLIMSession* findAdHocIMSession(const uuid_vec_t& ids); + /** + * Find an Ad-Hoc IM Session with specified participants + * @return first found Ad-Hoc session or NULL if the session does not exist + */ + LLIMSession* findAdHocIMSession(const uuid_vec_t& ids); - /** - * Rebind session data to a new session id. - */ - void processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id); + /** + * Rebind session data to a new session id. + */ + void processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id); - boost::signals2::connection addNewMsgCallback(const session_signal_t::slot_type& cb ) { return mNewMsgSignal.connect(cb); } - boost::signals2::connection addNoUnreadMsgsCallback(const session_signal_t::slot_type& cb ) { return mNoUnreadMsgsSignal.connect(cb); } + boost::signals2::connection addNewMsgCallback(const session_signal_t::slot_type& cb ) { return mNewMsgSignal.connect(cb); } + boost::signals2::connection addNoUnreadMsgsCallback(const session_signal_t::slot_type& cb ) { return mNoUnreadMsgsSignal.connect(cb); } - /** - * Create new session object in a model - * @param name session name should not be empty, will return false if empty - */ - bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, - const uuid_vec_t& ids, bool voice = false, bool has_offline_msg = false); + /** + * Create new session object in a model + * @param name session name should not be empty, will return false if empty + */ + bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, + const uuid_vec_t& ids, bool voice = false, bool has_offline_msg = false); - bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, - const LLUUID& other_participant_id, bool voice = false, bool has_offline_msg = false); + bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, + const LLUUID& other_participant_id, bool voice = false, bool has_offline_msg = false); - /** - * Remove all session data associated with a session specified by session_id - */ - bool clearSession(const LLUUID& session_id); + /** + * Remove all session data associated with a session specified by session_id + */ + bool clearSession(const LLUUID& session_id); - /** - * Sends no unread messages signal. - */ - void sendNoUnreadMessages(const LLUUID& session_id); + /** + * Sends no unread messages signal. + */ + void sendNoUnreadMessages(const LLUUID& session_id); - /** - * Populate supplied std::list with messages starting from index specified by start_index - */ - void getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0, const bool sendNoUnreadMsgs = true); + /** + * Populate supplied std::list with messages starting from index specified by start_index + */ + void getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0, const bool sendNoUnreadMsgs = true); - /** - * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id - * and also saved into a file if log2file is specified. - * It sends new message signal for each added message. - */ - void addMessage(const LLUUID& session_id, + /** + * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id + * and also saved into a file if log2file is specified. + * It sends new message signal for each added message. + */ + void addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, @@ -240,400 +240,400 @@ public: bool is_region_msg, U32 time_stamp); - /** - * Similar to addMessage(...) above but won't send a signal about a new message added - */ - LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file = true, bool is_region_msg = false, U32 timestamp = 0); - - /** - * Add a system message to an IM Model - */ - void proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text); - - /** - * Get a session's name. - * For a P2P chat - it's an avatar's name, - * For a group chat - it's a group's name - * For an incoming ad-hoc chat - is received from the server and is in a from of "<Avatar's name> Conference" - * It is updated in LLIMModel::LLIMSession's constructor to localize the "Conference". - */ - const std::string getName(const LLUUID& session_id) const; - - /** - * Get number of unread messages in a session with session_id - * Returns -1 if the session with session_id doesn't exist - */ - const S32 getNumUnread(const LLUUID& session_id) const; - - /** - * Get uuid of other participant in a session with session_id - * Returns LLUUID::null if the session doesn't exist - * - * *TODO what to do with other participants in ad-hoc and group chats? - */ - const LLUUID& getOtherParticipantID(const LLUUID& session_id) const; - - /** - * Get type of a session specified by session_id - * Returns EInstantMessage::IM_COUNT if the session does not exist - */ - EInstantMessage getType(const LLUUID& session_id) const; - - /** - * Get voice channel for the session specified by session_id - * Returns NULL if the session does not exist - */ - LLVoiceChannel* getVoiceChannel(const LLUUID& session_id) const; - - /** - * Get im speaker manager for the session specified by session_id - * Returns NULL if the session does not exist - */ - LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; - - const std::string& getHistoryFileName(const LLUUID& session_id) const; - - static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id); - static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, - const uuid_vec_t& ids, EInstantMessage dialog); - static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); - static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, - const LLUUID& other_participant_id, EInstantMessage dialog); - - // Adds people from speakers list (people with whom you are currently speaking) to the Recent People List - static void addSpeakersToRecent(const LLUUID& im_session_id); - - void testMessages(); - - /** - * Saves an IM message into a file - */ - bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); + /** + * Similar to addMessage(...) above but won't send a signal about a new message added + */ + LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, + const std::string& utf8_text, bool log2file = true, bool is_region_msg = false, U32 timestamp = 0); + + /** + * Add a system message to an IM Model + */ + void proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text); + + /** + * Get a session's name. + * For a P2P chat - it's an avatar's name, + * For a group chat - it's a group's name + * For an incoming ad-hoc chat - is received from the server and is in a from of "<Avatar's name> Conference" + * It is updated in LLIMModel::LLIMSession's constructor to localize the "Conference". + */ + const std::string getName(const LLUUID& session_id) const; + + /** + * Get number of unread messages in a session with session_id + * Returns -1 if the session with session_id doesn't exist + */ + const S32 getNumUnread(const LLUUID& session_id) const; + + /** + * Get uuid of other participant in a session with session_id + * Returns LLUUID::null if the session doesn't exist + * + * *TODO what to do with other participants in ad-hoc and group chats? + */ + const LLUUID& getOtherParticipantID(const LLUUID& session_id) const; + + /** + * Get type of a session specified by session_id + * Returns EInstantMessage::IM_COUNT if the session does not exist + */ + EInstantMessage getType(const LLUUID& session_id) const; + + /** + * Get voice channel for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLVoiceChannel* getVoiceChannel(const LLUUID& session_id) const; + + /** + * Get im speaker manager for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; + + const std::string& getHistoryFileName(const LLUUID& session_id) const; + + static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id); + static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, + const uuid_vec_t& ids, EInstantMessage dialog); + static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); + static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, + const LLUUID& other_participant_id, EInstantMessage dialog); + + // Adds people from speakers list (people with whom you are currently speaking) to the Recent People List + static void addSpeakersToRecent(const LLUUID& im_session_id); + + void testMessages(); + + /** + * Saves an IM message into a file + */ + bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); private: - /** - * Populate supplied std::list with messages starting from index specified by start_index without - * emitting no unread messages signal. - */ - void getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0); + /** + * Populate supplied std::list with messages starting from index specified by start_index without + * emitting no unread messages signal. + */ + void getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0); - /** - * Add message to a list of message associated with session specified by session_id - */ - bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg, U32 timestamp); + /** + * Add message to a list of message associated with session specified by session_id + */ + bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg, U32 timestamp); }; class LLIMSessionObserver { public: - virtual ~LLIMSessionObserver() {} - virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg) = 0; + virtual ~LLIMSessionObserver() {} + virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg) = 0; virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0; - virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0; - virtual void sessionRemoved(const LLUUID& session_id) = 0; - virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0; + virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0; + virtual void sessionRemoved(const LLUUID& session_id) = 0; + virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0; }; class LLIMMgr : public LLSingleton<LLIMMgr> { - LLSINGLETON(LLIMMgr); - friend class LLIMModel; + LLSINGLETON(LLIMMgr); + friend class LLIMModel; public: - enum EInvitationType - { - INVITATION_TYPE_INSTANT_MESSAGE = 0, - INVITATION_TYPE_VOICE = 1, - INVITATION_TYPE_IMMEDIATE = 2 - }; - - - // Add a message to a session. The session can keyed to sesion id - // or agent id. - void addMessage(const LLUUID& session_id, - const LLUUID& target_id, - const std::string& from, - const std::string& msg, - bool is_offline_msg = false, - const std::string& session_name = LLStringUtil::null, - EInstantMessage dialog = IM_NOTHING_SPECIAL, - U32 parent_estate_id = 0, - const LLUUID& region_id = LLUUID::null, - const LLVector3& position = LLVector3::zero, + enum EInvitationType + { + INVITATION_TYPE_INSTANT_MESSAGE = 0, + INVITATION_TYPE_VOICE = 1, + INVITATION_TYPE_IMMEDIATE = 2 + }; + + + // Add a message to a session. The session can keyed to sesion id + // or agent id. + void addMessage(const LLUUID& session_id, + const LLUUID& target_id, + const std::string& from, + const std::string& msg, + bool is_offline_msg = false, + const std::string& session_name = LLStringUtil::null, + EInstantMessage dialog = IM_NOTHING_SPECIAL, + U32 parent_estate_id = 0, + const LLUUID& region_id = LLUUID::null, + const LLVector3& position = LLVector3::zero, bool is_region_msg = false, U32 timestamp = 0); - void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); - - // This adds a session to the talk view. The name is the local - // name of the session, dialog specifies the type of - // session. Since sessions can be keyed off of first recipient or - // initiator, the session can be matched against the id - // provided. If the session exists, it is brought forward. This - // method accepts a group id or an agent id. Specifying id = NULL - // results in an im session to everyone. Returns the uuid of the - // session. - LLUUID addSession(const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, bool voice = false); - - // Adds a session using a specific group of starting agents - // the dialog type is assumed correct. Returns the uuid of the session. - // A session can be added to a floater specified by floater_id. - LLUUID addSession(const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, - const std::vector<LLUUID>& ids, bool voice = false, - const LLUUID& floater_id = LLUUID::null); - - /** - * Creates a P2P session with the requisite handle for responding to voice calls. - * - * @param name session name, cannot be null - * @param caller_uri - sip URI of caller. It should be always be passed into the method to avoid - * incorrect working of LLVoiceChannel instances. See EXT-2985. - */ - LLUUID addP2PSession(const std::string& name, - const LLUUID& other_participant_id, - const std::string& voice_session_handle, - const std::string& caller_uri); - - /** - * Leave the session with session id. Send leave session notification - * to the server and removes all associated session data - * @return false if the session with specified id was not exist - */ - bool leaveSession(const LLUUID& session_id); - - void inviteToSession( - const LLUUID& session_id, - const std::string& session_name, - const LLUUID& caller, - const std::string& caller_name, - EInstantMessage type, - EInvitationType inv_type, - const std::string& session_handle = LLStringUtil::null, - const std::string& session_uri = LLStringUtil::null); - - void processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type); - void processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type); - - // automatically start a call once the session has initialized - void autoStartCallOnStartup(const LLUUID& session_id); - - // Calc number of all unread IMs - S32 getNumberOfUnreadIM(); - - /** - * Calculates number of unread IMs from real participants in all stored sessions - */ - S32 getNumberOfUnreadParticipantMessages(); - - // This method is used to go through all active sessions and - // disable all of them. This method is usally called when you are - // forced to log out or similar situations where you do not have a - // good connection. - void disconnectAllSessions(); - - BOOL hasSession(const LLUUID& session_id); - - static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id); - - void clearPendingInvitation(const LLUUID& session_id); - - void processAgentListUpdates(const LLUUID& session_id, const LLSD& body); - LLSD getPendingAgentListUpdates(const LLUUID& session_id); - void addPendingAgentListUpdates( - const LLUUID& sessioN_id, - const LLSD& updates); - void clearPendingAgentListUpdates(const LLUUID& session_id); - - void addSessionObserver(LLIMSessionObserver *); - void removeSessionObserver(LLIMSessionObserver *); - - //show error statuses to the user - void showSessionStartError(const std::string& error_string, const LLUUID session_id); - void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id); - void showSessionForceClose(const std::string& reason, const LLUUID session_id); - static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); - - /** - * Start call in a session - * @return false if voice channel doesn't exist - **/ - bool startCall(const LLUUID& session_id, LLVoiceChannel::EDirection direction = LLVoiceChannel::OUTGOING_CALL); - - /** - * End call in a session - * @return false if voice channel doesn't exist - **/ - bool endCall(const LLUUID& session_id); - - bool isVoiceCall(const LLUUID& session_id); - - void updateDNDMessageStatus(); - - bool isDNDMessageSend(const LLUUID& session_id); - - void setDNDMessageSent(const LLUUID& session_id, bool is_send); - - void addNotifiedNonFriendSessionID(const LLUUID& session_id); - - bool isNonFriendSessionNotified(const LLUUID& session_id); + void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); + + // This adds a session to the talk view. The name is the local + // name of the session, dialog specifies the type of + // session. Since sessions can be keyed off of first recipient or + // initiator, the session can be matched against the id + // provided. If the session exists, it is brought forward. This + // method accepts a group id or an agent id. Specifying id = NULL + // results in an im session to everyone. Returns the uuid of the + // session. + LLUUID addSession(const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, bool voice = false); + + // Adds a session using a specific group of starting agents + // the dialog type is assumed correct. Returns the uuid of the session. + // A session can be added to a floater specified by floater_id. + LLUUID addSession(const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, + const std::vector<LLUUID>& ids, bool voice = false, + const LLUUID& floater_id = LLUUID::null); + + /** + * Creates a P2P session with the requisite handle for responding to voice calls. + * + * @param name session name, cannot be null + * @param caller_uri - sip URI of caller. It should be always be passed into the method to avoid + * incorrect working of LLVoiceChannel instances. See EXT-2985. + */ + LLUUID addP2PSession(const std::string& name, + const LLUUID& other_participant_id, + const std::string& voice_session_handle, + const std::string& caller_uri); + + /** + * Leave the session with session id. Send leave session notification + * to the server and removes all associated session data + * @return false if the session with specified id was not exist + */ + bool leaveSession(const LLUUID& session_id); + + void inviteToSession( + const LLUUID& session_id, + const std::string& session_name, + const LLUUID& caller, + const std::string& caller_name, + EInstantMessage type, + EInvitationType inv_type, + const std::string& session_handle = LLStringUtil::null, + const std::string& session_uri = LLStringUtil::null); + + void processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type); + void processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type); + + // automatically start a call once the session has initialized + void autoStartCallOnStartup(const LLUUID& session_id); + + // Calc number of all unread IMs + S32 getNumberOfUnreadIM(); + + /** + * Calculates number of unread IMs from real participants in all stored sessions + */ + S32 getNumberOfUnreadParticipantMessages(); + + // This method is used to go through all active sessions and + // disable all of them. This method is usally called when you are + // forced to log out or similar situations where you do not have a + // good connection. + void disconnectAllSessions(); + + BOOL hasSession(const LLUUID& session_id); + + static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id); + + void clearPendingInvitation(const LLUUID& session_id); + + void processAgentListUpdates(const LLUUID& session_id, const LLSD& body); + LLSD getPendingAgentListUpdates(const LLUUID& session_id); + void addPendingAgentListUpdates( + const LLUUID& sessioN_id, + const LLSD& updates); + void clearPendingAgentListUpdates(const LLUUID& session_id); + + void addSessionObserver(LLIMSessionObserver *); + void removeSessionObserver(LLIMSessionObserver *); + + //show error statuses to the user + void showSessionStartError(const std::string& error_string, const LLUUID session_id); + void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id); + void showSessionForceClose(const std::string& reason, const LLUUID session_id); + static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); + + /** + * Start call in a session + * @return false if voice channel doesn't exist + **/ + bool startCall(const LLUUID& session_id, LLVoiceChannel::EDirection direction = LLVoiceChannel::OUTGOING_CALL); + + /** + * End call in a session + * @return false if voice channel doesn't exist + **/ + bool endCall(const LLUUID& session_id); + + bool isVoiceCall(const LLUUID& session_id); + + void updateDNDMessageStatus(); + + bool isDNDMessageSend(const LLUUID& session_id); + + void setDNDMessageSent(const LLUUID& session_id, bool is_send); + + void addNotifiedNonFriendSessionID(const LLUUID& session_id); + + bool isNonFriendSessionNotified(const LLUUID& session_id); private: - /** - * Remove data associated with a particular session specified by session_id - */ - void removeSession(const LLUUID& session_id); + /** + * Remove data associated with a particular session specified by session_id + */ + void removeSession(const LLUUID& session_id); - // This simple method just iterates through all of the ids, and - // prints a simple message if they are not online. Used to help - // reduce 'hello' messages to the linden employees unlucky enough - // to have their calling card in the default inventory. - void noteOfflineUsers(const LLUUID& session_id, const std::vector<LLUUID>& ids); - void noteMutedUsers(const LLUUID& session_id, const std::vector<LLUUID>& ids); + // This simple method just iterates through all of the ids, and + // prints a simple message if they are not online. Used to help + // reduce 'hello' messages to the linden employees unlucky enough + // to have their calling card in the default inventory. + void noteOfflineUsers(const LLUUID& session_id, const std::vector<LLUUID>& ids); + void noteMutedUsers(const LLUUID& session_id, const std::vector<LLUUID>& ids); - void processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing); + void processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing); - static void onInviteNameLookup(LLSD payload, const LLUUID& id, const LLAvatarName& name); + static void onInviteNameLookup(LLSD payload, const LLUUID& id, const LLAvatarName& name); - void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg); + void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg); //Triggers when a session has already been added void notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); - void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id); - void notifyObserverSessionRemoved(const LLUUID& session_id); - void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); + void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id); + void notifyObserverSessionRemoved(const LLUUID& session_id); + void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); private: - - typedef std::list <LLIMSessionObserver *> session_observers_list_t; - session_observers_list_t mSessionObservers; - - // EXP-901 - // If "Only friends and groups can IM me" option is ON but the user got message from non-friend, - // the user should be notified that to be able to see this message the option should be OFF. - // This set stores session IDs in which user was notified. Need to store this IDs so that the user - // be notified only one time per session with non-friend. - typedef std::set<LLUUID> notified_non_friend_sessions_t; - notified_non_friend_sessions_t mNotifiedNonFriendSessions; - - LLSD mPendingInvitations; - LLSD mPendingAgentListUpdates; + + typedef std::list <LLIMSessionObserver *> session_observers_list_t; + session_observers_list_t mSessionObservers; + + // EXP-901 + // If "Only friends and groups can IM me" option is ON but the user got message from non-friend, + // the user should be notified that to be able to see this message the option should be OFF. + // This set stores session IDs in which user was notified. Need to store this IDs so that the user + // be notified only one time per session with non-friend. + typedef std::set<LLUUID> notified_non_friend_sessions_t; + notified_non_friend_sessions_t mNotifiedNonFriendSessions; + + LLSD mPendingInvitations; + LLSD mPendingAgentListUpdates; }; class LLCallDialogManager : public LLSingleton<LLCallDialogManager> { - LLSINGLETON(LLCallDialogManager); - ~LLCallDialogManager(); + LLSINGLETON(LLCallDialogManager); + ~LLCallDialogManager(); public: - // static for convinience - static void onVoiceChannelChanged(const LLUUID &session_id); - static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); + // static for convinience + static void onVoiceChannelChanged(const LLUUID &session_id); + static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); private: - void initSingleton() override; - void onVoiceChannelChangedInt(const LLUUID &session_id); - void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); + void initSingleton() override; + void onVoiceChannelChangedInt(const LLUUID &session_id); + void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); protected: - std::string mPreviousSessionlName; - std::string mCurrentSessionlName; - LLIMModel::LLIMSession* mSession; - LLVoiceChannel::EState mOldState; + std::string mPreviousSessionlName; + std::string mCurrentSessionlName; + LLIMModel::LLIMSession* mSession; + LLVoiceChannel::EState mOldState; }; class LLCallDialog : public LLDockableFloater { public: - LLCallDialog(const LLSD& payload); - virtual ~LLCallDialog(); + LLCallDialog(const LLSD& payload); + virtual ~LLCallDialog(); + + virtual BOOL postBuild(); + + void dockToToolbarButton(const std::string& toolbarButtonName); - virtual BOOL postBuild(); + // check timer state + /*virtual*/ void draw(); + /*virtual*/ void onOpen(const LLSD& key); - void dockToToolbarButton(const std::string& toolbarButtonName); - - // check timer state - /*virtual*/ void draw(); - /*virtual*/ void onOpen(const LLSD& key); - protected: - // lifetime timer for a notification - LLTimer mLifetimeTimer; - // notification's lifetime in seconds - S32 mLifetime; - static const S32 DEFAULT_LIFETIME = 5; - virtual bool lifetimeHasExpired(); - virtual void onLifetimeExpired(); - - /** - * Sets icon depend on session. - * - * If passed session_id is a group id group icon will be shown, otherwise avatar icon for participant_id - * - * @param session_id - UUID of session - * @param participant_id - UUID of other participant - */ - void setIcon(const LLSD& session_id, const LLSD& participant_id); - - LLSD mPayload; + // lifetime timer for a notification + LLTimer mLifetimeTimer; + // notification's lifetime in seconds + S32 mLifetime; + static const S32 DEFAULT_LIFETIME = 5; + virtual bool lifetimeHasExpired(); + virtual void onLifetimeExpired(); + + /** + * Sets icon depend on session. + * + * If passed session_id is a group id group icon will be shown, otherwise avatar icon for participant_id + * + * @param session_id - UUID of session + * @param participant_id - UUID of other participant + */ + void setIcon(const LLSD& session_id, const LLSD& participant_id); + + LLSD mPayload; private: - LLDockControl::DocAt getDockControlPos(const std::string& toolbarButtonName); + LLDockControl::DocAt getDockControlPos(const std::string& toolbarButtonName); }; class LLIncomingCallDialog : public LLCallDialog { public: - LLIncomingCallDialog(const LLSD& payload); - ~LLIncomingCallDialog() - { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - } - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - - static void onAccept(void* user_data); - static void onReject(void* user_data); - static void onStartIM(void* user_data); - - static void processCallResponse(S32 response, const LLSD& payload); + LLIncomingCallDialog(const LLSD& payload); + ~LLIncomingCallDialog() + { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + } + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + + static void onAccept(void* user_data); + static void onReject(void* user_data); + static void onStartIM(void* user_data); + + static void processCallResponse(S32 response, const LLSD& payload); private: - void setCallerName(const std::string& ui_title, - const std::string& ui_label, - const std::string& call_type); - void onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name, - const std::string& call_type); + void setCallerName(const std::string& ui_title, + const std::string& ui_label, + const std::string& call_type); + void onAvatarNameCache(const LLUUID& agent_id, + const LLAvatarName& av_name, + const std::string& call_type); - boost::signals2::connection mAvatarNameCacheConnection; + boost::signals2::connection mAvatarNameCacheConnection; - /*virtual*/ void onLifetimeExpired(); + /*virtual*/ void onLifetimeExpired(); }; class LLOutgoingCallDialog : public LLCallDialog { public: - LLOutgoingCallDialog(const LLSD& payload); + LLOutgoingCallDialog(const LLSD& payload); - /*virtual*/ BOOL postBuild(); - void show(const LLSD& key); + /*virtual*/ BOOL postBuild(); + void show(const LLSD& key); - static void onCancel(void* user_data); - static const LLUUID OCD_KEY; + static void onCancel(void* user_data); + static const LLUUID OCD_KEY; private: - // hide all text boxes - void hideAllText(); + // hide all text boxes + void hideAllText(); }; // Globals diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 7d1252ee31..f0dcdf01c1 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llinventoryfunctions.cpp * @brief Implementation of the inventory view and associated stuff. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -152,19 +152,19 @@ S32 count_stock_folders(LLInventoryModel::cat_array_t& categories) // Helper funtion : Count the number of items (not folders) in the descending hierarchy S32 count_descendants_items(const LLUUID& cat_id) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + S32 count = item_array->size(); - + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { - LLViewerInventoryCategory* category = *iter; + LLViewerInventoryCategory* category = *iter; count += count_descendants_items(category->getUUID()); } - + return count; } @@ -179,7 +179,7 @@ bool contains_nocopy_items(const LLUUID& id) LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(id,cat_array,item_array); - + // Check all the items: returns true upon encountering a nocopy item for (LLInventoryModel::item_array_t::iterator iter = item_array->begin(); iter != item_array->end(); iter++) { @@ -190,7 +190,7 @@ bool contains_nocopy_items(const LLUUID& id) return true; } } - + // Check all the sub folders recursively for (LLInventoryModel::cat_array_t::iterator iter = cat_array->begin(); iter != cat_array->end(); iter++) { @@ -203,14 +203,14 @@ bool contains_nocopy_items(const LLUUID& id) } else { - LLInventoryItem* item = gInventory.getItem(id); + LLInventoryItem* item = gInventory.getItem(id); LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item; if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { return true; } } - + // Exit without meeting a nocopy item return false; } @@ -218,21 +218,21 @@ bool contains_nocopy_items(const LLUUID& id) // Generates a string containing the path to the item specified by id. void append_path(const LLUUID& id, std::string& path) { - std::string temp; - const LLInventoryObject* obj = gInventory.getObject(id); - LLUUID parent_id; - if(obj) parent_id = obj->getParentUUID(); - std::string forward_slash("/"); - while(obj) - { - obj = gInventory.getCategory(parent_id); - if(obj) - { - temp.assign(forward_slash + obj->getName() + temp); - parent_id = obj->getParentUUID(); - } - } - path.append(temp); + std::string temp; + const LLInventoryObject* obj = gInventory.getObject(id); + LLUUID parent_id; + if(obj) parent_id = obj->getParentUUID(); + std::string forward_slash("/"); + while(obj) + { + obj = gInventory.getCategory(parent_id); + if(obj) + { + temp.assign(forward_slash + obj->getName() + temp); + parent_id = obj->getParentUUID(); + } + } + path.append(temp); } // Generates a string containing the path name of the object. @@ -273,10 +273,10 @@ void update_marketplace_folder_hierarchy(const LLUUID cat_id) gInventory.addChangedMask(LLInventoryObserver::LABEL, cat_id); // Update all descendent folders down - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { @@ -291,9 +291,9 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc // When changing the marketplace status of an item, we usually have to change the status of all // folders in the same listing. This is because the display of each folder is affected by the // overall status of the whole listing. - // Consequently, the only way to correctly update an item anywhere in the marketplace is to + // Consequently, the only way to correctly update an item anywhere in the marketplace is to // update the whole listing from its listing root. - // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth + // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth // is limited to 4. // We also take care of degenerated cases so we don't update all folders in the inventory by mistake. @@ -303,7 +303,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc { return; } - + // Grab marketplace listing data for this item S32 depth = depth_nesting_in_marketplace(cur_uuid); if (depth > 0) @@ -312,7 +312,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc LLUUID listing_uuid = nested_parent_id(cur_uuid, depth); LLViewerInventoryCategory* listing_cat = gInventory.getCategory(listing_uuid); bool listing_cat_loaded = listing_cat != NULL && listing_cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; - + // Verify marketplace data consistency for this listing if (perform_consistency_enforcement && listing_cat_loaded @@ -336,7 +336,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc LLMarketplaceData::instance().activateListing(listing_uuid, false,1); } } - + // Check if the count on hand needs to be updated on SLM if (perform_consistency_enforcement && listing_cat_loaded @@ -377,10 +377,10 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc void update_all_marketplace_count(const LLUUID& cat_id) { // Get all descendent folders down - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { @@ -412,19 +412,19 @@ void update_all_marketplace_count() void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) { - LLViewerInventoryCategory* cat; + LLViewerInventoryCategory* cat; - if (!model || - !get_is_category_renameable(model, cat_id) || - (cat = model->getCategory(cat_id)) == NULL || - cat->getName() == new_name) - { - return; - } + if (!model || + !get_is_category_renameable(model, cat_id) || + (cat = model->getCategory(cat_id)) == NULL || + cat->getName() == new_name) + { + return; + } - LLSD updates; - updates["name"] = new_name; - update_inventory_category(cat_id, updates, NULL); + LLSD updates; + updates["name"] = new_name; + update_inventory_category(cat_id, updates, NULL); } void copy_inventory_category(LLInventoryModel* model, @@ -448,7 +448,7 @@ void copy_inventory_category(LLInventoryModel* model, bool move_no_copy_items, inventory_func_type callback) { - // Create the initial folder + // Create the initial folder inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID &new_id) { copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items); @@ -457,7 +457,7 @@ void copy_inventory_category(LLInventoryModel* model, callback(new_id); } }; - gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); + gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); } void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) @@ -469,21 +469,21 @@ void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items) { - model->notifyObservers(); + model->notifyObservers(); - // We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... - LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); + // We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... + LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); - // Get the content of the folder - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(), cat_array, item_array); + // Get the content of the folder + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(), cat_array, item_array); - // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder - if (root_copy_id.isNull()) - { - LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); - } + // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder + if (root_copy_id.isNull()) + { + LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); + } LLPointer<LLInventoryCallback> cb; if (root_copy_id.isNull()) @@ -495,348 +495,348 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); } - // Copy all the items - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; - - if (item->getIsLinkType()) - { - link_inventory_object(new_cat_uuid, item->getLinkedUUID(), cb); - } - else if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) - { - // If the item is nocopy, we do nothing or, optionally, move it - if (move_no_copy_items) - { - // Reparent the item - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; - gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); - } + // Copy all the items + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; + + if (item->getIsLinkType()) + { + link_inventory_object(new_cat_uuid, item->getLinkedUUID(), cb); + } + else if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // If the item is nocopy, we do nothing or, optionally, move it + if (move_no_copy_items) + { + // Reparent the item + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; + gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); + } if (root_copy_id.isNull()) { // Decrement the count in root_id since that one item won't be copied over LLMarketplaceData::instance().decrementValidationWaiting(root_id); } - } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - new_cat_uuid, - std::string(), - cb); - } - } - - // Copy all the folders - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLViewerInventoryCategory* category = *iter; - if (category->getUUID() != root_id) - { - copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); - } - } + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + new_cat_uuid, + std::string(), + cb); + } + } + + // Copy all the folders + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLViewerInventoryCategory* category = *iter; + if (category->getUUID() != root_id) + { + copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); + } + } } class LLInventoryCollectAllItems : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + return true; + } }; BOOL get_is_parent_to_worn_item(const LLUUID& id) { - const LLViewerInventoryCategory* cat = gInventory.getCategory(id); - if (!cat) - { - return FALSE; - } + const LLViewerInventoryCategory* cat = gInventory.getCategory(id); + if (!cat) + { + return FALSE; + } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryCollectAllItems collect_all; - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryCollectAllItems collect_all; + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); - for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) - { - const LLViewerInventoryItem * const item = *it; + for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) + { + const LLViewerInventoryItem * const item = *it; - llassert(item->getIsLinkType()); + llassert(item->getIsLinkType()); - LLUUID linked_id = item->getLinkedUUID(); - const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id); + LLUUID linked_id = item->getLinkedUUID(); + const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id); - if (linked_item) - { - LLUUID parent_id = linked_item->getParentUUID(); + if (linked_item) + { + LLUUID parent_id = linked_item->getParentUUID(); - while (!parent_id.isNull()) - { - LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id); + while (!parent_id.isNull()) + { + LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id); - if (cat == parent_cat) - { - return TRUE; - } + if (cat == parent_cat) + { + return TRUE; + } - parent_id = parent_cat->getParentUUID(); - } - } - } + parent_id = parent_cat->getParentUUID(); + } + } + } - return FALSE; + return FALSE; } BOOL get_is_item_worn(const LLUUID& id) { - const LLViewerInventoryItem* item = gInventory.getItem(id); - if (!item) - return FALSE; + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + return FALSE; if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID())) { return FALSE; } - // Consider the item as worn if it has links in COF. - if (LLAppearanceMgr::instance().isLinkedInCOF(id)) - { - return TRUE; - } - - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - { - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) - return TRUE; - break; - } - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(gAgentWearables.isWearingItem(item->getLinkedUUID())) - return TRUE; - break; - case LLAssetType::AT_GESTURE: - if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID())) - return TRUE; - break; - default: - break; - } - return FALSE; + // Consider the item as worn if it has links in COF. + if (LLAppearanceMgr::instance().isLinkedInCOF(id)) + { + return TRUE; + } + + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + { + if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) + return TRUE; + break; + } + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if(gAgentWearables.isWearingItem(item->getLinkedUUID())) + return TRUE; + break; + case LLAssetType::AT_GESTURE: + if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID())) + return TRUE; + break; + default: + break; + } + return FALSE; } BOOL get_can_item_be_worn(const LLUUID& id) { - const LLViewerInventoryItem* item = gInventory.getItem(id); - if (!item) - return FALSE; - - if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) - { - // an item having links in COF (i.e. a worn item) - return FALSE; - } - - if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) - { - // a non-link object in COF (should not normally happen) - return FALSE; - } - - const LLUUID trash_id = gInventory.findCategoryUUIDForType( - LLFolderType::FT_TRASH); - - // item can't be worn if base obj in trash, see EXT-7015 - if (gInventory.isObjectDescendentOf(item->getLinkedUUID(), - trash_id)) - { - return false; - } - - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - { - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) - { - // Already being worn - return FALSE; - } - else - { - // Not being worn yet. - return TRUE; - } - break; - } - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(gAgentWearables.isWearingItem(item->getLinkedUUID())) - { - // Already being worn - return FALSE; - } - else - { - // Not being worn yet. - return TRUE; - } - break; - default: - break; - } - return FALSE; + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + return FALSE; + + if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) + { + // an item having links in COF (i.e. a worn item) + return FALSE; + } + + if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) + { + // a non-link object in COF (should not normally happen) + return FALSE; + } + + const LLUUID trash_id = gInventory.findCategoryUUIDForType( + LLFolderType::FT_TRASH); + + // item can't be worn if base obj in trash, see EXT-7015 + if (gInventory.isObjectDescendentOf(item->getLinkedUUID(), + trash_id)) + { + return false; + } + + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + { + if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) + { + // Already being worn + return FALSE; + } + else + { + // Not being worn yet. + return TRUE; + } + break; + } + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if(gAgentWearables.isWearingItem(item->getLinkedUUID())) + { + // Already being worn + return FALSE; + } + else + { + // Not being worn yet. + return TRUE; + } + break; + default: + break; + } + return FALSE; } BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) { - if (!model) - { - return FALSE; - } - - // Can't delete an item that's in the library. - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } - - // Disable delete from COF folder; have users explicitly choose "detach/take off", - // unless the item is not worn but in the COF (i.e. is bugged). - if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) - { - if (get_is_item_worn(id)) - { - return FALSE; - } - } - - const LLInventoryObject *obj = model->getItem(id); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - if (get_is_item_worn(id)) - { - return FALSE; - } - return TRUE; + if (!model) + { + return FALSE; + } + + // Can't delete an item that's in the library. + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } + + // Disable delete from COF folder; have users explicitly choose "detach/take off", + // unless the item is not worn but in the COF (i.e. is bugged). + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) + { + if (get_is_item_worn(id)) + { + return FALSE; + } + } + + const LLInventoryObject *obj = model->getItem(id); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } + if (get_is_item_worn(id)) + { + return FALSE; + } + return TRUE; } bool get_is_item_editable(const LLUUID& inv_item_id) { - if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) - { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - return gAgentWearables.isWearableModifiable(inv_item_id); - case LLAssetType::AT_OBJECT: - return true; - default: + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gAgentWearables.isWearableModifiable(inv_item_id); + case LLAssetType::AT_OBJECT: + return true; + default: return false;; - } - } - return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; + } + } + return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; } void handle_item_edit(const LLUUID& inv_item_id) { - if (get_is_item_editable(inv_item_id)) - { - if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) - { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - LLAgentWearables::editWearable(inv_item_id); - break; - case LLAssetType::AT_OBJECT: - handle_attachment_edit(inv_item_id); - break; - default: - break; - } - } - else - { - handle_attachment_edit(inv_item_id); - } - } + if (get_is_item_editable(inv_item_id)) + { + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + LLAgentWearables::editWearable(inv_item_id); + break; + case LLAssetType::AT_OBJECT: + handle_attachment_edit(inv_item_id); + break; + default: + break; + } + } + else + { + handle_attachment_edit(inv_item_id); + } + } } BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) { - // NOTE: This function doesn't check the folder's children. - // See LLFolderBridge::isItemRemovable for a function that does - // consider the children. + // NOTE: This function doesn't check the folder's children. + // See LLFolderBridge::isItemRemovable for a function that does + // consider the children. - if (!model) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } - if (!isAgentAvatarValid()) return FALSE; + if (!isAgentAvatarValid()) return FALSE; - const LLInventoryCategory* category = model->getCategory(id); - if (!category) - { - return FALSE; - } + const LLInventoryCategory* category = model->getCategory(id); + if (!category) + { + return FALSE; + } - const LLFolderType::EType folder_type = category->getPreferredType(); - - if (LLFolderType::lookupIsProtectedType(folder_type)) - { - return FALSE; - } + const LLFolderType::EType folder_type = category->getPreferredType(); - // Can't delete the outfit that is currently being worn. - if (folder_type == LLFolderType::FT_OUTFIT) - { - const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); - if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) - { - return FALSE; - } - } + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + return FALSE; + } - return TRUE; + // Can't delete the outfit that is currently being worn. + if (folder_type == LLFolderType::FT_OUTFIT) + { + const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) + { + return FALSE; + } + } + + return TRUE; } BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) { - if (!model) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - LLViewerInventoryCategory* cat = model->getCategory(id); + LLViewerInventoryCategory* cat = model->getCategory(id); - if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && - cat->getOwnerID() == gAgent.getID()) - { - return TRUE; - } - return FALSE; + if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && + cat->getOwnerID() == gAgent.getID()) + { + return TRUE; + } + return FALSE; } void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id) @@ -844,13 +844,13 @@ void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id) LLSD params; params["id"] = item_uuid; params["object"] = object_id; - + LLFloaterReg::showInstance("item_properties", params); } void show_item_profile(const LLUUID& item_uuid) { - LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); + LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); LLFloaterReg::showInstance("item_properties", LLSD().with("id", linked_uuid)); } @@ -877,7 +877,7 @@ void show_item_original(const LLUUID& item_uuid) LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); @@ -920,20 +920,20 @@ void show_item_original(const LLUUID& item_uuid) void reset_inventory_filter() { - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - if (sidepanel_inventory) - { - LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); - if (main_inventory) - { - main_inventory->onFilterEdit(""); - } - } + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory) + { + LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); + if (main_inventory) + { + main_inventory->onFilterEdit(""); + } + } } void open_marketplace_listings() { - LLFloaterReg::showInstance("marketplace_listings"); + LLFloaterReg::showInstance("marketplace_listings"); } ///---------------------------------------------------------------------------- @@ -960,7 +960,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid) { return -1; } - + // Iterate through the parents till we hit the marketplace listings root // Note that the marketplace listings root itself will return 0 S32 depth = 0; @@ -1062,13 +1062,13 @@ S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) } } } - + // In all other cases, the stock count is the min of stock folders count found in the descendents // "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder in the hierarchy has a count that cannot be evaluated at this time (folder not up to date) - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); + // "COMPUTE_STOCK_INFINITE" denotes a folder that doesn't countain any stock folders in its descendents S32 curr_count = COMPUTE_STOCK_INFINITE; @@ -1083,147 +1083,147 @@ S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) curr_count = count; } } - + return curr_count; } // local helper bool can_move_to_marketplace(LLInventoryItem* inv_item, std::string& tooltip_msg, bool resolve_links) { - // Collapse links directly to items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); // Linked items and folders cannot be put for sale if (linked_category || linked_item) { - tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); + tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); return false; } - + // A category is always considered as passing... if (linked_category != NULL) - { + { return true; - } - + } + // Take the linked item if necessary if (linked_item != NULL) - { - inv_item = linked_item; - } - + { + inv_item = linked_item; + } + // Check that the agent has transfer permission on the item: this is required as a resident cannot // put on sale items she cannot transfer. Proceed with move if we have permission. - bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); - if (!allow_transfer) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); - return false; - } - + bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + if (!allow_transfer) + { + tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); + return false; + } + // Check worn/not worn status: worn items cannot be put on the marketplace - bool worn = get_is_item_worn(inv_item->getUUID()); - if (worn) - { - tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); - return false; - } + bool worn = get_is_item_worn(inv_item->getUUID()); + if (worn) + { + tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); + return false; + } // Check library status: library items cannot be put on the marketplace - if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) + if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - return false; + tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + return false; } // Check type: for the moment, calling cards cannot be put on the marketplace - bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); - if (calling_card) - { - tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); - return false; - } - - return true; + bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); + if (calling_card) + { + tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); + return false; + } + + return true; } // local helper // Returns the max tree length (in folder nodes) down from the argument folder int get_folder_levels(LLInventoryCategory* inv_cat) { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - - int max_child_levels = 0; - - for (S32 i=0; i < cats->size(); ++i) - { - LLInventoryCategory* category = cats->at(i); - max_child_levels = llmax(max_child_levels, get_folder_levels(category)); - } - - return 1 + max_child_levels; + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + int max_child_levels = 0; + + for (S32 i=0; i < cats->size(); ++i) + { + LLInventoryCategory* category = cats->at(i); + max_child_levels = llmax(max_child_levels, get_folder_levels(category)); + } + + return 1 + max_child_levels; } // local helper // Returns the distance (in folder nodes) between the ancestor and its descendant. Returns -1 if not related. int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) { - int depth = 0; - - if (ancestor_id == descendant_id) return depth; - - const LLInventoryCategory* category = gInventory.getCategory(descendant_id); - - while (category) - { - LLUUID parent_id = category->getParentUUID(); - - if (parent_id.isNull()) break; - - depth++; - - if (parent_id == ancestor_id) return depth; - - category = gInventory.getCategory(parent_id); - } - - LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; - return -1; + int depth = 0; + + if (ancestor_id == descendant_id) return depth; + + const LLInventoryCategory* category = gInventory.getCategory(descendant_id); + + while (category) + { + LLUUID parent_id = category->getParentUUID(); + + if (parent_id.isNull()) break; + + depth++; + + if (parent_id == ancestor_id) return depth; + + category = gInventory.getCategory(parent_id); + } + + LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; + return -1; } // local helper // Returns true if all items within the argument folder are fit for sale, false otherwise bool has_correct_permissions_for_sale(LLInventoryCategory* cat, std::string& error_msg) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - - LLInventoryModel::item_array_t item_array_copy = *item_array; - - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + + LLInventoryModel::item_array_t item_array_copy = *item_array; + + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; if (!can_move_to_marketplace(item, error_msg, false)) { return false; } - } - - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLInventoryCategory* category = *iter; - if (!has_correct_permissions_for_sale(category, error_msg)) + } + + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + if (!has_correct_permissions_for_sale(category, error_msg)) { return false; } - } + } return true; } @@ -1246,18 +1246,18 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve { accept = can_move_to_marketplace(inv_item, tooltip_msg, true); } - + // Check that the total amount of items won't violate the max limit on the marketplace if (accept) { // If the dest folder is a stock folder, we do not count the incoming items toward the total (stock items are seen as one) int existing_item_count = (move_in_stock ? 0 : bundle_size); - + // If the dest folder is a stock folder, we do assume that the incoming items are also stock items (they should anyway) int existing_stock_count = (move_in_stock ? bundle_size : 0); - + int existing_folder_count = 0; - + // Get the version folder: that's where the counts start from const LLViewerInventoryCategory * version_folder = ((root_folder && (root_folder != dest_folder)) ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); @@ -1271,13 +1271,13 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve LLInventoryModel::cat_array_t existing_categories; LLInventoryModel::item_array_t existing_items; - + gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - + existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_stock_count += count_stock_items(existing_items); existing_folder_count += existing_categories.size(); - + // If the incoming item is a nocopy (stock) item, we need to consider that it will create a stock folder if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && !move_in_stock) { @@ -1285,7 +1285,7 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve existing_folder_count += 1; } } - + if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) { LLStringUtil::format_map_t args; @@ -1321,7 +1321,7 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size, bool check_items, bool from_paste) { bool accept = true; - + // Compute the nested folders level we'll add into with that incoming folder int incoming_folder_depth = get_folder_levels(inv_cat); // Compute the nested folders level we're inserting ourselves in @@ -1330,7 +1330,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn // Get the version folder: that's where the folders and items counts start from const LLViewerInventoryCategory * version_folder = (insertion_point_folder_depth >= 2 ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); - + // Compare the whole with the nested folders depth limit // Note: substract 2 as we leave root and version folder out of the count threshold if ((incoming_folder_depth + insertion_point_folder_depth - 2) > (S32)(gSavedSettings.getU32("InventoryOutboxMaxFolderDepth"))) @@ -1341,20 +1341,20 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels", args); accept = false; } - + if (accept) { LLInventoryModel::cat_array_t descendent_categories; LLInventoryModel::item_array_t descendent_items; gInventory.collectDescendents(inv_cat->getUUID(), descendent_categories, descendent_items, FALSE); - + int dragged_folder_count = descendent_categories.size() + bundle_size; // Note: We assume that we're moving a bunch of folders in. That might be wrong... int dragged_item_count = count_copyable_items(descendent_items) + count_stock_folders(descendent_categories); int dragged_stock_count = count_stock_items(descendent_items); int existing_item_count = 0; int existing_stock_count = 0; int existing_folder_count = 0; - + if (version_folder) { if (!from_paste && gInventory.isObjectDescendentOf(inv_cat->getUUID(), version_folder->getUUID())) @@ -1364,21 +1364,21 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn dragged_item_count = 0; dragged_stock_count = 0; } - + // Tally the total number of categories and items inside the root folder LLInventoryModel::cat_array_t existing_categories; LLInventoryModel::item_array_t existing_items; gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - + existing_folder_count += existing_categories.size(); existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_stock_count += count_stock_items(existing_items); } - + const int total_folder_count = existing_folder_count + dragged_folder_count; const int total_item_count = existing_item_count + dragged_item_count; const int total_stock_count = existing_stock_count + dragged_stock_count; - + if (total_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) { LLStringUtil::format_map_t args; @@ -1403,7 +1403,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args); accept = false; } - + // Now check that each item in the folder can be moved in the marketplace if (accept && check_items) { @@ -1418,7 +1418,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn } } } - + return accept; } @@ -1429,33 +1429,33 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol S32 depth = depth_nesting_in_marketplace(dest_folder); if (depth < 0) { - LLSD subs; - subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); - LLNotificationsUtil::add("MerchantPasteFailed", subs); + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } // We will collapse links into items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); - - if (linked_category != NULL) - { + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); + + if (linked_category != NULL) + { // Move the linked folder directly - return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); - } - else - { + return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); + } + else + { // Grab the linked item if any - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); viewer_inv_item = (linked_item != NULL ? linked_item : viewer_inv_item); - + // If we want to copy but the item is no copy, fail silently (this is a common case that doesn't warrant notification) if (copy && !viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { return false; } - + // Check that the agent has transfer permission on the item: this is required as a resident cannot // put on sale items she cannot transfer. Proceed with move if we have permission. std::string error_msg; @@ -1585,7 +1585,7 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol return false; } } - + open_marketplace_listings(); return true; } @@ -1607,7 +1607,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } - + // Get the parent folder of the moved item : we may have to update it LLUUID src_folder = inv_cat->getParentUUID(); @@ -1638,14 +1638,14 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } - + open_marketplace_listings(); return true; } bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCategory* cat2) { - return cat1->getName().compare(cat2->getName()) < 0; + return cat1->getName().compare(cat2->getName()) < 0; } // Make all relevant business logic checks on the marketplace listings starting with the folder as argument. @@ -1667,7 +1667,7 @@ void validate_marketplacelistings( { // Get the type and the depth of the folder LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat); - const LLFolderType::EType folder_type = cat->getPreferredType(); + const LLFolderType::EType folder_type = cat->getPreferredType(); if (depth < 0) { // If the depth argument was not provided, evaluate the depth directly @@ -1680,7 +1680,7 @@ void validate_marketplacelistings( depth = 1; fix_hierarchy = false; } - + // Set the indentation for print output (typically, audit button in marketplace folder floater) std::string indent; for (int i = 1; i < depth; i++) @@ -1703,7 +1703,7 @@ void validate_marketplacelistings( } } } - + // Check out that stock folders are at the right level if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth <= 2)) { @@ -1752,28 +1752,28 @@ void validate_marketplacelistings( } } } - + // Item sorting and validation : sorting and moving the various stock items is complicated as the set of constraints is high // We need to: // * separate non stock items, stock items per types in different folders // * have stock items nested at depth 2 at least // * never ever move the non-stock items - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - + + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + // We use a composite (type,permission) key on that map to store UUIDs of items of same (type,permissions) std::map<U32, std::vector<LLUUID> > items_vector; // Parse the items and create vectors of item UUIDs sorting copyable items and stock items of various types bool has_bad_items = false; - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) item; - + // Test but skip items that shouldn't be there to start with, raise an error message for those std::string error_msg; if (!can_move_to_marketplace(item, error_msg, false)) @@ -1797,13 +1797,13 @@ void validate_marketplacelistings( } U32 key = (((U32)(type) & 0xFF) << 24) | (perms & 0xFFFFFF); items_vector[key].push_back(viewer_inv_item->getUUID()); - } - + } + // How many types of items? Which type is it if only one? S32 count = items_vector.size(); U32 default_key = (U32)(LLInventoryType::IT_COUNT) << 24; // This is the key for any normal copyable item U32 unique_key = (count == 1 ? items_vector.begin()->first : default_key); // The key in the case of one item type only - + // If we have no items in there (only folders or empty), analyze a bit further if ((count == 0) && !has_bad_items) { @@ -2029,7 +2029,7 @@ void validate_marketplacelistings( } } } - + // Clean up if (viewer_cat->getDescendentCount() == 0) { @@ -2051,15 +2051,15 @@ void validate_marketplacelistings( // Recursion : Perform the same validation on each nested folder gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; // Sort the folders in alphabetical order first std::sort(cat_array_copy.begin(), cat_array_copy.end(), sort_alpha); - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLInventoryCategory* category = *iter; - validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); - } + + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); + } update_marketplace_category(cat->getUUID(), true, true); if (notify_observers) @@ -2071,22 +2071,22 @@ void validate_marketplacelistings( void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) { - LLInventoryItem* inv_item = gInventory.getItem(item_id); - if (inv_item) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); + LLInventoryItem* inv_item = gInventory.getItem(item_id); + if (inv_item) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } } void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids) @@ -2114,7 +2114,7 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { if (sidepanel_inventory->getActivePanel()) @@ -2301,7 +2301,7 @@ std::string get_localized_folder_name(LLUUID cat_uuid) LLTrans::findString(localized_root_name, std::string("InvFolder ") + cat->getName(), LLSD()); } } - + return localized_root_name; } @@ -2531,62 +2531,62 @@ LLMarketplaceValidator::ValidationRequest::ValidationRequest( // static bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryItem* item) { - if (!item) - return false; + if (!item) + return false; - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if (!get_is_item_worn(item->getUUID())) - return true; - break; - default: - return true; - break; - } - return false; + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if (!get_is_item_worn(item->getUUID())) + return true; + break; + default: + return true; + break; + } + return false; } bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return TRUE; - } - if(item) - { - if(item->getType() == mType) return TRUE; - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return TRUE; + } + if(item) + { + if(item->getType() == mType) return TRUE; + } + return FALSE; } bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return FALSE; - } - if(item) - { - if(item->getType() == mType) return FALSE; - else return TRUE; - } - return TRUE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return FALSE; + } + if(item) + { + if(item->getType() == mType) return FALSE; + else return TRUE; + } + return TRUE; } bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return TRUE; - } - if(item) - { - if(item->getActualType() == mType) return TRUE; - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return TRUE; + } + if(item) + { + if(item->getActualType() == mType) return TRUE; + } + return FALSE; } bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -2597,133 +2597,133 @@ bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryIt bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); - if (!vitem) return false; - return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem) return false; + return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); } bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) - { - return TRUE; - } - } - if(item) - { - if(item->getType() == mType) - { - LLPermissions perm = item->getPermissions(); - if ((perm.getMaskBase() & mPerm) == mPerm) - { - return TRUE; - } - } - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) + { + return TRUE; + } + } + if(item) + { + if(item->getType() == mType) + { + LLPermissions perm = item->getPermissions(); + if ((perm.getMaskBase() & mPerm) == mPerm) + { + return TRUE; + } + } + } + return FALSE; } bool LLBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (!item->getCreatorUUID().isNull()) - && (item->getCreatorUUID() != gAgent.getID())) - { - return true; - } - } - return false; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (!item->getCreatorUUID().isNull()) + && (item->getCreatorUUID() != gAgent.getID())) + { + return true; + } + } + return false; } bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (item->getCreatorUUID().notNull()) - && (item->getCreatorUUID() != gAgent.getID())) - { - mSeen.insert(item->getCreatorUUID()); - return true; - } - } - return false; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (item->getCreatorUUID().notNull()) + && (item->getCreatorUUID() != gAgent.getID())) + { + mSeen.insert(item->getCreatorUUID()); + return true; + } + } + return false; } bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (item->getCreatorUUID() == mBuddyID)) - { - return TRUE; - } - } - return FALSE; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (item->getCreatorUUID() == mBuddyID)) + { + return TRUE; + } + } + return FALSE; } bool LLNameCategoryCollector::operator()( - LLInventoryCategory* cat, LLInventoryItem* item) + LLInventoryCategory* cat, LLInventoryItem* item) { - if(cat) - { - if (!LLStringUtil::compareInsensitive(mName, cat->getName())) - { - return true; - } - } - return false; + if(cat) + { + if (!LLStringUtil::compareInsensitive(mName, cat->getName())) + { + return true; + } + } + return false; } bool LLNameItemCollector::operator()( - LLInventoryCategory* cat, LLInventoryItem* item) + LLInventoryCategory* cat, LLInventoryItem* item) { - if(item) - { - if (!LLStringUtil::compareInsensitive(mName, item->getName())) - { - return true; - } - } - return false; + if(item) + { + if (!LLStringUtil::compareInsensitive(mName, item->getName())) + { + return true; + } + } + return false; } bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - // Valid COF items are: - // - links to wearables (body parts or clothing) - // - links to attachments - // - links to gestures - // - links to ensemble folders - LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); - if (linked_item) - { - LLAssetType::EType type = linked_item->getType(); - return (type == LLAssetType::AT_CLOTHING || - type == LLAssetType::AT_BODYPART || - type == LLAssetType::AT_GESTURE || - type == LLAssetType::AT_OBJECT); - } - else - { - LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); - // BAP remove AT_NONE support after ensembles are fully working? - return (linked_category && - ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || - (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); - } + LLInventoryItem* item) +{ + // Valid COF items are: + // - links to wearables (body parts or clothing) + // - links to attachments + // - links to gestures + // - links to ensemble folders + LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); + if (linked_item) + { + LLAssetType::EType type = linked_item->getType(); + return (type == LLAssetType::AT_CLOTHING || + type == LLAssetType::AT_BODYPART || + type == LLAssetType::AT_GESTURE || + type == LLAssetType::AT_OBJECT); + } + else + { + LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); + // BAP remove AT_NONE support after ensembles are fully working? + return (linked_category && + ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || + (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); + } } bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat, @@ -2740,68 +2740,68 @@ bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat, } bool LLFindWearables::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((item->getType() == LLAssetType::AT_CLOTHING) - || (item->getType() == LLAssetType::AT_BODYPART)) - { - return TRUE; - } - } - return FALSE; + if(item) + { + if((item->getType() == LLAssetType::AT_CLOTHING) + || (item->getType() == LLAssetType::AT_BODYPART)) + { + return TRUE; + } + } + return FALSE; } LLFindWearablesEx::LLFindWearablesEx(bool is_worn, bool include_body_parts) -: mIsWorn(is_worn) -, mIncludeBodyParts(include_body_parts) +: mIsWorn(is_worn) +, mIncludeBodyParts(include_body_parts) {} bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); - if (!vitem) return false; + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem) return false; - // Skip non-wearables. - if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) - { - return false; - } + // Skip non-wearables. + if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) + { + return false; + } - // Skip body parts if requested. - if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) - { - return false; - } + // Skip body parts if requested. + if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) + { + return false; + } - // Skip broken links. - if (vitem->getIsBrokenLink()) - { - return false; - } + // Skip broken links. + if (vitem->getIsBrokenLink()) + { + return false; + } - return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; + return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; } bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if (!item) return false; - if (item->getType() != LLAssetType::AT_CLOTHING && - item->getType() != LLAssetType::AT_BODYPART) - { - return false; - } + if (!item) return false; + if (item->getType() != LLAssetType::AT_CLOTHING && + item->getType() != LLAssetType::AT_BODYPART) + { + return false; + } - LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); - if (!vitem || vitem->getWearableType() != mWearableType) return false; + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem || vitem->getWearableType() != mWearableType) return false; - return true; + return true; } void LLFindWearablesOfType::setType(LLWearableType::EType type) { - mWearableType = type; + mWearableType = type; } bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -2811,141 +2811,141 @@ bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if (item) - { - return !get_is_item_removable(&gInventory, item->getUUID()); - } - if (cat) - { - return !get_is_category_removable(&gInventory, cat->getUUID()); - } + if (item) + { + return !get_is_item_removable(&gInventory, item->getUUID()); + } + if (cat) + { + return !get_is_category_removable(&gInventory, cat->getUUID()); + } - LL_WARNS() << "Not a category and not an item?" << LL_ENDL; - return false; + LL_WARNS() << "Not a category and not an item?" << LL_ENDL; + return false; } ///---------------------------------------------------------------------------- -/// LLAssetIDMatches +/// LLAssetIDMatches ///---------------------------------------------------------------------------- bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - return (item && item->getAssetUUID() == mAssetID); + return (item && item->getAssetUUID() == mAssetID); } ///---------------------------------------------------------------------------- -/// LLLinkedItemIDMatches +/// LLLinkedItemIDMatches ///---------------------------------------------------------------------------- bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - return (item && - (item->getIsLinkType()) && - (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. + return (item && + (item->getIsLinkType()) && + (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. } void LLSaveFolderState::setApply(BOOL apply) { - mApply = apply; - // before generating new list of open folders, clear the old one - if(!apply) - { - clearOpenFolders(); - } + mApply = apply; + // before generating new list of open folders, clear the old one + if(!apply) + { + clearOpenFolders(); + } } void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getViewModelItem(); - if(!bridge) return; - - if(mApply) - { - // we're applying the open state - LLUUID id(bridge->getUUID()); - if(mOpenFolders.find(id) != mOpenFolders.end()) - { - if (!folder->isOpen()) - { - folder->setOpen(TRUE); - } - } - else - { - // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected() && folder->isOpen()) - { - folder->setOpen(FALSE); - } - } - } - else - { - // we're recording state at this point - if(folder->isOpen()) - { - mOpenFolders.insert(bridge->getUUID()); - } - } + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getViewModelItem(); + if(!bridge) return; + + if(mApply) + { + // we're applying the open state + LLUUID id(bridge->getUUID()); + if(mOpenFolders.find(id) != mOpenFolders.end()) + { + if (!folder->isOpen()) + { + folder->setOpen(TRUE); + } + } + else + { + // keep selected filter in its current state, this is less jarring to user + if (!folder->isSelected() && folder->isOpen()) + { + folder->setOpen(FALSE); + } + } + } + else + { + // we're recording state at this point + if(folder->isOpen()) + { + mOpenFolders.insert(bridge->getUUID()); + } + } } void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) { - if (item->passedFilter()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (item->passedFilter()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) { - if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - // if this folder didn't pass the filter, and none of its descendants did - else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter()) - { - folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); - } + if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + // if this folder didn't pass the filter, and none of its descendants did + else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter()) + { + folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); + } } void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) { - if (item->passedFilter() && !mItemSelected) - { - item->getRoot()->setSelection(item, FALSE, FALSE); - if (item->getParentFolder()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - mItemSelected = TRUE; - } + if (item->passedFilter() && !mItemSelected) + { + item->getRoot()->setSelection(item, FALSE, FALSE); + if (item->getParentFolder()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + mItemSelected = TRUE; + } } void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) { - // Skip if folder or item already found, if not filtered or if no parent (root folder is not selectable) - if (!mFolderSelected && !mItemSelected && folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) - { - folder->getRoot()->setSelection(folder, FALSE, FALSE); - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - mFolderSelected = TRUE; - } + // Skip if folder or item already found, if not filtered or if no parent (root folder is not selectable) + if (!mFolderSelected && !mItemSelected && folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) + { + folder->getRoot()->setSelection(folder, FALSE, FALSE); + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + mFolderSelected = TRUE; + } } void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) { - if (item->getParentFolder() && item->isSelected()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (item->getParentFolder() && item->isSelected()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) { - if (folder->getParentFolder() && folder->isSelected()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (folder->getParentFolder() && folder->isSelected()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } // Callback for doToSelected if DAMA required... @@ -2975,34 +2975,34 @@ void LLInventoryAction::callback_copySelected(const LLSD& notification, const LL // case returns their corresponding uuids. bool get_selection_object_uuids(LLFolderView *root, uuid_vec_t& ids) { - uuid_vec_t results; - S32 non_object = 0; - LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); - for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) - { - LLObjectBridge *view_model = dynamic_cast<LLObjectBridge *>((*it)->getViewModelItem()); - - if(view_model && view_model->getUUID().notNull()) - { - results.push_back(view_model->getUUID()); - } - else - { - non_object++; - } - } - if (non_object == 0) - { - ids = results; - return true; - } - return false; + uuid_vec_t results; + S32 non_object = 0; + LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); + for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + LLObjectBridge *view_model = dynamic_cast<LLObjectBridge *>((*it)->getViewModelItem()); + + if(view_model && view_model->getUUID().notNull()) + { + results.push_back(view_model->getUUID()); + } + else + { + non_object++; + } + } + if (non_object == 0) + { + ids = results; + return true; + } + return false; } void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm) { - std::set<LLFolderViewItem*> selected_items = root->getSelectionList(); + std::set<LLFolderViewItem*> selected_items = root->getSelectionList(); if (selected_items.empty() && action != "wear" && action != "wear_add" @@ -3020,9 +3020,9 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } - + // Prompt the user and check for authorization for some marketplace active listing edits - if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) + if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) { std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); LLFolderViewModelItemInventory * viewModel = NULL; @@ -3079,138 +3079,138 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } } - + // Keep track of the marketplace folders that will need update of their status/name after the operation is performed buildMarketplaceFolders(root); - - if ("rename" == action) - { - root->startRenamingSelectedItem(); + + if ("rename" == action) + { + root->startRenamingSelectedItem(); // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - return; - } - - if ("delete" == action) - { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - bool marketplacelistings_item = false; - LLAllDescendentsPassedFilter f; - for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) - { - if (LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*it)) - { - folder->applyFunctorRecursively(f); - } - LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem()); - if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) - { - marketplacelistings_item = true; - break; - } - } - // Fall through to the generic confirmation if the user choose to ignore the specialized one - if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) - { - LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); - } - else - { - if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session - { - LLNotifications::instance().setIgnored("DeleteItems", false); - sDeleteConfirmationDisplayed = true; - } - - LLSD args; - args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); - LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); - } + return; + } + + if ("delete" == action) + { + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + bool marketplacelistings_item = false; + LLAllDescendentsPassedFilter f; + for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) + { + if (LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*it)) + { + folder->applyFunctorRecursively(f); + } + LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem()); + if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) + { + marketplacelistings_item = true; + break; + } + } + // Fall through to the generic confirmation if the user choose to ignore the specialized one + if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) + { + LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } + else + { + if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session + { + LLNotifications::instance().setIgnored("DeleteItems", false); + sDeleteConfirmationDisplayed = true; + } + + LLSD args; + args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); + LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } // Note: marketplace listings will be updated in the callback if delete confirmed - return; - } - if (("copy" == action) || ("cut" == action)) - { - // Clear the clipboard before we start adding things on it - LLClipboard::instance().reset(); - } - if ("replace_links" == action) - { - LLSD params; - if (root->getSelectedCount() == 1) - { - LLFolderViewItem* folder_item = root->getSelectedItems().front(); - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); - - if (bridge) - { - LLInventoryObject* obj = bridge->getInventoryObject(); - if (obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getActualType() != LLAssetType::AT_LINK_FOLDER) - { - params = LLSD(obj->getUUID()); - } - } - } - LLFloaterReg::showInstance("linkreplace", params); - return; - } - - static const std::string change_folder_string = "change_folder_type_"; - if (action.length() > change_folder_string.length() && - (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) - { - LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); - LLFolderViewModelItemInventory* inventory_item = static_cast<LLFolderViewModelItemInventory*>(root->getViewModelItem()); - LLViewerInventoryCategory *cat = model->getCategory(inventory_item->getUUID()); - if (!cat) return; - cat->changeType(new_folder_type); + return; + } + if (("copy" == action) || ("cut" == action)) + { + // Clear the clipboard before we start adding things on it + LLClipboard::instance().reset(); + } + if ("replace_links" == action) + { + LLSD params; + if (root->getSelectedCount() == 1) + { + LLFolderViewItem* folder_item = root->getSelectedItems().front(); + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); + + if (bridge) + { + LLInventoryObject* obj = bridge->getInventoryObject(); + if (obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getActualType() != LLAssetType::AT_LINK_FOLDER) + { + params = LLSD(obj->getUUID()); + } + } + } + LLFloaterReg::showInstance("linkreplace", params); + return; + } + + static const std::string change_folder_string = "change_folder_type_"; + if (action.length() > change_folder_string.length() && + (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) + { + LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); + LLFolderViewModelItemInventory* inventory_item = static_cast<LLFolderViewModelItemInventory*>(root->getViewModelItem()); + LLViewerInventoryCategory *cat = model->getCategory(inventory_item->getUUID()); + if (!cat) return; + cat->changeType(new_folder_type); // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - return; - } - - - LLMultiPreview* multi_previewp = NULL; - LLMultiItemProperties* multi_itempropertiesp = nullptr; - - if (("task_open" == action || "open" == action) && selected_items.size() > 1) - { - bool open_multi_preview = true; - - if ("open" == action) - { - for (std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) - { - LLFolderViewItem* folder_item = *set_iter; - if (folder_item) - { - LLInvFVBridge* bridge = dynamic_cast<LLInvFVBridge*>(folder_item->getViewModelItem()); - if (!bridge || !bridge->isMultiPreviewAllowed()) - { - open_multi_preview = false; - break; - } - } - } - } - - if (open_multi_preview) - { - multi_previewp = new LLMultiPreview(); - gFloaterView->addChild(multi_previewp); - - LLFloater::setFloaterHost(multi_previewp); - } - - } - else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) - { - multi_itempropertiesp = new LLMultiItemProperties("item_properties"); - gFloaterView->addChild(multi_itempropertiesp); - LLFloater::setFloaterHost(multi_itempropertiesp); - } - - std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); + return; + } + + + LLMultiPreview* multi_previewp = NULL; + LLMultiItemProperties* multi_itempropertiesp = nullptr; + + if (("task_open" == action || "open" == action) && selected_items.size() > 1) + { + bool open_multi_preview = true; + + if ("open" == action) + { + for (std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewItem* folder_item = *set_iter; + if (folder_item) + { + LLInvFVBridge* bridge = dynamic_cast<LLInvFVBridge*>(folder_item->getViewModelItem()); + if (!bridge || !bridge->isMultiPreviewAllowed()) + { + open_multi_preview = false; + break; + } + } + } + } + + if (open_multi_preview) + { + multi_previewp = new LLMultiPreview(); + gFloaterView->addChild(multi_previewp); + + LLFloater::setFloaterHost(multi_previewp); + } + + } + else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) + { + multi_itempropertiesp = new LLMultiItemProperties("item_properties"); + gFloaterView->addChild(multi_itempropertiesp); + LLFloater::setFloaterHost(multi_itempropertiesp); + } + + std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); // copy list of applicable items into a vector for bulk handling uuid_vec_t ids; @@ -3307,10 +3307,10 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } } - + LLSD args; args["DESC"] = LLTrans::getString("New Folder"); - + LLNotificationsUtil::add("CreateSubfolder", args, LLSD(), [ids](const LLSD& notification, const LLSD& response) { @@ -3358,22 +3358,22 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - - LLFloater::setFloaterHost(NULL); - if (multi_previewp) - { - multi_previewp->openFloater(LLSD()); - } - else if (multi_itempropertiesp) - { - multi_itempropertiesp->openFloater(LLSD()); - } + + LLFloater::setFloaterHost(NULL); + if (multi_previewp) + { + multi_previewp->openFloater(LLSD()); + } + else if (multi_itempropertiesp) + { + multi_itempropertiesp->openFloater(LLSD()); + } } void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model) { gSavedSettings.setString("TextureSaveLocation", filenames[0]); - + LLMultiPreview* multi_previewp = new LLMultiPreview(); gFloaterView->addChild(multi_previewp); @@ -3381,7 +3381,7 @@ void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& fil std::map<std::string, S32> tex_names_map; std::set<LLFolderViewItem*>::iterator set_iter; - + for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) { LLFolderViewItem* folder_item = *set_iter; @@ -3390,10 +3390,10 @@ void LLInventoryAction::saveMultipleTextures(const std::vector<std::string>& fil if(!bridge) continue; std::string tex_name = bridge->getName(); - if(!tex_names_map.insert(std::pair<std::string, S32>(tex_name, 0)).second) - { + if(!tex_names_map.insert(std::pair<std::string, S32>(tex_name, 0)).second) + { tex_names_map[tex_name]++; - bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); + bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); } bridge->performAction(model, "save_selected_as"); } @@ -3430,18 +3430,18 @@ void LLInventoryAction::removeItemFromDND(LLFolderView* root) void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0 && !root.isDead() && !root.get()->isDead()) - { - LLFolderView* folder_root = root.get(); - //Need to remove item from DND before item is removed from root folder view - //because once removed from root folder view the item is no longer a selected item - removeItemFromDND(folder_root); - folder_root->removeSelectedItems(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0 && !root.isDead() && !root.get()->isDead()) + { + LLFolderView* folder_root = root.get(); + //Need to remove item from DND before item is removed from root folder view + //because once removed from root folder view the item is no longer a selected item + removeItemFromDND(folder_root); + folder_root->removeSelectedItems(); - // Update the marketplace listings that have been affected by the operation - updateMarketplaceFolders(); - } + // Update the marketplace listings that have been affected by the operation + updateMarketplaceFolders(); + } } void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) @@ -3457,7 +3457,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.isNull()) { - return; + return; } std::set<LLFolderViewItem*> selected_items = root->getSelectionList(); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index edc83147f2..8edb51b5a8 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -1,4 +1,4 @@ -/** +/** * @file llinventoryfunctions.h * @brief Miscellaneous inventory-related functions and classes * class definition @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -184,10 +184,10 @@ private: class LLInventoryCollectFunctor { public: - virtual ~LLInventoryCollectFunctor(){}; - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; + virtual ~LLInventoryCollectFunctor(){}; + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; - static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); + static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -200,12 +200,12 @@ class LLViewerInventoryItem; class LLAssetIDMatches : public LLInventoryCollectFunctor { public: - LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} - virtual ~LLAssetIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - + LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} + virtual ~LLAssetIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + protected: - LLUUID mAssetID; + LLUUID mAssetID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -217,12 +217,12 @@ protected: class LLLinkedItemIDMatches : public LLInventoryCollectFunctor { public: - LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} - virtual ~LLLinkedItemIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - + LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} + virtual ~LLLinkedItemIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + protected: - LLUUID mBaseItemID; + LLUUID mBaseItemID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -235,12 +235,12 @@ protected: class LLIsType : public LLInventoryCollectFunctor { public: - LLIsType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -252,12 +252,12 @@ protected: class LLIsNotType : public LLInventoryCollectFunctor { public: - LLIsNotType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsNotType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsNotType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsNotType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -271,12 +271,12 @@ protected: class LLIsOfAssetType : public LLInventoryCollectFunctor { public: - LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsOfAssetType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsOfAssetType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -304,23 +304,23 @@ protected: class LLIsValidItemLink : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; class LLIsTypeWithPermissions : public LLInventoryCollectFunctor { public: - LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) - : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} - virtual ~LLIsTypeWithPermissions() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) + : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} + virtual ~LLIsTypeWithPermissions() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; - PermissionBit mPerm; - LLUUID mAgentID; - LLUUID mGroupID; + LLAssetType::EType mType; + PermissionBit mPerm; + LLUUID mAgentID; + LLUUID mGroupID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -332,10 +332,10 @@ protected: class LLBuddyCollector : public LLInventoryCollectFunctor { public: - LLBuddyCollector() {} - virtual ~LLBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLBuddyCollector() {} + virtual ~LLBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -347,13 +347,13 @@ public: class LLUniqueBuddyCollector : public LLInventoryCollectFunctor { public: - LLUniqueBuddyCollector() {} - virtual ~LLUniqueBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLUniqueBuddyCollector() {} + virtual ~LLUniqueBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::set<LLUUID> mSeen; + std::set<LLUUID> mSeen; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -365,12 +365,12 @@ protected: class LLParticularBuddyCollector : public LLInventoryCollectFunctor { public: - LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} - virtual ~LLParticularBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} + virtual ~LLParticularBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLUUID mBuddyID; + LLUUID mBuddyID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -381,12 +381,12 @@ protected: class LLNameCategoryCollector : public LLInventoryCollectFunctor { public: - LLNameCategoryCollector(const std::string& name) : mName(name) {} - virtual ~LLNameCategoryCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLNameCategoryCollector(const std::string& name) : mName(name) {} + virtual ~LLNameCategoryCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::string mName; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -397,12 +397,12 @@ protected: class LLNameItemCollector : public LLInventoryCollectFunctor { public: - LLNameItemCollector(const std::string& name) : mName(name) {} - virtual ~LLNameItemCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLNameItemCollector(const std::string& name) : mName(name) {} + virtual ~LLNameItemCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::string mName; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -413,11 +413,11 @@ protected: class LLFindCOFValidItems : public LLInventoryCollectFunctor { public: - LLFindCOFValidItems() {} - virtual ~LLFindCOFValidItems() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - + LLFindCOFValidItems() {} + virtual ~LLFindCOFValidItems() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -440,23 +440,23 @@ public: class LLFindByMask : public LLInventoryCollectFunctor { public: - LLFindByMask(U64 mask) - : mFilterMask(mask) - {} + LLFindByMask(U64 mask) + : mFilterMask(mask) + {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - //converting an inventory type to a bitmap filter mask - if(item && (mFilterMask & (1LL << item->getInventoryType())) ) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + //converting an inventory type to a bitmap filter mask + if(item && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } - return false; - } + return false; + } private: - U64 mFilterMask; + U64 mFilterMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -467,27 +467,27 @@ private: class LLFindNonLinksByMask : public LLInventoryCollectFunctor { public: - LLFindNonLinksByMask(U64 mask) - : mFilterMask(mask) - {} + LLFindNonLinksByMask(U64 mask) + : mFilterMask(mask) + {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } - return false; - } + return false; + } - void setFilterMask(U64 mask) - { - mFilterMask = mask; - } + void setFilterMask(U64 mask) + { + mFilterMask = mask; + } private: - U64 mFilterMask; + U64 mFilterMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -498,10 +498,10 @@ private: class LLFindWearables : public LLInventoryCollectFunctor { public: - LLFindWearables() {} - virtual ~LLFindWearables() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLFindWearables() {} + virtual ~LLFindWearables() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -512,24 +512,24 @@ public: class LLFindWearablesEx : public LLInventoryCollectFunctor { public: - LLFindWearablesEx(bool is_worn, bool include_body_parts = true); - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + LLFindWearablesEx(bool is_worn, bool include_body_parts = true); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); private: - bool mIncludeBodyParts; - bool mIsWorn; + bool mIncludeBodyParts; + bool mIsWorn; }; //Inventory collect functor collecting wearables of a specific wearable type class LLFindWearablesOfType : public LLInventoryCollectFunctor { public: - LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} - virtual ~LLFindWearablesOfType() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - void setType(LLWearableType::EType type); + LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} + virtual ~LLFindWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + void setType(LLWearableType::EType type); private: - LLWearableType::EType mWearableType; + LLWearableType::EType mWearableType; }; class LLIsTextureType : public LLInventoryCollectFunctor @@ -545,33 +545,33 @@ public: class LLFindActualWearablesOfType : public LLFindWearablesOfType { public: - LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} - virtual ~LLFindActualWearablesOfType() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if (item && item->getIsLinkType()) return false; - return LLFindWearablesOfType::operator()(cat, item); - } + LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} + virtual ~LLFindActualWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLFindWearablesOfType::operator()(cat, item); + } }; /* Filters out items of a particular asset type */ class LLIsTypeActual : public LLIsType { public: - LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} - virtual ~LLIsTypeActual() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if (item && item->getIsLinkType()) return false; - return LLIsType::operator()(cat, item); - } + LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} + virtual ~LLIsTypeActual() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLIsType::operator()(cat, item); + } }; // Collect non-removable folders and items. class LLFindNonRemovableObjects : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); }; /** Inventory Collector Functions @@ -585,27 +585,27 @@ class LLFolderView; class LLInventoryState { public: - // HACK: Until we can route this info through the instant message hierarchy - static BOOL sWearNewClothing; - static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction + // HACK: Until we can route this info through the instant message hierarchy + static BOOL sWearNewClothing; + static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction }; struct LLInventoryAction { - static void doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm = TRUE); - static void callback_doToSelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); - static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); - static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root); - static void removeItemFromDND(LLFolderView* root); + static void doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm = TRUE); + static void callback_doToSelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); + static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); + static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root); + static void removeItemFromDND(LLFolderView* root); static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model); static bool sDeleteConfirmationDisplayed; private: - static void buildMarketplaceFolders(LLFolderView* root); - static void updateMarketplaceFolders(); - static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed + static void buildMarketplaceFolders(LLFolderView* root); + static void updateMarketplaceFolders(); + static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed }; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 3a930684a4..6408d4eaf6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llinventorymodel.cpp * @brief Implementation of the inventory model used to track agent inventory. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,7 +50,7 @@ #include "llwindow.h" #include "llviewercontrol.h" #include "llviewernetwork.h" -#include "llpreview.h" +#include "llpreview.h" #include "llviewergenericmessage.h" #include "llviewermessage.h" #include "llviewerfoldertype.h" @@ -94,49 +94,49 @@ static const char * const LOG_INV("Inventory"); struct InventoryIDPtrLess { - bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const - { - return (i1->getUUID() < i2->getUUID()); - } + bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const + { + return (i1->getUUID() < i2->getUUID()); + } }; -class LLCanCache : public LLInventoryCollectFunctor +class LLCanCache : public LLInventoryCollectFunctor { public: - LLCanCache(LLInventoryModel* model) : mModel(model) {} - virtual ~LLCanCache() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + LLCanCache(LLInventoryModel* model) : mModel(model) {} + virtual ~LLCanCache() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); protected: - LLInventoryModel* mModel; - std::set<LLUUID> mCachedCatIDs; + LLInventoryModel* mModel; + std::set<LLUUID> mCachedCatIDs; }; bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - bool rv = false; - if(item) - { - if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) - { - rv = true; - } - } - else if(cat) - { - // HACK: downcast - LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; - if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = c->getDescendentCount(); - S32 descendents_actual = c->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - mCachedCatIDs.insert(c->getUUID()); - rv = true; - } - } - } - return rv; + bool rv = false; + if(item) + { + if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) + { + rv = true; + } + } + else if(cat) + { + // HACK: downcast + LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; + if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + S32 descendents_server = c->getDescendentCount(); + S32 descendents_actual = c->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + mCachedCatIDs.insert(c->getUUID()); + rv = true; + } + } + } + return rv; } struct InventoryCallbackInfo @@ -364,7 +364,7 @@ LLInventoryValidationInfo::LLInventoryValidationInfo() void LLInventoryValidationInfo::toOstream(std::ostream& os) const { - os << "mFatalErrorCount " << mFatalErrorCount + os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount << " mLoopCount " << mLoopCount << " mOrphanedCount " << mOrphanedCount; @@ -373,52 +373,52 @@ void LLInventoryValidationInfo::toOstream(std::ostream& os) const std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) { - v.toOstream(os); - return os; + v.toOstream(os); + return os; } void LLInventoryValidationInfo::asLLSD(LLSD& sd) const { - sd["fatal_error_count"] = mFatalErrorCount; + sd["fatal_error_count"] = mFatalErrorCount; sd["loop_count"] = mLoopCount; sd["orphaned_count"] = mOrphanedCount; - sd["initialized"] = mInitialized; - sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); - sd["fatal_no_root_folder"] = mFatalNoRootFolder; - sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder; - sd["fatal_qa_debug_mode"] = mFatalQADebugMode; - - sd["warning_count"] = mWarningCount; - if (mWarningCount>0) - { - sd["warnings"] = LLSD::emptyArray(); - for (auto const& it : mWarnings) - { - S32 val =LLSD::Integer(it.second); - if (val>0) - { - sd["warnings"][it.first] = val; - } - } - } - if (mMissingRequiredSystemFolders.size()>0) - { - sd["missing_system_folders"] = LLSD::emptyArray(); - for(auto ft: mMissingRequiredSystemFolders) - { - sd["missing_system_folders"].append(LLFolderType::lookup(ft)); - } - } - sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); - if (mDuplicateRequiredSystemFolders.size()>0) - { - sd["duplicate_system_folders"] = LLSD::emptyArray(); - for(auto ft: mDuplicateRequiredSystemFolders) - { - sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); - } - } - + sd["initialized"] = mInitialized; + sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); + sd["fatal_no_root_folder"] = mFatalNoRootFolder; + sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder; + sd["fatal_qa_debug_mode"] = mFatalQADebugMode; + + sd["warning_count"] = mWarningCount; + if (mWarningCount>0) + { + sd["warnings"] = LLSD::emptyArray(); + for (auto const& it : mWarnings) + { + S32 val =LLSD::Integer(it.second); + if (val>0) + { + sd["warnings"][it.first] = val; + } + } + } + if (mMissingRequiredSystemFolders.size()>0) + { + sd["missing_system_folders"] = LLSD::emptyArray(); + for(auto ft: mMissingRequiredSystemFolders) + { + sd["missing_system_folders"].append(LLFolderType::lookup(ft)); + } + } + sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); + if (mDuplicateRequiredSystemFolders.size()>0) + { + sd["duplicate_system_folders"] = LLSD::emptyArray(); + for(auto ft: mDuplicateRequiredSystemFolders) + { + sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); + } + } + } ///---------------------------------------------------------------------------- @@ -431,117 +431,117 @@ LLInventoryModel gInventory; // Default constructor LLInventoryModel::LLInventoryModel() : // These are now ordered, keep them that way. - mBacklinkMMap(), - mIsAgentInvUsable(false), - mRootFolderID(), - mLibraryRootFolderID(), - mLibraryOwnerID(), - mCategoryMap(), - mItemMap(), - mParentChildCategoryTree(), - mParentChildItemTree(), - mLastItem(NULL), - mIsNotifyObservers(FALSE), - mModifyMask(LLInventoryObserver::ALL), - mChangedItemIDs(), + mBacklinkMMap(), + mIsAgentInvUsable(false), + mRootFolderID(), + mLibraryRootFolderID(), + mLibraryOwnerID(), + mCategoryMap(), + mItemMap(), + mParentChildCategoryTree(), + mParentChildItemTree(), + mLastItem(NULL), + mIsNotifyObservers(FALSE), + mModifyMask(LLInventoryObserver::ALL), + mChangedItemIDs(), mBulkFecthCallbackSlot(), - mObservers(), - mHttpRequestFG(NULL), - mHttpRequestBG(NULL), - mHttpOptions(), - mHttpHeaders(), - mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mCategoryLock(), - mItemLock(), - mValidationInfo(new LLInventoryValidationInfo) + mObservers(), + mHttpRequestFG(NULL), + mHttpRequestBG(NULL), + mHttpOptions(), + mHttpHeaders(), + mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mCategoryLock(), + mItemLock(), + mValidationInfo(new LLInventoryValidationInfo) {} // Destroys the object LLInventoryModel::~LLInventoryModel() { - cleanupInventory(); + cleanupInventory(); } void LLInventoryModel::cleanupInventory() { - empty(); - // Deleting one observer might erase others from the list, so always pop off the front - while (!mObservers.empty()) - { - observer_list_t::iterator iter = mObservers.begin(); - LLInventoryObserver* observer = *iter; - mObservers.erase(iter); - delete observer; - } + empty(); + // Deleting one observer might erase others from the list, so always pop off the front + while (!mObservers.empty()) + { + observer_list_t::iterator iter = mObservers.begin(); + LLInventoryObserver* observer = *iter; + mObservers.erase(iter); + delete observer; + } if (mBulkFecthCallbackSlot.connected()) { mBulkFecthCallbackSlot.disconnect(); } - mObservers.clear(); + mObservers.clear(); - // Run down HTTP transport + // Run down HTTP transport mHttpHeaders.reset(); mHttpOptions.reset(); - delete mHttpRequestFG; - mHttpRequestFG = NULL; - delete mHttpRequestBG; - mHttpRequestBG = NULL; + delete mHttpRequestFG; + mHttpRequestFG = NULL; + delete mHttpRequestBG; + mHttpRequestBG = NULL; } // This is a convenience function to check if one object has a parent // chain up to the category specified by UUID. BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, - const LLUUID& cat_id) const + const LLUUID& cat_id) const { - if (obj_id == cat_id) return TRUE; - - const LLInventoryObject* obj = getObject(obj_id); - while(obj) - { - const LLUUID& parent_id = obj->getParentUUID(); - if( parent_id.isNull() ) - { - return FALSE; - } - if(parent_id == cat_id) - { - return TRUE; - } - // Since we're scanning up the parents, we only need to check - // in the category list. - obj = getCategory(parent_id); - } - return FALSE; + if (obj_id == cat_id) return TRUE; + + const LLInventoryObject* obj = getObject(obj_id); + while(obj) + { + const LLUUID& parent_id = obj->getParentUUID(); + if( parent_id.isNull() ) + { + return FALSE; + } + if(parent_id == cat_id) + { + return TRUE; + } + // Since we're scanning up the parents, we only need to check + // in the category list. + obj = getCategory(parent_id); + } + return FALSE; } const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const { - const LLInventoryObject* obj = getObject(obj_id); - if(!obj) - { - LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; - return NULL; - } - // Search up the parent chain until we get to root or an acceptable folder. - // This assumes there are no cycles in the tree else we'll get a hang. - LLUUID parent_id = obj->getParentUUID(); - while (!parent_id.isNull()) - { - const LLViewerInventoryCategory *cat = getCategory(parent_id); - if (!cat) break; - const LLFolderType::EType folder_type = cat->getPreferredType(); - if (folder_type != LLFolderType::FT_NONE && - folder_type != LLFolderType::FT_ROOT_INVENTORY && - !LLFolderType::lookupIsEnsembleType(folder_type)) - { - return cat; - } - parent_id = cat->getParentUUID(); - } - return NULL; + const LLInventoryObject* obj = getObject(obj_id); + if(!obj) + { + LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; + return NULL; + } + // Search up the parent chain until we get to root or an acceptable folder. + // This assumes there are no cycles in the tree else we'll get a hang. + LLUUID parent_id = obj->getParentUUID(); + while (!parent_id.isNull()) + { + const LLViewerInventoryCategory *cat = getCategory(parent_id); + if (!cat) break; + const LLFolderType::EType folder_type = cat->getPreferredType(); + if (folder_type != LLFolderType::FT_NONE && + folder_type != LLFolderType::FT_ROOT_INVENTORY && + !LLFolderType::lookupIsEnsembleType(folder_type)) + { + return cat; + } + parent_id = cat->getParentUUID(); + } + return NULL; } // @@ -549,36 +549,36 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons // const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const { - if (master_parent_id == obj_id) - { - return NULL; - } - - const LLViewerInventoryCategory* current_cat = getCategory(obj_id); - - if (current_cat == NULL) - { - current_cat = getCategory(getObject(obj_id)->getParentUUID()); - } - - while (current_cat != NULL) - { - const LLUUID& current_parent_id = current_cat->getParentUUID(); - - if (current_parent_id == master_parent_id) - { - return current_cat; - } - - current_cat = getCategory(current_parent_id); - } - - return NULL; + if (master_parent_id == obj_id) + { + return NULL; + } + + const LLViewerInventoryCategory* current_cat = getCategory(obj_id); + + if (current_cat == NULL) + { + current_cat = getCategory(getObject(obj_id)->getParentUUID()); + } + + while (current_cat != NULL) + { + const LLUUID& current_parent_id = current_cat->getParentUUID(); + + if (current_parent_id == master_parent_id) + { + return current_cat; + } + + current_cat = getCategory(current_parent_id); + } + + return NULL; } LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const { - LLInventoryObject *object = getObject(object_id); + LLInventoryObject *object = getObject(object_id); if (!object) { LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL; @@ -596,73 +596,73 @@ LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(con } object_ids.insert(parent_id); LLInventoryObject *parent_object = getObject(parent_id); - if (!parent_object) - { - LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; - return ANCESTOR_MISSING; - } - object = parent_object; - } - result = object->getUUID(); - return ANCESTOR_OK; + if (!parent_object) + { + LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; + return ANCESTOR_MISSING; + } + object = parent_object; + } + result = object->getUUID(); + return ANCESTOR_OK; } // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { - LLViewerInventoryCategory* cat = getCategory(id); - if (cat) - { - return cat; - } - LLViewerInventoryItem* item = getItem(id); - if (item) - { - return item; - } - return NULL; + LLViewerInventoryCategory* cat = getCategory(id); + if (cat) + { + return cat; + } + LLViewerInventoryItem* item = getItem(id); + if (item) + { + return item; + } + return NULL; } // Get the item by id. Returns NULL if not found. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const { - LLViewerInventoryItem* item = NULL; - if(mLastItem.notNull() && mLastItem->getUUID() == id) - { - item = mLastItem; - } - else - { - item_map_t::const_iterator iter = mItemMap.find(id); - if (iter != mItemMap.end()) - { - item = iter->second; - mLastItem = item; - } - } - return item; + LLViewerInventoryItem* item = NULL; + if(mLastItem.notNull() && mLastItem->getUUID() == id) + { + item = mLastItem; + } + else + { + item_map_t::const_iterator iter = mItemMap.find(id); + if (iter != mItemMap.end()) + { + item = iter->second; + mLastItem = item; + } + } + return item; } // Get the category by id. Returns NULL if not found LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const { - LLViewerInventoryCategory* category = NULL; - cat_map_t::const_iterator iter = mCategoryMap.find(id); - if (iter != mCategoryMap.end()) - { - category = iter->second; - } - return category; + LLViewerInventoryCategory* category = NULL; + cat_map_t::const_iterator iter = mCategoryMap.find(id); + if (iter != mCategoryMap.end()) + { + category = iter->second; + } + return category; } S32 LLInventoryModel::getItemCount() const { - return mItemMap.size(); + return mItemMap.size(); } S32 LLInventoryModel::getCategoryCount() const { - return mCategoryMap.size(); + return mCategoryMap.size(); } // Return the direct descendents of the id provided. The array @@ -671,11 +671,11 @@ S32 LLInventoryModel::getCategoryCount() const // may invalidate the internal state of the inventory. Set passed // in values to NULL if the call fails. void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, - cat_array_t*& categories, - item_array_t*& items) const + cat_array_t*& categories, + item_array_t*& items) const { - categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); - items = get_ptr_in_map(mParentChildItemTree, cat_id); + categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); + items = get_ptr_in_map(mParentChildItemTree, cat_id); } void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const @@ -684,10 +684,10 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& { for (LLViewerInventoryCategory* pFolder : *categoriesp) { - if (f(pFolder, nullptr)) - { - categories.push_back(pFolder); - } + if (f(pFolder, nullptr)) + { + categories.push_back(pFolder); + } } } @@ -695,56 +695,56 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& { for (LLViewerInventoryItem* pItem : *itemsp) { - if (f(nullptr, pItem)) - { - items.push_back(pItem); - } + if (f(nullptr, pItem)) + { + items.push_back(pItem); + } } } } LLInventoryModel::digest_t LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - getDirectDescendentsOf(cat_id,cat_array,item_array); - if (!item_array) - { - return LLUUID::null; - } - HBXXH128 item_name_hash; - for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); - iter != item_array->end(); - iter++) - { - const LLViewerInventoryItem *item = (*iter); - if (!item) - continue; - item_name_hash.update(item->getName()); - } - return item_name_hash.digest(); + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + getDirectDescendentsOf(cat_id,cat_array,item_array); + if (!item_array) + { + return LLUUID::null; + } + HBXXH128 item_name_hash; + for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); + iter != item_array->end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + if (!item) + continue; + item_name_hash.update(item->getName()); + } + return item_name_hash.digest(); } // SJB: Added version to lock the arrays to catch potential logic bugs void LLInventoryModel::lockDirectDescendentArrays(const LLUUID& cat_id, - cat_array_t*& categories, - item_array_t*& items) + cat_array_t*& categories, + item_array_t*& items) { - getDirectDescendentsOf(cat_id, categories, items); - if (categories) - { - mCategoryLock[cat_id] = true; - } - if (items) - { - mItemLock[cat_id] = true; - } + getDirectDescendentsOf(cat_id, categories, items); + if (categories) + { + mCategoryLock[cat_id] = true; + } + if (items) + { + mItemLock[cat_id] = true; + } } void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) { - mCategoryLock[cat_id] = false; - mItemLock[cat_id] = false; + mCategoryLock[cat_id] = false; + mItemLock[cat_id] = false; } void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::EType type) @@ -761,15 +761,15 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } // Iterate through those folders - for (std::vector<LLUUID>::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) - { - LLUUID folder_id = (*folder_ids_it); - + for (std::vector<LLUUID>::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) + { + LLUUID folder_id = (*folder_ids_it); + // Get the content of this folder cat_array_t* cats; item_array_t* items; getDirectDescendentsOf(folder_id, cats, items); - + // Move all items to the main folder // Note : we get the list of UUIDs and iterate on them instead of iterating directly on item_array_t // elements. This is because moving elements modify the maps and, consequently, invalidate iterators on them. @@ -809,7 +809,7 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } } remove_inventory_category(folder_id, NULL); - } + } } void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type) @@ -881,49 +881,49 @@ void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred } const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( - LLFolderType::EType preferred_type, - const LLUUID& root_id) const + LLFolderType::EType preferred_type, + const LLUUID& root_id) const { - LLUUID rv = LLUUID::null; - if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) - { - rv = root_id; - } - else if (root_id.notNull()) - { - cat_array_t* cats = NULL; - cats = get_ptr_in_map(mParentChildCategoryTree, root_id); - if(cats) - { - S32 count = cats->size(); - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* p_cat = cats->at(i); - if(p_cat && p_cat->getPreferredType() == preferred_type) - { - const LLUUID& folder_id = cats->at(i)->getUUID(); - if (rv.isNull() || folder_id < rv) - { - rv = folder_id; - } - } - } - } - } - - if(rv.isNull() + LLUUID rv = LLUUID::null; + if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) + { + rv = root_id; + } + else if (root_id.notNull()) + { + cat_array_t* cats = NULL; + cats = get_ptr_in_map(mParentChildCategoryTree, root_id); + if(cats) + { + S32 count = cats->size(); + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* p_cat = cats->at(i); + if(p_cat && p_cat->getPreferredType() == preferred_type) + { + const LLUUID& folder_id = cats->at(i)->getUUID(); + if (rv.isNull() || folder_id < rv) + { + rv = folder_id; + } + } + } + } + } + + if(rv.isNull() && root_id.notNull() && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS && preferred_type != LLFolderType::FT_OUTBOX) - { + { // if it does not exists, it should either be added // to createCommonSystemCategories or server should // have set it llassert(!isInventoryUsable()); LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type - << " but category does not exist" << LL_ENDL; - } - return rv; + << " but category does not exist" << LL_ENDL; + } + return rv; } // findCategoryUUIDForType() returns the uuid of the category that @@ -932,7 +932,7 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( // inventory category on the fly if one does not exist. const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); } const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const @@ -968,7 +968,7 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: default: break; } - + if (cat_id.isNull() || !getCategory(cat_id)) { cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID()); @@ -978,7 +978,7 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); } // Convenience function to create a new category. You could call @@ -986,56 +986,56 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp // version will take care of details like what the name should be // based on preferred type. void LLInventoryModel::createNewCategory(const LLUUID& parent_id, - LLFolderType::EType preferred_type, - const std::string& pname, - inventory_func_type callback, - const LLUUID& thumbnail_id) + LLFolderType::EType preferred_type, + const std::string& pname, + inventory_func_type callback, + const LLUUID& thumbnail_id) { - LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; - if (!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " - << preferred_type << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; + if (!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " + << preferred_type << LL_ENDL; if (callback) { callback(LLUUID::null); } - return; - } + return; + } - if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) - { - LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; + if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) + { + LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; if (callback) { callback(LLUUID::null); } - return; - } - - if (preferred_type != LLFolderType::FT_NONE) - { - // Ultimately this should only be done for non-singleton - // types. Requires back-end changes to guarantee that others - // already exist. - LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; - } - - std::string name = pname; - if (pname.empty()) - { - name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); - } - - if (AISAPI::isAvailable()) - { - LLSD new_inventory = LLSD::emptyMap(); - new_inventory["categories"] = LLSD::emptyArray(); - LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); + return; + } + + if (preferred_type != LLFolderType::FT_NONE) + { + // Ultimately this should only be done for non-singleton + // types. Requires back-end changes to guarantee that others + // already exist. + LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; + } + + std::string name = pname; + if (pname.empty()) + { + name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); + } + + if (AISAPI::isAvailable()) + { + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["categories"] = LLSD::emptyArray(); + LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); cat.setThumbnailUUID(thumbnail_id); - LLSD cat_sd = cat.asAISCreateCatLLSD(); - new_inventory["categories"].append(cat_sd); - AISAPI::CreateInventory( + LLSD cat_sd = cat.asAISCreateCatLLSD(); + new_inventory["categories"].append(cat_sd); + AISAPI::CreateInventory( parent_id, new_inventory, [this, callback, parent_id, preferred_type, name] (const LLUUID& new_category) @@ -1075,32 +1075,32 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, } }); return; - } - - LLViewerRegion* viewer_region = gAgent.getRegion(); - std::string url; - if ( viewer_region ) - url = viewer_region->getCapability("CreateInventoryCategory"); - - if (!url.empty()) - { - //Let's use the new capability. + } + + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty()) + { + //Let's use the new capability. LLUUID id; - id.generate(); - LLSD request, body; - body["folder_id"] = id; - body["parent_id"] = parent_id; - body["type"] = (LLSD::Integer) preferred_type; - body["name"] = name; - - request["message"] = "CreateInventoryCategory"; - request["payload"] = body; - - LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; + id.generate(); + LLSD request, body; + body["folder_id"] = id; + body["parent_id"] = parent_id; + body["type"] = (LLSD::Integer) preferred_type; + body["name"] = name; + + request["message"] = "CreateInventoryCategory"; + request["payload"] = body; + + LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); return; - } + } if (callback) { @@ -1115,7 +1115,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("createNewCategoryCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - + httpOpts->setWantHeaders(true); @@ -1213,36 +1213,36 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv // category has any immediate children meeting a condition, without // needing to recurse or build up any lists. bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, - LLInventoryCollectFunctor& filter) + LLInventoryCollectFunctor& filter) { - LLInventoryModel::cat_array_t *cats; - LLInventoryModel::item_array_t *items; - getDirectDescendentsOf(cat_id, cats, items); - if (cats) - { - for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); - it != cats->end(); ++it) - { - if (filter(*it,NULL)) - { - return true; - } - } - } - if (items) - { - for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); - it != items->end(); ++it) - { - if (filter(NULL,*it)) - { - return true; - } - } - } - return false; + LLInventoryModel::cat_array_t *cats; + LLInventoryModel::item_array_t *items; + getDirectDescendentsOf(cat_id, cats, items); + if (cats) + { + for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); + it != cats->end(); ++it) + { + if (filter(*it,NULL)) + { + return true; + } + } + } + if (items) + { + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); + it != items->end(); ++it) + { + if (filter(NULL,*it)) + { + return true; + } + } + } + return false; } - + // Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified by // id. There is no guaranteed order. Neither array will be erased @@ -1253,135 +1253,135 @@ bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, class LLAlwaysCollect : public LLInventoryCollectFunctor { public: - virtual ~LLAlwaysCollect() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - return TRUE; - } + virtual ~LLAlwaysCollect() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + return TRUE; + } }; void LLInventoryModel::collectDescendents(const LLUUID& id, - cat_array_t& cats, - item_array_t& items, - BOOL include_trash) + cat_array_t& cats, + item_array_t& items, + BOOL include_trash) { - LLAlwaysCollect always; - collectDescendentsIf(id, cats, items, include_trash, always); + LLAlwaysCollect always; + collectDescendentsIf(id, cats, items, include_trash, always); } void LLInventoryModel::collectDescendentsIf(const LLUUID& id, - cat_array_t& cats, - item_array_t& items, - BOOL include_trash, - LLInventoryCollectFunctor& add) + cat_array_t& cats, + item_array_t& items, + BOOL include_trash, + LLInventoryCollectFunctor& add) { - // Start with categories - if(!include_trash) - { - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(trash_id.notNull() && (trash_id == id)) - return; - } - cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); - if(cat_array) - { - S32 count = cat_array->size(); - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = cat_array->at(i); - if(add(cat,NULL)) - { - cats.push_back(cat); - } - collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); - } - } - - LLViewerInventoryItem* item = NULL; - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - - // Move onto items - if(item_array) - { - S32 count = item_array->size(); - for(S32 i = 0; i < count; ++i) - { - item = item_array->at(i); - if(add(NULL, item)) - { - items.push_back(item); - } - } - } + // Start with categories + if(!include_trash) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(trash_id.notNull() && (trash_id == id)) + return; + } + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if(cat_array) + { + S32 count = cat_array->size(); + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = cat_array->at(i); + if(add(cat,NULL)) + { + cats.push_back(cat); + } + collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); + } + } + + LLViewerInventoryItem* item = NULL; + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + // Move onto items + if(item_array) + { + S32 count = item_array->size(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->at(i); + if(add(NULL, item)) + { + items.push_back(item); + } + } + } } void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { - const LLInventoryObject *obj = getObject(object_id); - if (!obj || obj->getIsLinkType()) - return; - - LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); - for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) - { - LLViewerInventoryItem *linked_item = (*iter); - addChangedMask(mask, linked_item->getUUID()); - }; + const LLInventoryObject *obj = getObject(object_id); + if (!obj || obj->getIsLinkType()) + return; + + LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + addChangedMask(mask, linked_item->getUUID()); + }; } const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const { - const LLInventoryItem *item = gInventory.getItem(object_id); - if (!item) - { - return object_id; - } - - // Find the base item in case this a link (if it's not a link, - // this will just be inv_item_id) - return item->getLinkedUUID(); + const LLInventoryItem *item = gInventory.getItem(object_id); + if (!item) + { + return object_id; + } + + // Find the base item in case this a link (if it's not a link, + // this will just be inv_item_id) + return item->getLinkedUUID(); } LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) const { - return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; + return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; } LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id) { - // Get item list via collectDescendents (slow!) - item_array_t items; - const LLInventoryObject *obj = getObject(id); - // FIXME - should be as in next line, but this is causing a - // stack-smashing crash of cause TBD... check in the REBUILD code. - //if (obj && obj->getIsLinkType()) - if (!obj || obj->getIsLinkType()) - return items; - - std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); - for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) - { - LLViewerInventoryItem *item = getItem(it->second); - if (item) - { - items.push_back(item); - } - } - - return items; + // Get item list via collectDescendents (slow!) + item_array_t items; + const LLInventoryObject *obj = getObject(id); + // FIXME - should be as in next line, but this is causing a + // stack-smashing crash of cause TBD... check in the REBUILD code. + //if (obj && obj->getIsLinkType()) + if (!obj || obj->getIsLinkType()) + return items; + + std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) + { + LLViewerInventoryItem *item = getItem(it->second); + if (item) + { + items.push_back(item); + } + } + + return items; } bool LLInventoryModel::isInventoryUsable() const { - bool result = false; - if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) - { - result = true; - } - return result; + bool result = false; + if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) + { + result = true; + } + return result; } // Calling this method with an inventory item will either change an @@ -1389,34 +1389,34 @@ bool LLInventoryModel::isInventoryUsable() const // current inventory. U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { - if(item->getUUID().isNull()) - { - return mask; - } - - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return mask; - } - - if (item->getType() == LLAssetType::AT_MESH) - { - return mask; - } - - LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID()); - LLPointer<LLViewerInventoryItem> new_item; - if(old_item) - { - // We already have an old item, modify its values - new_item = old_item; - LLUUID old_parent_id = old_item->getParentUUID(); - LLUUID new_parent_id = item->getParentUUID(); - bool update_parent_on_server = false; - - if (new_parent_id.isNull() && !LLApp::isExiting()) - { + if(item->getUUID().isNull()) + { + return mask; + } + + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return mask; + } + + if (item->getType() == LLAssetType::AT_MESH) + { + return mask; + } + + LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID()); + LLPointer<LLViewerInventoryItem> new_item; + if(old_item) + { + // We already have an old item, modify its values + new_item = old_item; + LLUUID old_parent_id = old_item->getParentUUID(); + LLUUID new_parent_id = item->getParentUUID(); + bool update_parent_on_server = false; + + if (new_parent_id.isNull() && !LLApp::isExiting()) + { if (old_parent_id.isNull()) { // Item with null parent will end in random location and then in Lost&Found, @@ -1438,359 +1438,359 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) new_parent_id = old_parent_id; update_parent_on_server = true; } - } - - if(old_parent_id != new_parent_id) - { - // need to update the parent-child tree - item_array_t* item_array; - item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); - if(item_array) - { - vector_replace_with_last(*item_array, old_item); - } - item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); - if(item_array) - { - if (update_parent_on_server) - { - LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); - gInventory.accountForUpdate(update); - } - item_array->push_back(old_item); - } - mask |= LLInventoryObserver::STRUCTURE; - } - if(old_item->getName() != item->getName()) - { - mask |= LLInventoryObserver::LABEL; - } + } + + if(old_parent_id != new_parent_id) + { + // need to update the parent-child tree + item_array_t* item_array; + item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); + if(item_array) + { + vector_replace_with_last(*item_array, old_item); + } + item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); + if(item_array) + { + if (update_parent_on_server) + { + LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); + gInventory.accountForUpdate(update); + } + item_array->push_back(old_item); + } + mask |= LLInventoryObserver::STRUCTURE; + } + if(old_item->getName() != item->getName()) + { + mask |= LLInventoryObserver::LABEL; + } if (old_item->getPermissions() != item->getPermissions()) { mask |= LLInventoryObserver::INTERNAL; } - old_item->copyViewerItem(item); - if (update_parent_on_server) - { - // Parent id at server is null, so update server even if item already is in the same folder - old_item->setParent(new_parent_id); - new_item->updateParentOnServer(FALSE); - } - mask |= LLInventoryObserver::INTERNAL; - } - else - { - // Simply add this item - new_item = new LLViewerInventoryItem(item); - addItem(new_item); - - if(item->getParentUUID().isNull()) - { - const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType())); - new_item->setParent(category_id); - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); - if( item_array ) - { - LLInventoryModel::LLCategoryUpdate update(category_id, 1); - gInventory.accountForUpdate(update); - - // *FIX: bit of a hack to call update server from here... - new_item->updateParentOnServer(FALSE); - item_array->push_back(new_item); - } - else - { - LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; - } - } - else - { - // *NOTE: The general scheme is that if every byte of the - // uuid is 0, except for the last one or two,the use the - // last two bytes of the parent id, and match that up - // against the type. For now, we're only worried about - // lost & found. - LLUUID parent_id = item->getParentUUID(); - if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID) - { - parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - new_item->setParent(parent_id); - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - } - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); - if(item_array) - { - item_array->push_back(new_item); - } - else - { - // Whoops! No such parent, make one. - LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " - << new_item->getName() << LL_ENDL; - parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - new_item->setParent(parent_id); - item_array = get_ptr_in_map(mParentChildItemTree, parent_id); - if(item_array) - { - LLInventoryModel::LLCategoryUpdate update(parent_id, 1); - gInventory.accountForUpdate(update); - // *FIX: bit of a hack to call update server from - // here... - new_item->updateParentOnServer(FALSE); - item_array->push_back(new_item); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - } - mask |= LLInventoryObserver::ADD; - } - if(new_item->getType() == LLAssetType::AT_CALLINGCARD) - { - mask |= LLInventoryObserver::CALLING_CARD; - // Handle user created calling cards. - // Target ID is stored in the description field of the card. - LLUUID id; - std::string desc = new_item->getDescription(); - BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); - if (isId) - { - // Valid UUID; set the item UUID and rename it - new_item->setCreator(id); - LLAvatarName av_name; - - if (LLAvatarNameCache::get(id, &av_name)) - { - new_item->rename(av_name.getUserName()); - mask |= LLInventoryObserver::LABEL; - } - else - { - // Fetch the current name - LLAvatarNameCache::get(id, - boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), - _1, _2)); - } - - } - } - else if (new_item->getType() == LLAssetType::AT_GESTURE) - { - mask |= LLInventoryObserver::GESTURE; - } - addChangedMask(mask, new_item->getUUID()); - return mask; + old_item->copyViewerItem(item); + if (update_parent_on_server) + { + // Parent id at server is null, so update server even if item already is in the same folder + old_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + } + mask |= LLInventoryObserver::INTERNAL; + } + else + { + // Simply add this item + new_item = new LLViewerInventoryItem(item); + addItem(new_item); + + if(item->getParentUUID().isNull()) + { + const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType())); + new_item->setParent(category_id); + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); + if( item_array ) + { + LLInventoryModel::LLCategoryUpdate update(category_id, 1); + gInventory.accountForUpdate(update); + + // *FIX: bit of a hack to call update server from here... + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); + } + else + { + LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; + } + } + else + { + // *NOTE: The general scheme is that if every byte of the + // uuid is 0, except for the last one or two,the use the + // last two bytes of the parent id, and match that up + // against the type. For now, we're only worried about + // lost & found. + LLUUID parent_id = item->getParentUUID(); + if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID) + { + parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + new_item->setParent(parent_id); + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + } + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); + if(item_array) + { + item_array->push_back(new_item); + } + else + { + // Whoops! No such parent, make one. + LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " + << new_item->getName() << LL_ENDL; + parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + new_item->setParent(parent_id); + item_array = get_ptr_in_map(mParentChildItemTree, parent_id); + if(item_array) + { + LLInventoryModel::LLCategoryUpdate update(parent_id, 1); + gInventory.accountForUpdate(update); + // *FIX: bit of a hack to call update server from + // here... + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + } + mask |= LLInventoryObserver::ADD; + } + if(new_item->getType() == LLAssetType::AT_CALLINGCARD) + { + mask |= LLInventoryObserver::CALLING_CARD; + // Handle user created calling cards. + // Target ID is stored in the description field of the card. + LLUUID id; + std::string desc = new_item->getDescription(); + BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); + if (isId) + { + // Valid UUID; set the item UUID and rename it + new_item->setCreator(id); + LLAvatarName av_name; + + if (LLAvatarNameCache::get(id, &av_name)) + { + new_item->rename(av_name.getUserName()); + mask |= LLInventoryObserver::LABEL; + } + else + { + // Fetch the current name + LLAvatarNameCache::get(id, + boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), + _1, _2)); + } + + } + } + else if (new_item->getType() == LLAssetType::AT_GESTURE) + { + mask |= LLInventoryObserver::GESTURE; + } + addChangedMask(mask, new_item->getUUID()); + return mask; } LLInventoryModel::cat_array_t* LLInventoryModel::getUnlockedCatArray(const LLUUID& id) { - cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); - if (cat_array) - { - llassert_always(mCategoryLock[id] == false); - } - return cat_array; + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if (cat_array) + { + llassert_always(mCategoryLock[id] == false); + } + return cat_array; } LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLUUID& id) { - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - if (item_array) - { - llassert_always(mItemLock[id] == false); - } - return item_array; + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + if (item_array) + { + llassert_always(mItemLock[id] == false); + } + return item_array; } // Calling this method with an inventory category will either change // an existing item with the matching id, or it will add the category. void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask) { - if(!cat || cat->getUUID().isNull()) - { - return; - } - - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return; - } - - LLPointer<LLViewerInventoryCategory> old_cat = getCategory(cat->getUUID()); - if(old_cat) - { - // We already have an old category, modify its values - LLUUID old_parent_id = old_cat->getParentUUID(); - LLUUID new_parent_id = cat->getParentUUID(); - if(old_parent_id != new_parent_id) - { - // need to update the parent-child tree - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(old_parent_id); - if(cat_array) - { - vector_replace_with_last(*cat_array, old_cat); - } - cat_array = getUnlockedCatArray(new_parent_id); - if(cat_array) - { - cat_array->push_back(old_cat); - } - mask |= LLInventoryObserver::STRUCTURE; + if(!cat || cat->getUUID().isNull()) + { + return; + } + + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return; + } + + LLPointer<LLViewerInventoryCategory> old_cat = getCategory(cat->getUUID()); + if(old_cat) + { + // We already have an old category, modify its values + LLUUID old_parent_id = old_cat->getParentUUID(); + LLUUID new_parent_id = cat->getParentUUID(); + if(old_parent_id != new_parent_id) + { + // need to update the parent-child tree + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(old_parent_id); + if(cat_array) + { + vector_replace_with_last(*cat_array, old_cat); + } + cat_array = getUnlockedCatArray(new_parent_id); + if(cat_array) + { + cat_array->push_back(old_cat); + } + mask |= LLInventoryObserver::STRUCTURE; mask |= LLInventoryObserver::INTERNAL; - } - if(old_cat->getName() != cat->getName()) - { - mask |= LLInventoryObserver::LABEL; - } + } + if(old_cat->getName() != cat->getName()) + { + mask |= LLInventoryObserver::LABEL; + } // Under marketplace, category labels are quite complex and need extra upate const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) { - mask |= LLInventoryObserver::LABEL; + mask |= LLInventoryObserver::LABEL; } old_cat->copyViewerCategory(cat); - addChangedMask(mask, cat->getUUID()); - } - else - { - // add this category - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat->getOwnerID()); - new_cat->copyViewerCategory(cat); - addCategory(new_cat); - - // make sure this category is correctly referenced by its parent. - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) - { - cat_array->push_back(new_cat); - } - - // make space in the tree for this category's children. - llassert_always(mCategoryLock[new_cat->getUUID()] == false); - llassert_always(mItemLock[new_cat->getUUID()] == false); - cat_array_t* catsp = new cat_array_t; - item_array_t* itemsp = new item_array_t; - mParentChildCategoryTree[new_cat->getUUID()] = catsp; - mParentChildItemTree[new_cat->getUUID()] = itemsp; - mask |= LLInventoryObserver::ADD; - addChangedMask(mask, cat->getUUID()); - } + addChangedMask(mask, cat->getUUID()); + } + else + { + // add this category + LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat->getOwnerID()); + new_cat->copyViewerCategory(cat); + addCategory(new_cat); + + // make sure this category is correctly referenced by its parent. + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) + { + cat_array->push_back(new_cat); + } + + // make space in the tree for this category's children. + llassert_always(mCategoryLock[new_cat->getUUID()] == false); + llassert_always(mItemLock[new_cat->getUUID()] == false); + cat_array_t* catsp = new cat_array_t; + item_array_t* itemsp = new item_array_t; + mParentChildCategoryTree[new_cat->getUUID()] = catsp; + mParentChildItemTree[new_cat->getUUID()] = itemsp; + mask |= LLInventoryObserver::ADD; + addChangedMask(mask, cat->getUUID()); + } } void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) { - LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return; - } - - if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) - { - LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " - << cat_id << LL_ENDL; - return; - } - LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); - if(cat && (cat->getParentUUID() != cat_id)) - { - LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) vector_replace_with_last(*cat_array, cat); - cat_array = getUnlockedCatArray(cat_id); - cat->setParent(cat_id); - if(cat_array) cat_array->push_back(cat); - addChangedMask(LLInventoryObserver::STRUCTURE, object_id); - return; - } - LLPointer<LLViewerInventoryItem> item = getItem(object_id); - if(item && (item->getParentUUID() != cat_id)) - { - LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; - item_array_t* item_array; - item_array = getUnlockedItemArray(item->getParentUUID()); - if(item_array) vector_replace_with_last(*item_array, item); - item_array = getUnlockedItemArray(cat_id); - item->setParent(cat_id); - if(item_array) item_array->push_back(item); - addChangedMask(LLInventoryObserver::STRUCTURE, object_id); - return; - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return; + } + + if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) + { + LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " + << cat_id << LL_ENDL; + return; + } + LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); + if(cat && (cat->getParentUUID() != cat_id)) + { + LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) vector_replace_with_last(*cat_array, cat); + cat_array = getUnlockedCatArray(cat_id); + cat->setParent(cat_id); + if(cat_array) cat_array->push_back(cat); + addChangedMask(LLInventoryObserver::STRUCTURE, object_id); + return; + } + LLPointer<LLViewerInventoryItem> item = getItem(object_id); + if(item && (item->getParentUUID() != cat_id)) + { + LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; + item_array_t* item_array; + item_array = getUnlockedItemArray(item->getParentUUID()); + if(item_array) vector_replace_with_last(*item_array, item); + item_array = getUnlockedItemArray(cat_id); + item->setParent(cat_id); + if(item_array) item_array->push_back(item); + addChangedMask(LLInventoryObserver::STRUCTURE, object_id); + return; + } } // Migrated from llinventoryfunctions void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp) + const LLUUID& new_parent_id, + BOOL restamp) { - if (item->getParentUUID() == new_parent_id) - { - LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; - } - else - { - LL_INFOS(LOG_INV) << "Move item " << make_info(item) - << " from " << make_inventory_info(item->getParentUUID()) - << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(restamp); - updateItem(new_item); - notifyObservers(); - } + if (item->getParentUUID() == new_parent_id) + { + LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; + } + else + { + LL_INFOS(LOG_INV) << "Move item " << make_info(item) + << " from " << make_inventory_info(item->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(restamp); + updateItem(new_item); + notifyObservers(); + } } // Migrated from llinventoryfunctions void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp) + const LLUUID& new_parent_id, + BOOL restamp) { - if (!cat) - { - return; - } - - // Can't move a folder into a child of itself. - if (isObjectDescendentOf(new_parent_id, cat->getUUID())) - { - return; - } - - LL_INFOS(LOG_INV) << "Move category " << make_info(cat) - << " from " << make_inventory_info(cat->getParentUUID()) - << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - updateCategory(new_cat); - notifyObservers(); + if (!cat) + { + return; + } + + // Can't move a folder into a child of itself. + if (isObjectDescendentOf(new_parent_id, cat->getUUID())) + { + return; + } + + LL_INFOS(LOG_INV) << "Move category " << make_info(cat) + << " from " << make_inventory_info(cat->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent_id); + new_cat->updateParentOnServer(restamp); + updateCategory(new_cat); + notifyObservers(); } void LLInventoryModel::rebuildBrockenLinks() @@ -1817,262 +1817,262 @@ void LLInventoryModel::rebuildBrockenLinks() // Does not appear to be used currently. void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) { - U32 mask = LLInventoryObserver::NONE; - - LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); - LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; - if(item) - { - for (LLSD::map_const_iterator it = updates.beginMap(); - it != updates.endMap(); ++it) - { - if (it->first == "name") - { - LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; - item->rename(it->second.asString()); - mask |= LLInventoryObserver::LABEL; - } - else if (it->first == "desc") - { - LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() - << " to " << it->second.asString() << LL_ENDL; - item->setDescription(it->second.asString()); - } - else - { - LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; - } - } - mask |= LLInventoryObserver::INTERNAL; - addChangedMask(mask, item->getUUID()); - if (update_parent_version) - { - // Descendent count is unchanged, but folder version incremented. - LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); - accountForUpdate(up); - } - notifyObservers(); // do we want to be able to make this optional? - } + U32 mask = LLInventoryObserver::NONE; + + LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; + if(item) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; + item->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else if (it->first == "desc") + { + LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() + << " to " << it->second.asString() << LL_ENDL; + item->setDescription(it->second.asString()); + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, item->getUUID()); + if (update_parent_version) + { + // Descendent count is unchanged, but folder version incremented. + LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); + accountForUpdate(up); + } + notifyObservers(); // do we want to be able to make this optional? + } } // Not used? void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) { - U32 mask = LLInventoryObserver::NONE; - - LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); - LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; - if(cat) - { - for (LLSD::map_const_iterator it = updates.beginMap(); - it != updates.endMap(); ++it) - { - if (it->first == "name") - { - LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; - cat->rename(it->second.asString()); - mask |= LLInventoryObserver::LABEL; - } - else - { - LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; - } - } - mask |= LLInventoryObserver::INTERNAL; - addChangedMask(mask, cat->getUUID()); - notifyObservers(); // do we want to be able to make this optional? - } + U32 mask = LLInventoryObserver::NONE; + + LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); + LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; + if(cat) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; + cat->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, cat->getUUID()); + notifyObservers(); // do we want to be able to make this optional? + } } // Update model after descendents have been purged. void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) { - LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); - if (cat.notNull()) - { - // do the cache accounting - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); - accountForUpdate(up); - } - - // we know that descendent count is 0, however since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); - - // unceremoniously remove anything we have locally stored. - LLInventoryModel::cat_array_t categories; - LLInventoryModel::item_array_t items; - collectDescendents(object_id, - categories, - items, - LLInventoryModel::INCLUDE_TRASH); - S32 count = items.size(); - - LLUUID uu_id; - for(S32 i = 0; i < count; ++i) - { - uu_id = items.at(i)->getUUID(); - - // This check prevents the deletion of a previously deleted item. - // This is necessary because deletion is not done in a hierarchical - // order. The current item may have been already deleted as a child - // of its deleted parent. - if (getItem(uu_id)) - { - deleteObject(uu_id, fix_broken_links); - } - } - - count = categories.size(); - // Slightly kludgy way to make sure categories are removed - // only after their child categories have gone away. - - // FIXME: Would probably make more sense to have this whole - // descendent-clearing thing be a post-order recursive - // function to get the leaf-up behavior automatically. - S32 deleted_count; - S32 total_deleted_count = 0; - do - { - deleted_count = 0; - for(S32 i = 0; i < count; ++i) - { - uu_id = categories.at(i)->getUUID(); - if (getCategory(uu_id)) - { - cat_array_t* cat_list = getUnlockedCatArray(uu_id); - if (!cat_list || (cat_list->size() == 0)) - { - deleteObject(uu_id, fix_broken_links); - deleted_count++; - } - } - } - total_deleted_count += deleted_count; - } - while (deleted_count > 0); - if (total_deleted_count != count) - { - LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " - << total_deleted_count << " expected " << count << LL_ENDL; - } - //gInventory.validate(); - } + LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); + if (cat.notNull()) + { + // do the cache accounting + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); + accountForUpdate(up); + } + + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // unceremoniously remove anything we have locally stored. + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + collectDescendents(object_id, + categories, + items, + LLInventoryModel::INCLUDE_TRASH); + S32 count = items.size(); + + LLUUID uu_id; + for(S32 i = 0; i < count; ++i) + { + uu_id = items.at(i)->getUUID(); + + // This check prevents the deletion of a previously deleted item. + // This is necessary because deletion is not done in a hierarchical + // order. The current item may have been already deleted as a child + // of its deleted parent. + if (getItem(uu_id)) + { + deleteObject(uu_id, fix_broken_links); + } + } + + count = categories.size(); + // Slightly kludgy way to make sure categories are removed + // only after their child categories have gone away. + + // FIXME: Would probably make more sense to have this whole + // descendent-clearing thing be a post-order recursive + // function to get the leaf-up behavior automatically. + S32 deleted_count; + S32 total_deleted_count = 0; + do + { + deleted_count = 0; + for(S32 i = 0; i < count; ++i) + { + uu_id = categories.at(i)->getUUID(); + if (getCategory(uu_id)) + { + cat_array_t* cat_list = getUnlockedCatArray(uu_id); + if (!cat_list || (cat_list->size() == 0)) + { + deleteObject(uu_id, fix_broken_links); + deleted_count++; + } + } + } + total_deleted_count += deleted_count; + } + while (deleted_count > 0); + if (total_deleted_count != count) + { + LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " + << total_deleted_count << " expected " << count << LL_ENDL; + } + //gInventory.validate(); + } } // Update model after an item is confirmed as removed from // server. Works for categories or items. void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) { - LLPointer<LLInventoryObject> obj = getObject(object_id); - if(obj) - { - if (getCategory(object_id)) - { - // For category, need to delete/update all children first. - onDescendentsPurgedFromServer(object_id, fix_broken_links); - } - - - // From item/cat removeFromServer() - if (update_parent_version) - { - LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); - accountForUpdate(up); - } - - // From purgeObject() - LLViewerInventoryItem *item = getItem(object_id); - if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) - { - LLPreview::hide(object_id, TRUE); - } - deleteObject(object_id, fix_broken_links, do_notify_observers); - } + LLPointer<LLInventoryObject> obj = getObject(object_id); + if(obj) + { + if (getCategory(object_id)) + { + // For category, need to delete/update all children first. + onDescendentsPurgedFromServer(object_id, fix_broken_links); + } + + + // From item/cat removeFromServer() + if (update_parent_version) + { + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + } + + // From purgeObject() + LLViewerInventoryItem *item = getItem(object_id); + if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) + { + LLPreview::hide(object_id, TRUE); + } + deleteObject(object_id, fix_broken_links, do_notify_observers); + } } // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers) { - LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; - LLPointer<LLInventoryObject> obj = getObject(id); - if (!obj) - { - LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; - return; - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; + LLPointer<LLInventoryObject> obj = getObject(id); + if (!obj) + { + LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; + return; + } //collect the links before removing the item from mItemMap LLInventoryModel::item_array_t links = collectLinksTo(id); - - LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; - mLastItem = NULL; - LLUUID parent_id = obj->getParentUUID(); - mCategoryMap.erase(id); - mItemMap.erase(id); - //mInventory.erase(id); - item_array_t* item_list = getUnlockedItemArray(parent_id); - if(item_list) - { - LLPointer<LLViewerInventoryItem> item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); - vector_replace_with_last(*item_list, item); - } - cat_array_t* cat_list = getUnlockedCatArray(parent_id); - if(cat_list) - { - LLPointer<LLViewerInventoryCategory> cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); - vector_replace_with_last(*cat_list, cat); - } - + + LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; + mLastItem = NULL; + LLUUID parent_id = obj->getParentUUID(); + mCategoryMap.erase(id); + mItemMap.erase(id); + //mInventory.erase(id); + item_array_t* item_list = getUnlockedItemArray(parent_id); + if(item_list) + { + LLPointer<LLViewerInventoryItem> item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); + vector_replace_with_last(*item_list, item); + } + cat_array_t* cat_list = getUnlockedCatArray(parent_id); + if(cat_list) + { + LLPointer<LLViewerInventoryCategory> cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); + vector_replace_with_last(*cat_list, cat); + } + // Note : We need to tell the inventory observers that those things are going to be deleted *before* the tree is cleared or they won't know what to delete (in views and view models) - addChangedMask(LLInventoryObserver::REMOVE, id); - gInventory.notifyObservers(); - - item_list = getUnlockedItemArray(id); - if(item_list) - { - if (item_list->size()) - { - LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; - } - delete item_list; - mParentChildItemTree.erase(id); - } - cat_list = getUnlockedCatArray(id); - if(cat_list) - { - if (cat_list->size()) - { - LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; - } - delete cat_list; - mParentChildCategoryTree.erase(id); - } - addChangedMask(LLInventoryObserver::REMOVE, id); - - bool is_link_type = obj->getIsLinkType(); - if (is_link_type) - { - removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); - } - - // Can't have links to links, so there's no need for this update - // if the item removed is a link. Can also skip if source of the - // update is getting broken link info separately. - if (fix_broken_links && !is_link_type) - { + addChangedMask(LLInventoryObserver::REMOVE, id); + gInventory.notifyObservers(); + + item_list = getUnlockedItemArray(id); + if(item_list) + { + if (item_list->size()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; + } + delete item_list; + mParentChildItemTree.erase(id); + } + cat_list = getUnlockedCatArray(id); + if(cat_list) + { + if (cat_list->size()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; + } + delete cat_list; + mParentChildCategoryTree.erase(id); + } + addChangedMask(LLInventoryObserver::REMOVE, id); + + bool is_link_type = obj->getIsLinkType(); + if (is_link_type) + { + removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); + } + + // Can't have links to links, so there's no need for this update + // if the item removed is a link. Can also skip if source of the + // update is getting broken link info separately. + if (fix_broken_links && !is_link_type) + { rebuildLinkItems(links); - } - obj = nullptr; // delete obj - if (do_notify_observers) - { - notifyObservers(); - } + } + obj = nullptr; // delete obj + if (do_notify_observers) + { + notifyObservers(); + } } void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items) @@ -2100,23 +2100,23 @@ void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items) // remove it. void LLInventoryModel::addObserver(LLInventoryObserver* observer) { - mObservers.insert(observer); + mObservers.insert(observer); } - + void LLInventoryModel::removeObserver(LLInventoryObserver* observer) { - mObservers.erase(observer); + mObservers.erase(observer); } BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const { - return mObservers.find(observer) != mObservers.end(); + return mObservers.find(observer) != mObservers.end(); } void LLInventoryModel::idleNotifyObservers() { - // *FIX: Think I want this conditional or moved elsewhere... - handleResponses(true); + // *FIX: Think I want this conditional or moved elsewhere... + handleResponses(true); if (mLinksRebuildList.size() > 0) { @@ -2131,78 +2131,78 @@ void LLInventoryModel::idleNotifyObservers() mLinksRebuildList.clear(); notifyObservers(); } - - if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) - { - return; - } - notifyObservers(); + + if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) + { + return; + } + notifyObservers(); } // Call this method when it's time to update everyone on a new state. void LLInventoryModel::notifyObservers() { - if (mIsNotifyObservers) - { - // Within notifyObservers, something called notifyObservers - // again. This type of recursion is unsafe because it causes items to be - // processed twice, and this can easily lead to infinite loops. - LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; - return; - } - - mIsNotifyObservers = TRUE; - for (observer_list_t::iterator iter = mObservers.begin(); - iter != mObservers.end(); ) - { - LLInventoryObserver* observer = *iter; - observer->changed(mModifyMask); - - // safe way to increment since changed may delete entries! (@!##%@!@&*!) - iter = mObservers.upper_bound(observer); - } - - // If there were any changes that arrived during notifyObservers, - // shedule them for next loop - mModifyMask = mModifyMaskBacklog; - mChangedItemIDs.clear(); - mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); - mAddedItemIDs.clear(); - mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); - - mModifyMaskBacklog = LLInventoryObserver::NONE; - mChangedItemIDsBacklog.clear(); - mAddedItemIDsBacklog.clear(); - - mIsNotifyObservers = FALSE; + if (mIsNotifyObservers) + { + // Within notifyObservers, something called notifyObservers + // again. This type of recursion is unsafe because it causes items to be + // processed twice, and this can easily lead to infinite loops. + LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; + return; + } + + mIsNotifyObservers = TRUE; + for (observer_list_t::iterator iter = mObservers.begin(); + iter != mObservers.end(); ) + { + LLInventoryObserver* observer = *iter; + observer->changed(mModifyMask); + + // safe way to increment since changed may delete entries! (@!##%@!@&*!) + iter = mObservers.upper_bound(observer); + } + + // If there were any changes that arrived during notifyObservers, + // shedule them for next loop + mModifyMask = mModifyMaskBacklog; + mChangedItemIDs.clear(); + mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); + mAddedItemIDs.clear(); + mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); + + mModifyMaskBacklog = LLInventoryObserver::NONE; + mChangedItemIDsBacklog.clear(); + mAddedItemIDsBacklog.clear(); + + mIsNotifyObservers = FALSE; } // store flag for change // and id of object change applies to -void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) -{ - if (mIsNotifyObservers) - { - // Something marked an item for change within a call to notifyObservers - // (which is in the process of processing the list of items marked for change). - // This means the change will have to be processed later. - // It's preferable for this not to happen, but it's not an issue unless code - // specifically wants to notifyObservers immediately (changes won't happen untill later) - LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; - LLViewerInventoryItem *item = getItem(referent); - if (item) - { - LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; - } - else - { - LLViewerInventoryCategory *cat = getCategory(referent); - if (cat) - { - LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; - } - } - } +void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) +{ + if (mIsNotifyObservers) + { + // Something marked an item for change within a call to notifyObservers + // (which is in the process of processing the list of items marked for change). + // This means the change will have to be processed later. + // It's preferable for this not to happen, but it's not an issue unless code + // specifically wants to notifyObservers immediately (changes won't happen untill later) + LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; + LLViewerInventoryItem *item = getItem(referent); + if (item) + { + LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; + } + else + { + LLViewerInventoryCategory *cat = getCategory(referent); + if (cat) + { + LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; + } + } + } if (mIsNotifyObservers) { @@ -2227,7 +2227,7 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } if (needs_update) - { + { if (mIsNotifyObservers) { mChangedItemIDsBacklog.insert(referent); @@ -2256,42 +2256,42 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) mAddedItemIDs.insert(referent); } } - - // Update all linked items. Starting with just LABEL because I'm - // not sure what else might need to be accounted for this. - if (mask & LLInventoryObserver::LABEL) - { - addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); - } - } + + // Update all linked items. Starting with just LABEL because I'm + // not sure what else might need to be accounted for this. + if (mask & LLInventoryObserver::LABEL) + { + addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); + } + } } bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const { - if(folder_id.isNull()) - { - LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; - return false; - } - LLViewerInventoryCategory* cat = getCategory(folder_id); - if(!cat) - { - LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " - << folder_id << LL_ENDL; - return false; - } - //S32 known_descendents = 0; - ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); - //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); - //if(categories) - //{ - // known_descendents += categories->size(); - //} - //if(items) - //{ - // known_descendents += items->size(); - //} - return cat->fetch(); + if(folder_id.isNull()) + { + LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; + return false; + } + LLViewerInventoryCategory* cat = getCategory(folder_id); + if(!cat) + { + LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " + << folder_id << LL_ENDL; + return false; + } + //S32 known_descendents = 0; + ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); + //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); + //if(categories) + //{ + // known_descendents += categories->size(); + //} + //if(items) + //{ + // known_descendents += items->size(); + //} + return cat->fetch(); } //static @@ -2318,138 +2318,138 @@ std::string LLInventoryModel::getInvCacheAddres(const LLUUID& owner_id) } void LLInventoryModel::cache( - const LLUUID& parent_folder_id, - const LLUUID& agent_id) + const LLUUID& parent_folder_id, + const LLUUID& agent_id) { - LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id - << LL_ENDL; - LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); - if(!root_cat) return; - cat_array_t categories; - categories.push_back(root_cat); - item_array_t items; - - LLCanCache can_cache(this); - can_cache(root_cat, NULL); - collectDescendentsIf( - parent_folder_id, - categories, - items, - INCLUDE_TRASH, - can_cache); + LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id + << LL_ENDL; + LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); + if(!root_cat) return; + cat_array_t categories; + categories.push_back(root_cat); + item_array_t items; + + LLCanCache can_cache(this); + can_cache(root_cat, NULL); + collectDescendentsIf( + parent_folder_id, + categories, + items, + INCLUDE_TRASH, + can_cache); // Use temporary file to avoid potential conflicts with other // instances (even a 'read only' instance unzips into a file) std::string temp_file = gDirUtilp->getTempFilename(); - saveToFile(temp_file, categories, items); + saveToFile(temp_file, categories, items); std::string gzip_filename = getInvCacheAddres(agent_id); - gzip_filename.append(".gz"); - if(gzip_file(temp_file, gzip_filename)) - { - LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; - LLFile::remove(temp_file); - } - else - { - LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; - } + gzip_filename.append(".gz"); + if(gzip_file(temp_file, gzip_filename)) + { + LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; + LLFile::remove(temp_file); + } + else + { + LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; + } } void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) { - //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; - if(category) - { - // We aren't displaying the Meshes folder - if (category->mPreferredType == LLFolderType::FT_MESH) - { - return; - } - - // try to localize default names first. See EXT-8319, EXT-7051. - category->localizeName(); - - // Insert category uniquely into the map - mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one - //mInventory[category->getUUID()] = category; - } + //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; + if(category) + { + // We aren't displaying the Meshes folder + if (category->mPreferredType == LLFolderType::FT_MESH) + { + return; + } + + // try to localize default names first. See EXT-8319, EXT-7051. + category->localizeName(); + + // Insert category uniquely into the map + mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one + //mInventory[category->getUUID()] = category; + } } bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const { - std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; - range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - if (it->second == link_id) - { - return true; - } - } - return false; + std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + if (it->second == link_id) + { + return true; + } + } + return false; } void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - if (!hasBacklinkInfo(link_id, target_id)) - { - mBacklinkMMap.insert(std::make_pair(target_id, link_id)); - } + if (!hasBacklinkInfo(link_id, target_id)) + { + mBacklinkMMap.insert(std::make_pair(target_id, link_id)); + } } void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; - range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::iterator it = range.first; it != range.second; ) - { - if (it->second == link_id) - { - backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. - ++it; - mBacklinkMMap.erase(delete_it); - } - else - { - ++it; - } - } + std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ) + { + if (it->second == link_id) + { + backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. + ++it; + mBacklinkMMap.erase(delete_it); + } + else + { + ++it; + } + } } void LLInventoryModel::addItem(LLViewerInventoryItem* item) { - llassert(item); - if(item) - { - if (item->getType() <= LLAssetType::AT_NONE) - { - LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; - return; - } - - if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) - { - if (item->getType() >= LLAssetType::AT_COUNT) - { - // Not yet supported. - LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; - } - else - { - LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; - } - } - - // This condition means that we tried to add a link without the baseobj being in memory. - // The item will show up as a broken link. - if (item->getIsBrokenLink()) - { + llassert(item); + if(item) + { + if (item->getType() <= LLAssetType::AT_NONE) + { + LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; + return; + } + + if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) + { + if (item->getType() >= LLAssetType::AT_COUNT) + { + // Not yet supported. + LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + } + + // This condition means that we tried to add a link without the baseobj being in memory. + // The item will show up as a broken link. + if (item->getIsBrokenLink()) + { if (item->getAssetUUID().notNull() && LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive()) { @@ -2485,7 +2485,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; } - } + } if (!mPossiblyBrockenLinks.empty()) { // check if we are waiting for this item @@ -2496,705 +2496,705 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) mPossiblyBrockenLinks.erase(iter); } } - if (item->getIsLinkType()) - { - // Add back-link from linked-to UUID. - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - addBacklinkInfo(link_id, target_id); - } - mItemMap[item->getUUID()] = item; - } + if (item->getIsLinkType()) + { + // Add back-link from linked-to UUID. + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + addBacklinkInfo(link_id, target_id); + } + mItemMap[item->getUUID()] = item; + } } // Empty the entire contents void LLInventoryModel::empty() { -// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; - std::for_each( - mParentChildCategoryTree.begin(), - mParentChildCategoryTree.end(), - DeletePairedPointer()); - mParentChildCategoryTree.clear(); - std::for_each( - mParentChildItemTree.begin(), - mParentChildItemTree.end(), - DeletePairedPointer()); - mParentChildItemTree.clear(); - mBacklinkMMap.clear(); // forget all backlink information. - mCategoryMap.clear(); // remove all references (should delete entries) - mItemMap.clear(); // remove all references (should delete entries) - mLastItem = NULL; - //mInventory.clear(); +// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; + std::for_each( + mParentChildCategoryTree.begin(), + mParentChildCategoryTree.end(), + DeletePairedPointer()); + mParentChildCategoryTree.clear(); + std::for_each( + mParentChildItemTree.begin(), + mParentChildItemTree.end(), + DeletePairedPointer()); + mParentChildItemTree.clear(); + mBacklinkMMap.clear(); // forget all backlink information. + mCategoryMap.clear(); // remove all references (should delete entries) + mItemMap.clear(); // remove all references (should delete entries) + mLastItem = NULL; + //mInventory.clear(); } void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const { - LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); - if(cat) - { - S32 version = cat->getVersion(); - if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = cat->getDescendentCount(); - S32 descendents_actual = cat->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - descendents_actual += update.mDescendentDelta; - cat->setDescendentCount(descendents_actual); - cat->setVersion(++version); - LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " - << version << " with " << descendents_actual - << " descendents." << LL_ENDL; - } - else - { - // Error condition, this means that the category did not register that - // it got new descendents (perhaps because it is still being loaded) - // which means its descendent count will be wrong. - LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" - << version << " due to mismatched descendent count: server == " - << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; - } - } - else - { - LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" - << version << ")" << LL_ENDL; - } - } - else - { - LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; - } + LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); + if(cat) + { + S32 version = cat->getVersion(); + if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + descendents_actual += update.mDescendentDelta; + cat->setDescendentCount(descendents_actual); + cat->setVersion(++version); + LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " + << version << " with " << descendents_actual + << " descendents." << LL_ENDL; + } + else + { + // Error condition, this means that the category did not register that + // it got new descendents (perhaps because it is still being loaded) + // which means its descendent count will be wrong. + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" + << version << " due to mismatched descendent count: server == " + << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; + } + } + else + { + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" + << version << ")" << LL_ENDL; + } + } + else + { + LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; + } } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_list_t& update) + const LLInventoryModel::update_list_t& update) { - update_list_t::const_iterator it = update.begin(); - update_list_t::const_iterator end = update.end(); - for(; it != end; ++it) - { - accountForUpdate(*it); - } + update_list_t::const_iterator it = update.begin(); + update_list_t::const_iterator end = update.end(); + for(; it != end; ++it) + { + accountForUpdate(*it); + } } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_map_t& update) + const LLInventoryModel::update_map_t& update) { - LLCategoryUpdate up; - update_map_t::const_iterator it = update.begin(); - update_map_t::const_iterator end = update.end(); - for(; it != end; ++it) - { - up.mCategoryID = (*it).first; - up.mDescendentDelta = (*it).second.mValue; - accountForUpdate(up); - } + LLCategoryUpdate up; + update_map_t::const_iterator it = update.begin(); + update_map_t::const_iterator end = update.end(); + for(; it != end; ++it) + { + up.mCategoryID = (*it).first; + up.mDescendentDelta = (*it).second.mValue; + accountForUpdate(up); + } } LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( - const LLUUID& cat_id) const + const LLUUID& cat_id) const { - LLViewerInventoryCategory* cat = getCategory(cat_id); - if(!cat) return CHILDREN_NO; - if(cat->getDescendentCount() > 0) - { - return CHILDREN_YES; - } - if(cat->getDescendentCount() == 0) - { - return CHILDREN_NO; - } - if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) - || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) - { - return CHILDREN_MAYBE; - } - - // Shouldn't have to run this, but who knows. - parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) - { - return CHILDREN_YES; - } - parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); - if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) - { - return CHILDREN_YES; - } - - return CHILDREN_NO; + LLViewerInventoryCategory* cat = getCategory(cat_id); + if(!cat) return CHILDREN_NO; + if(cat->getDescendentCount() > 0) + { + return CHILDREN_YES; + } + if(cat->getDescendentCount() == 0) + { + return CHILDREN_NO; + } + if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + return CHILDREN_MAYBE; + } + + // Shouldn't have to run this, but who knows. + parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); + if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) + { + return CHILDREN_YES; + } + parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); + if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) + { + return CHILDREN_YES; + } + + return CHILDREN_NO; } bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const { - LLViewerInventoryCategory* cat = getCategory(cat_id); - if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) - { - S32 descendents_server = cat->getDescendentCount(); - S32 descendents_actual = cat->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - return true; - } - } - return false; -} - + LLViewerInventoryCategory* cat = getCategory(cat_id); + if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + return true; + } + } + return false; +} + bool LLInventoryModel::loadSkeleton( - const LLSD& options, - const LLUUID& owner_id) + const LLSD& options, + const LLUUID& owner_id) { LL_PROFILE_ZONE_SCOPED; - LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; - - typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t; - cat_set_t temp_cats; - bool rv = true; - - for(LLSD::array_const_iterator it = options.beginArray(), - end = options.endArray(); it != end; ++it) - { - LLSD name = (*it)["name"]; - LLSD folder_id = (*it)["folder_id"]; - LLSD parent_id = (*it)["parent_id"]; - LLSD version = (*it)["version"]; - if(name.isDefined() - && folder_id.isDefined() - && parent_id.isDefined() - && version.isDefined() - && folder_id.asUUID().notNull() // if an id is null, it locks the viewer. - ) - { - LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id); - cat->rename(name.asString()); - cat->setUUID(folder_id.asUUID()); - cat->setParent(parent_id.asUUID()); - - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLSD type_default = (*it)["type_default"]; - if(type_default.isDefined()) + LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; + + typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t; + cat_set_t temp_cats; + bool rv = true; + + for(LLSD::array_const_iterator it = options.beginArray(), + end = options.endArray(); it != end; ++it) + { + LLSD name = (*it)["name"]; + LLSD folder_id = (*it)["folder_id"]; + LLSD parent_id = (*it)["parent_id"]; + LLSD version = (*it)["version"]; + if(name.isDefined() + && folder_id.isDefined() + && parent_id.isDefined() + && version.isDefined() + && folder_id.asUUID().notNull() // if an id is null, it locks the viewer. + ) + { + LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id); + cat->rename(name.asString()); + cat->setUUID(folder_id.asUUID()); + cat->setParent(parent_id.asUUID()); + + LLFolderType::EType preferred_type = LLFolderType::FT_NONE; + LLSD type_default = (*it)["type_default"]; + if(type_default.isDefined()) { - preferred_type = (LLFolderType::EType)type_default.asInteger(); + preferred_type = (LLFolderType::EType)type_default.asInteger(); } cat->setPreferredType(preferred_type); - cat->setVersion(version.asInteger()); + cat->setVersion(version.asInteger()); temp_cats.insert(cat); - } - else - { - LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; rv = false; - } - } - - S32 cached_category_count = 0; - S32 cached_item_count = 0; - if(!temp_cats.empty()) - { - update_map_t child_counts; - cat_array_t categories; - item_array_t items; - changed_items_t categories_to_update; - item_array_t possible_broken_links; - cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. - std::string inventory_filename = getInvCacheAddres(owner_id); - const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; - std::string gzip_filename(inventory_filename); - gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); - bool remove_inventory_file = false; - if(fp) - { - fclose(fp); - fp = NULL; - if(gunzip_file(gzip_filename, inventory_filename)) - { - // we only want to remove the inventory file if it was - // gzipped before we loaded, and we successfully - // gunziped it. - remove_inventory_file = true; - } - else - { - LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; - } - } - bool is_cache_obsolete = false; - if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) - { - // We were able to find a cache of files. So, use what we - // found to generate a set of categories we should add. We - // will go through each category loaded and if the version - // does not match, invalidate the version. - S32 count = categories.size(); - cat_set_t::iterator not_cached = temp_cats.end(); - std::set<LLUUID> cached_ids; - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = categories[i]; - cat_set_t::iterator cit = temp_cats.find(cat); - if (cit == temp_cats.end()) - { - continue; // cache corruption?? not sure why this happens -SJB - } - LLViewerInventoryCategory* tcat = *cit; - - if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) - { - tcat->setVersion(NO_VERSION); - LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; - } - - // we can safely ignore anything loaded from file, but - // not sent down in the skeleton. Must have been removed from inventory. - if (cit == not_cached) - { - continue; - } - else if (cat->getVersion() != tcat->getVersion()) - { - // if the cached version does not match the server version, - // throw away the version we have so we can fetch the - // correct contents the next time the viewer opens the folder. - tcat->setVersion(NO_VERSION); - } - else - { - cached_ids.insert(tcat->getUUID()); + } + } + + S32 cached_category_count = 0; + S32 cached_item_count = 0; + if(!temp_cats.empty()) + { + update_map_t child_counts; + cat_array_t categories; + item_array_t items; + changed_items_t categories_to_update; + item_array_t possible_broken_links; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. + std::string inventory_filename = getInvCacheAddres(owner_id); + const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; + std::string gzip_filename(inventory_filename); + gzip_filename.append(".gz"); + LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); + bool remove_inventory_file = false; + if(fp) + { + fclose(fp); + fp = NULL; + if(gunzip_file(gzip_filename, inventory_filename)) + { + // we only want to remove the inventory file if it was + // gzipped before we loaded, and we successfully + // gunziped it. + remove_inventory_file = true; + } + else + { + LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; + } + } + bool is_cache_obsolete = false; + if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) + { + // We were able to find a cache of files. So, use what we + // found to generate a set of categories we should add. We + // will go through each category loaded and if the version + // does not match, invalidate the version. + S32 count = categories.size(); + cat_set_t::iterator not_cached = temp_cats.end(); + std::set<LLUUID> cached_ids; + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories[i]; + cat_set_t::iterator cit = temp_cats.find(cat); + if (cit == temp_cats.end()) + { + continue; // cache corruption?? not sure why this happens -SJB + } + LLViewerInventoryCategory* tcat = *cit; + + if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) + { + tcat->setVersion(NO_VERSION); + LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; + } + + // we can safely ignore anything loaded from file, but + // not sent down in the skeleton. Must have been removed from inventory. + if (cit == not_cached) + { + continue; + } + else if (cat->getVersion() != tcat->getVersion()) + { + // if the cached version does not match the server version, + // throw away the version we have so we can fetch the + // correct contents the next time the viewer opens the folder. + tcat->setVersion(NO_VERSION); + } + else + { + cached_ids.insert(tcat->getUUID()); // At the moment download does not provide a thumbnail // uuid, use the one from cache tcat->setThumbnailUUID(cat->getThumbnailUUID()); - } - } - - // go ahead and add the cats returned during the download - std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end(); - cached_category_count = cached_ids.size(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - if(cached_ids.find((*it)->getUUID()) == not_cached_id) - { - // this check is performed so that we do not - // mark new folders in the skeleton (and not in cache) - // as being cached. - LLViewerInventoryCategory *llvic = (*it); - llvic->setVersion(NO_VERSION); - } - addCategory(*it); - ++child_counts[(*it)->getParentUUID()]; - } - - // Add all the items loaded which are parented to a - // category with a correctly cached parent - S32 bad_link_count = 0; - S32 good_link_count = 0; - S32 recovered_link_count = 0; - cat_map_t::iterator unparented = mCategoryMap.end(); - for(item_array_t::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) - { - LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - - if(cit != unparented) - { - const LLViewerInventoryCategory* cat = cit->second.get(); - if(cat->getVersion() != NO_VERSION) - { - // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. - if (item->getIsBrokenLink()) - { - //bad_link_count++; - LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " - << item->getName() << " itemID: " << item->getUUID() - << " assetID: " << item->getAssetUUID() - << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; - possible_broken_links.push_back(item); - continue; - } - else if (item->getIsLinkType()) - { - good_link_count++; - } - addItem(item); - cached_item_count += 1; - ++child_counts[cat->getUUID()]; - } - } - } - if (possible_broken_links.size() > 0) - { - for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); - item_iter != possible_broken_links.end(); - ++item_iter) - { - LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - const LLViewerInventoryCategory* cat = cit->second.get(); - if (item->getIsBrokenLink()) - { - bad_link_count++; - invalid_categories.insert(cit->second); - //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; - } - else - { - // was marked as broken because of loading order, its actually fine to load - addItem(item); - cached_item_count += 1; - ++child_counts[cat->getUUID()]; - recovered_link_count++; - } - } - - LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << good_link_count << " link items were successfully added. " - << recovered_link_count << " links added in recovery. " - << "The corresponding categories were invalidated." << LL_ENDL; - } - - } - else - { - // go ahead and add everything after stripping the version - // information. - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - LLViewerInventoryCategory *llvic = (*it); - llvic->setVersion(NO_VERSION); - addCategory(*it); - } - } - - // Invalidate all categories that failed fetching descendents for whatever - // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) - { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); - cat->setVersion(NO_VERSION); - LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; - } - if (invalid_categories.size() > 0) - { - LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; - } - - // At this point, we need to set the known descendents for each - // category which successfully cached so that we do not - // needlessly fetch descendents for categories which we have. - update_map_t::const_iterator no_child_counts = child_counts.end(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - LLViewerInventoryCategory* cat = (*it).get(); - if(cat->getVersion() != NO_VERSION) - { - update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); - if(the_count != no_child_counts) - { - const S32 num_descendents = (*the_count).second.mValue; - cat->setDescendentCount(num_descendents); - } - else - { - cat->setDescendentCount(0); - } - } - } - - if(remove_inventory_file) - { - // clean up the gunzipped file. - LLFile::remove(inventory_filename); - } - if(is_cache_obsolete) - { - // If out of date, remove the gzipped file too. - LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; - LLFile::remove(gzip_filename); - } - categories.clear(); // will unref and delete entries - } - - LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count - << " categories and " << cached_item_count << " items from cache." - << LL_ENDL; - - return rv; + } + } + + // go ahead and add the cats returned during the download + std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end(); + cached_category_count = cached_ids.size(); + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + if(cached_ids.find((*it)->getUUID()) == not_cached_id) + { + // this check is performed so that we do not + // mark new folders in the skeleton (and not in cache) + // as being cached. + LLViewerInventoryCategory *llvic = (*it); + llvic->setVersion(NO_VERSION); + } + addCategory(*it); + ++child_counts[(*it)->getParentUUID()]; + } + + // Add all the items loaded which are parented to a + // category with a correctly cached parent + S32 bad_link_count = 0; + S32 good_link_count = 0; + S32 recovered_link_count = 0; + cat_map_t::iterator unparented = mCategoryMap.end(); + for(item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + + if(cit != unparented) + { + const LLViewerInventoryCategory* cat = cit->second.get(); + if(cat->getVersion() != NO_VERSION) + { + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. + if (item->getIsBrokenLink()) + { + //bad_link_count++; + LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " + << item->getName() << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; + possible_broken_links.push_back(item); + continue; + } + else if (item->getIsLinkType()) + { + good_link_count++; + } + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + } + } + } + if (possible_broken_links.size() > 0) + { + for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); + item_iter != possible_broken_links.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const LLViewerInventoryCategory* cat = cit->second.get(); + if (item->getIsBrokenLink()) + { + bad_link_count++; + invalid_categories.insert(cit->second); + //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; + } + else + { + // was marked as broken because of loading order, its actually fine to load + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + recovered_link_count++; + } + } + + LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << LL_ENDL; + } + + } + else + { + // go ahead and add everything after stripping the version + // information. + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + LLViewerInventoryCategory *llvic = (*it); + llvic->setVersion(NO_VERSION); + addCategory(*it); + } + } + + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; + } + if (invalid_categories.size() > 0) + { + LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + } + + // At this point, we need to set the known descendents for each + // category which successfully cached so that we do not + // needlessly fetch descendents for categories which we have. + update_map_t::const_iterator no_child_counts = child_counts.end(); + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + LLViewerInventoryCategory* cat = (*it).get(); + if(cat->getVersion() != NO_VERSION) + { + update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); + if(the_count != no_child_counts) + { + const S32 num_descendents = (*the_count).second.mValue; + cat->setDescendentCount(num_descendents); + } + else + { + cat->setDescendentCount(0); + } + } + } + + if(remove_inventory_file) + { + // clean up the gunzipped file. + LLFile::remove(inventory_filename); + } + if(is_cache_obsolete) + { + // If out of date, remove the gzipped file too. + LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; + LLFile::remove(gzip_filename); + } + categories.clear(); // will unref and delete entries + } + + LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count + << " categories and " << cached_item_count << " items from cache." + << LL_ENDL; + + return rv; } // This is a brute force method to rebuild the entire parent-child // relations. The overall operation has O(NlogN) performance, which -// should be sufficient for our needs. +// should be sufficient for our needs. void LLInventoryModel::buildParentChildMap() { - LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; - - // *NOTE: I am skipping the logic around folder version - // synchronization here because it seems if a folder is lost, we - // might actually want to invalidate it at that point - not - // attempt to cache. More time & thought is necessary. - - // First the categories. We'll copy all of the categories into a - // temporary container to iterate over (oh for real iterators.) - // While we're at it, we'll allocate the arrays in the trees. - cat_array_t cats; - cat_array_t* catsp; - item_array_t* itemsp; - - for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - LLViewerInventoryCategory* cat = cit->second; - cats.push_back(cat); - if (mParentChildCategoryTree.count(cat->getUUID()) == 0) - { - llassert_always(mCategoryLock[cat->getUUID()] == false); - catsp = new cat_array_t; - mParentChildCategoryTree[cat->getUUID()] = catsp; - } - if (mParentChildItemTree.count(cat->getUUID()) == 0) - { - llassert_always(mItemLock[cat->getUUID()] == false); - itemsp = new item_array_t; - mParentChildItemTree[cat->getUUID()] = itemsp; - } - } - - // Insert a special parent for the root - so that lookups on - // LLUUID::null as the parent work correctly. This is kind of a - // blatent wastes of space since we allocate a block of memory for - // the array, but whatever - it's not that much space. - if (mParentChildCategoryTree.count(LLUUID::null) == 0) - { - catsp = new cat_array_t; - mParentChildCategoryTree[LLUUID::null] = catsp; - } - - // Now we have a structure with all of the categories that we can - // iterate over and insert into the correct place in the child - // category tree. - S32 count = cats.size(); - S32 i; - S32 lost = 0; - cat_array_t lost_cats; - for(i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = cats.at(i); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp && - // Only the two root folders should be children of null. - // Others should go to lost & found. - (cat->getParentUUID().notNull() || - cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) - { - catsp->push_back(cat); - } - else - { - // *NOTE: This process could be a lot more efficient if we - // used the new MoveInventoryFolder message, but we would - // have to continue to do the update & build here. So, to - // implement it, we would need a set or map of uuid pairs - // which would be (folder_id, new_parent_id) to be sent up - // to the server. - LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " - << cat->getName() << LL_ENDL; - ++lost; - lost_cats.push_back(cat); - } - } - if(lost) - { - LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; - } - - // Do moves in a separate pass to make sure we've properly filed - // the FT_LOST_AND_FOUND category before we try to find its UUID. - for(i = 0; i<lost_cats.size(); ++i) - { - LLViewerInventoryCategory *cat = lost_cats.at(i); - - // plop it into the lost & found. - LLFolderType::EType pref = cat->getPreferredType(); - if(LLFolderType::FT_NONE == pref) - { - cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - } - else if(LLFolderType::FT_ROOT_INVENTORY == pref) - { - // it's the root - cat->setParent(LLUUID::null); - } - else - { - // it's a protected folder. - cat->setParent(gInventory.getRootFolderID()); - } - // FIXME note that updateServer() fails with protected - // types, so this will not work as intended in that case. - // UpdateServer uses AIS, AIS cat move is not implemented yet - // cat->updateServer(TRUE); - - // MoveInventoryFolder message, intentionally per item - cat->updateParentOnServer(FALSE); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp) - { - catsp->push_back(cat); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - - const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); - sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); - - - // Now the items. We allocated in the last step, so now all we - // have to do is iterate over the items and put them in the right - // place. - item_array_t items; - if(!mItemMap.empty()) - { - LLPointer<LLViewerInventoryItem> item; - for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - item = (*iit).second; - items.push_back(item); - } - } - count = items.size(); - lost = 0; - uuid_vec_t lost_item_ids; - for(i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryItem> item; - item = items.at(i); - itemsp = getUnlockedItemArray(item->getParentUUID()); - if(itemsp) - { - itemsp->push_back(item); - } - else - { - LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " - << item->getName() << LL_ENDL; - ++lost; - // plop it into the lost & found. - // - item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - // move it later using a special message to move items. If - // we update server here, the client might crash. - //item->updateServer(); - lost_item_ids.push_back(item->getUUID()); - itemsp = getUnlockedItemArray(item->getParentUUID()); - if(itemsp) - { - itemsp->push_back(item); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - } - if(lost) - { - LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - for(uuid_vec_t::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it) - { - if(start_new_message) - { - start_new_message = FALSE; - msg->newMessageFast(_PREHASH_MoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOLFast(_PREHASH_Stamp, FALSE); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, (*it)); - msg->addUUIDFast(_PREHASH_FolderID, lnf); - msg->addString("NewName", NULL); - if(msg->isSendFull(NULL)) - { - start_new_message = TRUE; - gAgent.sendReliableMessage(); - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - } - } - - const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); - if (agent_inv_root_id.notNull()) - { - cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); - if(catsp) - { - // *HACK - fix root inventory folder - // some accounts has pbroken inventory root folders - - std::string name = "My Inventory"; - for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), - it_end = mParentChildCategoryTree.end(); it != it_end; ++it) - { - cat_array_t* cat_array = it->second; - for (cat_array_t::const_iterator cat_it = cat_array->begin(), - cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) - { - LLPointer<LLViewerInventoryCategory> category = *cat_it; - - if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) - continue; - if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) - { - if(category->getUUID()!=mRootFolderID) - { - LLUUID& new_inv_root_folder_id = const_cast<LLUUID&>(mRootFolderID); - new_inv_root_folder_id = category->getUUID(); - } - } - } - } - - LLPointer<LLInventoryValidationInfo> validation_info = validate(); - if (validation_info->mFatalErrorCount > 0) - { - // Fatal inventory error. Will not be able to engage in many inventory operations. - // This should be followed by an error dialog leading to logout. - LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " - << "Will not be able to do normal inventory operations in this session." - << LL_ENDL; - mIsAgentInvUsable = false; - } - else - { - mIsAgentInvUsable = true; - } - validation_info->mInitialized = true; - mValidationInfo = validation_info; - - // notifyObservers() has been moved to - // llstartup/idle_startup() after this func completes. - // Allows some system categories to be created before - // observers start firing. - } - } + LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; + + // *NOTE: I am skipping the logic around folder version + // synchronization here because it seems if a folder is lost, we + // might actually want to invalidate it at that point - not + // attempt to cache. More time & thought is necessary. + + // First the categories. We'll copy all of the categories into a + // temporary container to iterate over (oh for real iterators.) + // While we're at it, we'll allocate the arrays in the trees. + cat_array_t cats; + cat_array_t* catsp; + item_array_t* itemsp; + + for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + LLViewerInventoryCategory* cat = cit->second; + cats.push_back(cat); + if (mParentChildCategoryTree.count(cat->getUUID()) == 0) + { + llassert_always(mCategoryLock[cat->getUUID()] == false); + catsp = new cat_array_t; + mParentChildCategoryTree[cat->getUUID()] = catsp; + } + if (mParentChildItemTree.count(cat->getUUID()) == 0) + { + llassert_always(mItemLock[cat->getUUID()] == false); + itemsp = new item_array_t; + mParentChildItemTree[cat->getUUID()] = itemsp; + } + } + + // Insert a special parent for the root - so that lookups on + // LLUUID::null as the parent work correctly. This is kind of a + // blatent wastes of space since we allocate a block of memory for + // the array, but whatever - it's not that much space. + if (mParentChildCategoryTree.count(LLUUID::null) == 0) + { + catsp = new cat_array_t; + mParentChildCategoryTree[LLUUID::null] = catsp; + } + + // Now we have a structure with all of the categories that we can + // iterate over and insert into the correct place in the child + // category tree. + S32 count = cats.size(); + S32 i; + S32 lost = 0; + cat_array_t lost_cats; + for(i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = cats.at(i); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp && + // Only the two root folders should be children of null. + // Others should go to lost & found. + (cat->getParentUUID().notNull() || + cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) + { + catsp->push_back(cat); + } + else + { + // *NOTE: This process could be a lot more efficient if we + // used the new MoveInventoryFolder message, but we would + // have to continue to do the update & build here. So, to + // implement it, we would need a set or map of uuid pairs + // which would be (folder_id, new_parent_id) to be sent up + // to the server. + LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " + << cat->getName() << LL_ENDL; + ++lost; + lost_cats.push_back(cat); + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; + } + + // Do moves in a separate pass to make sure we've properly filed + // the FT_LOST_AND_FOUND category before we try to find its UUID. + for(i = 0; i<lost_cats.size(); ++i) + { + LLViewerInventoryCategory *cat = lost_cats.at(i); + + // plop it into the lost & found. + LLFolderType::EType pref = cat->getPreferredType(); + if(LLFolderType::FT_NONE == pref) + { + cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + } + else if(LLFolderType::FT_ROOT_INVENTORY == pref) + { + // it's the root + cat->setParent(LLUUID::null); + } + else + { + // it's a protected folder. + cat->setParent(gInventory.getRootFolderID()); + } + // FIXME note that updateServer() fails with protected + // types, so this will not work as intended in that case. + // UpdateServer uses AIS, AIS cat move is not implemented yet + // cat->updateServer(TRUE); + + // MoveInventoryFolder message, intentionally per item + cat->updateParentOnServer(FALSE); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp) + { + catsp->push_back(cat); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + + const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); + sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); + + + // Now the items. We allocated in the last step, so now all we + // have to do is iterate over the items and put them in the right + // place. + item_array_t items; + if(!mItemMap.empty()) + { + LLPointer<LLViewerInventoryItem> item; + for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + item = (*iit).second; + items.push_back(item); + } + } + count = items.size(); + lost = 0; + uuid_vec_t lost_item_ids; + for(i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryItem> item; + item = items.at(i); + itemsp = getUnlockedItemArray(item->getParentUUID()); + if(itemsp) + { + itemsp->push_back(item); + } + else + { + LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " + << item->getName() << LL_ENDL; + ++lost; + // plop it into the lost & found. + // + item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + // move it later using a special message to move items. If + // we update server here, the client might crash. + //item->updateServer(); + lost_item_ids.push_back(item->getUUID()); + itemsp = getUnlockedItemArray(item->getParentUUID()); + if(itemsp) + { + itemsp->push_back(item); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + for(uuid_vec_t::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it) + { + if(start_new_message) + { + start_new_message = FALSE; + msg->newMessageFast(_PREHASH_MoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addBOOLFast(_PREHASH_Stamp, FALSE); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, (*it)); + msg->addUUIDFast(_PREHASH_FolderID, lnf); + msg->addString("NewName", NULL); + if(msg->isSendFull(NULL)) + { + start_new_message = TRUE; + gAgent.sendReliableMessage(); + } + } + if(!start_new_message) + { + gAgent.sendReliableMessage(); + } + } + + const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); + if (agent_inv_root_id.notNull()) + { + cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); + if(catsp) + { + // *HACK - fix root inventory folder + // some accounts has pbroken inventory root folders + + std::string name = "My Inventory"; + for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), + it_end = mParentChildCategoryTree.end(); it != it_end; ++it) + { + cat_array_t* cat_array = it->second; + for (cat_array_t::const_iterator cat_it = cat_array->begin(), + cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) + { + LLPointer<LLViewerInventoryCategory> category = *cat_it; + + if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) + continue; + if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) + { + if(category->getUUID()!=mRootFolderID) + { + LLUUID& new_inv_root_folder_id = const_cast<LLUUID&>(mRootFolderID); + new_inv_root_folder_id = category->getUUID(); + } + } + } + } + + LLPointer<LLInventoryValidationInfo> validation_info = validate(); + if (validation_info->mFatalErrorCount > 0) + { + // Fatal inventory error. Will not be able to engage in many inventory operations. + // This should be followed by an error dialog leading to logout. + LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " + << "Will not be able to do normal inventory operations in this session." + << LL_ENDL; + mIsAgentInvUsable = false; + } + else + { + mIsAgentInvUsable = true; + } + validation_info->mInitialized = true; + mValidationInfo = validation_info; + + // notifyObservers() has been moved to + // llstartup/idle_startup() after this func completes. + // Allows some system categories to be created before + // observers start firing. + } + } } // Would normally do this at construction but that's too early @@ -3202,22 +3202,22 @@ void LLInventoryModel::buildParentChildMap() // call set things up. void LLInventoryModel::initHttpRequest() { - if (! mHttpRequestFG) - { - // Haven't initialized, get to it - LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); - - mHttpRequestFG = new LLCore::HttpRequest; - mHttpRequestBG = new LLCore::HttpRequest; - mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); - mHttpOptions->setTransferTimeout(300); - mHttpOptions->setUseRetryAfter(true); - // mHttpOptions->setTrace(2); // Do tracing of requests + if (! mHttpRequestFG) + { + // Haven't initialized, get to it + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + + mHttpRequestFG = new LLCore::HttpRequest; + mHttpRequestBG = new LLCore::HttpRequest; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + mHttpOptions->setTransferTimeout(300); + mHttpOptions->setUseRetryAfter(true); + // mHttpOptions->setTrace(2); // Do tracing of requests mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); - mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); - mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); - mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); - } + mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); + mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); + } if (!gGenericDispatcher.isHandlerPresent("BulkUpdateInventory")) { @@ -3227,49 +3227,49 @@ void LLInventoryModel::initHttpRequest() void LLInventoryModel::handleResponses(bool foreground) { - if (foreground && mHttpRequestFG) - { - mHttpRequestFG->update(0); - } - else if (! foreground && mHttpRequestBG) - { - mHttpRequestBG->update(50000L); - } + if (foreground && mHttpRequestFG) + { + mHttpRequestFG->update(0); + } + else if (! foreground && mHttpRequestBG) + { + mHttpRequestBG->update(50000L); + } } LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground, - const std::string & url, - const LLSD & body, - const LLCore::HttpHandler::ptr_t &handler, - const char * const message) + const std::string & url, + const LLSD & body, + const LLCore::HttpHandler::ptr_t &handler, + const char * const message) { - if (! mHttpRequestFG) - { - // We do the initialization late and lazily as this class is - // statically-constructed and not all the bits are ready at - // that time. - initHttpRequest(); - } - - LLCore::HttpRequest * request(foreground ? mHttpRequestFG : mHttpRequestBG); - LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - - handle = LLCoreHttpUtil::requestPostWithLLSD(request, - mHttpPolicyClass, - url, - body, - mHttpOptions, - mHttpHeaders, - handler); - if (LLCORE_HTTP_HANDLE_INVALID == handle) - { - LLCore::HttpStatus status(request->getStatus()); - LL_WARNS(LOG_INV) << "HTTP POST request failed for " << message - << ", Status: " << status.toTerseString() - << " Reason: '" << status.toString() << "'" - << LL_ENDL; - } - return handle; + if (! mHttpRequestFG) + { + // We do the initialization late and lazily as this class is + // statically-constructed and not all the bits are ready at + // that time. + initHttpRequest(); + } + + LLCore::HttpRequest * request(foreground ? mHttpRequestFG : mHttpRequestBG); + LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + + handle = LLCoreHttpUtil::requestPostWithLLSD(request, + mHttpPolicyClass, + url, + body, + mHttpOptions, + mHttpHeaders, + handler); + if (LLCORE_HTTP_HANDLE_INVALID == handle) + { + LLCore::HttpStatus status(request->getStatus()); + LL_WARNS(LOG_INV) << "HTTP POST request failed for " << message + << ", Status: " << status.toTerseString() + << " Reason: '" << status.toString() << "'" + << LL_ENDL; + } + return handle; } void LLInventoryModel::createCommonSystemCategories() @@ -3277,12 +3277,12 @@ void LLInventoryModel::createCommonSystemCategories() //amount of System Folder we should wait for sPendingSystemFolders = 9; - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS); gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MATERIAL); // probably should be server created gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX); @@ -3290,154 +3290,154 @@ void LLInventoryModel::createCommonSystemCategories() struct LLUUIDAndName { - LLUUIDAndName() {} - LLUUIDAndName(const LLUUID& id, const std::string& name); - bool operator==(const LLUUIDAndName& rhs) const; - bool operator<(const LLUUIDAndName& rhs) const; - bool operator>(const LLUUIDAndName& rhs) const; - - LLUUID mID; - std::string mName; + LLUUIDAndName() {} + LLUUIDAndName(const LLUUID& id, const std::string& name); + bool operator==(const LLUUIDAndName& rhs) const; + bool operator<(const LLUUIDAndName& rhs) const; + bool operator>(const LLUUIDAndName& rhs) const; + + LLUUID mID; + std::string mName; }; LLUUIDAndName::LLUUIDAndName(const LLUUID& id, const std::string& name) : - mID(id), mName(name) + mID(id), mName(name) { } bool LLUUIDAndName::operator==(const LLUUIDAndName& rhs) const { - return ((mID == rhs.mID) && (mName == rhs.mName)); + return ((mID == rhs.mID) && (mName == rhs.mName)); } bool LLUUIDAndName::operator<(const LLUUIDAndName& rhs) const { - return (mID < rhs.mID); + return (mID < rhs.mID); } bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const { - return (mID > rhs.mID); + return (mID > rhs.mID); } // static bool LLInventoryModel::loadFromFile(const std::string& filename, - LLInventoryModel::cat_array_t& categories, - LLInventoryModel::item_array_t& items, - LLInventoryModel::changed_items_t& cats_to_update, - bool &is_cache_obsolete) + LLInventoryModel::cat_array_t& categories, + LLInventoryModel::item_array_t& items, + LLInventoryModel::changed_items_t& cats_to_update, + bool &is_cache_obsolete) { LL_PROFILE_ZONE_NAMED("inventory load from file"); - if(filename.empty()) - { - LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; - return false; - } - LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; - - llifstream file(filename.c_str()); - - if (!file.is_open()) - { - LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; - return false; - } - - is_cache_obsolete = true; // Obsolete until proven current - - //U64 lines_count = 0U; - std::string line; - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - while (std::getline(file, line)) - { - LLSD s_item; - std::istringstream iss(line); - if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; - break; - } - - if (s_item.has("inv_cache_version")) - { - S32 version = s_item["inv_cache_version"].asInteger(); - if (version == sCurrentInvCacheVersion) - { - // Cache is up to date - is_cache_obsolete = false; - continue; - } - else - { - LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; - break; - } - } - else if (s_item.has("cat_id")) - { - if (is_cache_obsolete) - break; - - LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importLLSD(s_item)) - { - categories.push_back(inv_cat); - } - } - else if (s_item.has("item_id")) - { - if (is_cache_obsolete) - break; - - LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; - if( inv_item->fromLLSD(s_item) ) - { - if(inv_item->getUUID().isNull()) - { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - } - else - { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) - { - cats_to_update.insert(inv_item->getParentUUID()); - } - else - { - items.push_back(inv_item); - } - } - } - } + if(filename.empty()) + { + LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; + return false; + } + LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; + + llifstream file(filename.c_str()); + + if (!file.is_open()) + { + LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; + return false; + } + + is_cache_obsolete = true; // Obsolete until proven current + + //U64 lines_count = 0U; + std::string line; + LLPointer<LLSDParser> parser = new LLSDNotationParser(); + while (std::getline(file, line)) + { + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; + break; + } + + if (s_item.has("inv_cache_version")) + { + S32 version = s_item["inv_cache_version"].asInteger(); + if (version == sCurrentInvCacheVersion) + { + // Cache is up to date + is_cache_obsolete = false; + continue; + } + else + { + LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; + break; + } + } + else if (s_item.has("cat_id")) + { + if (is_cache_obsolete) + break; + + LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if(inv_cat->importLLSD(s_item)) + { + categories.push_back(inv_cat); + } + } + else if (s_item.has("item_id")) + { + if (is_cache_obsolete) + break; + + LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; + if( inv_item->fromLLSD(s_item) ) + { + if(inv_item->getUUID().isNull()) + { + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; + } + else + { + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } + } + } + } // TODO(brad) - figure out how to reenable this without breaking everything else -// static constexpr U64 BATCH_SIZE = 512U; -// if ((++lines_count % BATCH_SIZE) == 0) -// { -// // SL-19968 - make sure message system code gets a chance to run every so often -// pump_idle_startup_network(); -// } - } +// static constexpr U64 BATCH_SIZE = 512U; +// if ((++lines_count % BATCH_SIZE) == 0) +// { +// // SL-19968 - make sure message system code gets a chance to run every so often +// pump_idle_startup_network(); +// } + } - file.close(); + file.close(); - return !is_cache_obsolete; + return !is_cache_obsolete; } // static bool LLInventoryModel::saveToFile(const std::string& filename, - const cat_array_t& categories, - const item_array_t& items) + const cat_array_t& categories, + const item_array_t& items) { - if (filename.empty()) - { - LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; - return false; - } + if (filename.empty()) + { + LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; + return false; + } - LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; + LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; try { @@ -3509,46 +3509,46 @@ bool LLInventoryModel::saveToFile(const std::string& filename, // static void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) { - //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate, - // processInventoryUpdate, - // NULL); - //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory, - // processUseCachedInventory, - // NULL); - msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem, - processUpdateCreateInventoryItem, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, - processRemoveInventoryItem, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, - processRemoveInventoryFolder, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, - processRemoveInventoryObjects, - NULL); - msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory, - processSaveAssetIntoInventory, - NULL); - msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, - processBulkUpdateInventory, - NULL); - msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem); + //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate, + // processInventoryUpdate, + // NULL); + //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory, + // processUseCachedInventory, + // NULL); + msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem, + processUpdateCreateInventoryItem, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, + processRemoveInventoryItem, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, + processRemoveInventoryFolder, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, + processRemoveInventoryObjects, + NULL); + msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory, + processSaveAssetIntoInventory, + NULL); + msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, + processBulkUpdateInventory, + NULL); + msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem); } -// static +// static void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**) { - // do accounting and highlight new items if they arrive - if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) - { - U32 callback_id; - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); - msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id); + // do accounting and highlight new items if they arrive + if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) + { + U32 callback_id; + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); + msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id); - gInventoryCallbacks.fire(callback_id, item_id); + gInventoryCallbacks.fire(callback_id, item_id); // Message system at the moment doesn't support Thumbnails and potential // newer features so just rerequest whole item @@ -3556,251 +3556,251 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo // todo: instead of unpacking message fully, // grab only an item_id, then fetch LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true); - } + } } bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask) { - //make sure our added inventory observer is active - start_new_inventory_observer(); - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id - << LL_ENDL; - return false; - } - item_array_t items; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - // Does this loop ever execute more than once? - for(S32 i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " - << titem->getUUID() << LL_ENDL; - items.push_back(titem); - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) - { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; - } - } - if(account) - { - gInventory.accountForUpdate(update); - } - - if (account) - { - mask |= LLInventoryObserver::CREATE; - } - //as above, this loop never seems to loop more than once per call - for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - gInventory.updateItem(*it, mask); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); - - return true; -} - -// static -void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) -{ - LLUUID item_id; - S32 count = msg->getNumberOfBlocksFast(msg_label); - LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; - uuid_vec_t item_ids; - update_map_t update; - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); - LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if(itemp) - { - LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; - // we only bother with the delete and account if we found - // the item - this is usually a back-up for permissions, - // so frequently the item will already be gone. - --update[itemp->getParentUUID()]; - item_ids.push_back(item_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; - gInventory.deleteObject(*it); - } -} - -// static -void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) -{ - LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; - LLUUID agent_id, item_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); - gInventory.notifyObservers(); -} + //make sure our added inventory observer is active + start_new_inventory_observer(); -// static -void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, - LLMessageSystem* msg) + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return false; + } + item_array_t items; + update_map_t update; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + // Does this loop ever execute more than once? + for(S32 i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + titem->unpackMessage(msg, _PREHASH_InventoryData, i); + LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + // examine update for changes. + LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); + if(itemp) + { + if(titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + } + if(account) + { + gInventory.accountForUpdate(update); + } + + if (account) + { + mask |= LLInventoryObserver::CREATE; + } + //as above, this loop never seems to loop more than once per call + for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + gInventory.updateItem(*it, mask); + } + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); + + return true; +} + +// static +void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) +{ + LLUUID item_id; + S32 count = msg->getNumberOfBlocksFast(msg_label); + LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; + uuid_vec_t item_ids; + update_map_t update; + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); + LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if(itemp) + { + LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; + // we only bother with the delete and account if we found + // the item - this is usually a back-up for permissions, + // so frequently the item will already be gone. + --update[itemp->getParentUUID()]; + item_ids.push_back(item_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) + { + LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; + gInventory.deleteObject(*it); + } +} + +// static +void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) { - LLUUID folder_id; - uuid_vec_t folder_ids; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i); - LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id); - if(folderp) - { - --update[folderp->getParentUUID()]; - folder_ids.push_back(folder_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) - { - gInventory.deleteObject(*it); - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; + LLUUID agent_id, item_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); + gInventory.notifyObservers(); } -// static +// static +void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, + LLMessageSystem* msg) +{ + LLUUID folder_id; + uuid_vec_t folder_ids; + update_map_t update; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i); + LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id); + if(folderp) + { + --update[folderp->getParentUUID()]; + folder_ids.push_back(folder_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) + { + gInventory.deleteObject(*it); + } +} + +// static void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, - void**) + void**) { - LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; - LLUUID agent_id, session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryFolder( agent_id, msg ); - gInventory.notifyObservers(); + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + gInventory.notifyObservers(); } -// static +// static void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, - void**) + void**) { - LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; - LLUUID agent_id, session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryFolder( agent_id, msg ); - LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); - gInventory.notifyObservers(); + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); + gInventory.notifyObservers(); } -// static +// static void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, - void**) + void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." - << LL_ENDL; - return; - } - - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); - - // The viewer ignores the asset id because this message is only - // used for attachments/objects, so the asset id is not used in - // the viewer anyway. - LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" - << item_id << LL_ENDL; - LLViewerInventoryItem* item = gInventory.getItem( item_id ); - if( item ) - { - LLCategoryUpdate up(item->getParentUUID(), 0); - gInventory.accountForUpdate(up); - gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id); - gInventory.notifyObservers(); - } - else - { - LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" - " not found: " << item_id << LL_ENDL; - } - if(gViewerWindow) - { - gViewerWindow->getWindow()->decBusyCount(); - } + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." + << LL_ENDL; + return; + } + + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); + + // The viewer ignores the asset id because this message is only + // used for attachments/objects, so the asset id is not used in + // the viewer anyway. + LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" + << item_id << LL_ENDL; + LLViewerInventoryItem* item = gInventory.getItem( item_id ); + if( item ) + { + LLCategoryUpdate up(item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id); + gInventory.notifyObservers(); + } + else + { + LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" + " not found: " << item_id << LL_ENDL; + } + if(gViewerWindow) + { + gViewerWindow->getWindow()->decBusyCount(); + } } // static void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; - return; - } - LLUUID tid; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; + return; + } + LLUUID tid; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); #ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; + LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; #endif - update_map_t update; - cat_array_t folders; - S32 count; - S32 i; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID()); - tfolder->unpackMessage(msg, _PREHASH_FolderData, i); - LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" - << tfolder->getUUID() << ") in " << tfolder->getParentUUID() - << LL_ENDL; - + update_map_t update; + cat_array_t folders; + S32 count; + S32 i; + count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + for(i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID()); + tfolder->unpackMessage(msg, _PREHASH_FolderData, i); + LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" + << tfolder->getUUID() << ") in " << tfolder->getParentUUID() + << LL_ENDL; + // If the folder is a listing or a version folder, all we need to do is update the SLM data int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID()); if ((depth_folder == 1) || (depth_folder == 2)) @@ -3811,12 +3811,12 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLMarketplaceData::instance().getListing(listing_id); // In that case, there is no item to update so no callback -> we skip the rest of the update } - else if(tfolder->getUUID().notNull()) - { - folders.push_back(tfolder); - LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); - if(folderp) - { + else if(tfolder->getUUID().notNull()) + { + folders.push_back(tfolder); + LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { if (tfolder->getParentUUID() == folderp->getParentUUID()) @@ -3833,15 +3833,15 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - else - { - // we could not find the folder, so it is probably - // new. However, we only want to attempt accounting - // for the parent if we can find the parent. - folderp = gInventory.getCategory(tfolder->getParentUUID()); - if(folderp) - { + } + else + { + // we could not find the folder, so it is probably + // new. However, we only want to attempt accounting + // for the parent if we can find the parent. + folderp = gInventory.getCategory(tfolder->getParentUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { ++update[tfolder->getParentUUID()]; @@ -3850,51 +3850,51 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - } - } - } - - - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - uuid_vec_t wearable_ids; - item_array_t items; - std::list<InventoryCallbackInfo> cblist; - for(i = 0; i < count; ++i) - { - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - titem->unpackMessage(msg, _PREHASH_ItemData, i); - LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " - << titem->getParentUUID() << LL_ENDL; - U32 callback_id; - msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); - if(titem->getUUID().notNull() ) // && callback_id.notNull() ) - { - items.push_back(titem); - cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); - if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) - { - wearable_ids.push_back(titem->getUUID()); - } - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) - { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); - if(folderp) - { + } + } + } + } + + + count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); + uuid_vec_t wearable_ids; + item_array_t items; + std::list<InventoryCallbackInfo> cblist; + for(i = 0; i < count; ++i) + { + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + titem->unpackMessage(msg, _PREHASH_ItemData, i); + LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " + << titem->getParentUUID() << LL_ENDL; + U32 callback_id; + msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); + if(titem->getUUID().notNull() ) // && callback_id.notNull() ) + { + items.push_back(titem); + cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); + if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) + { + wearable_ids.push_back(titem->getUUID()); + } + // examine update for changes. + LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); + if(itemp) + { + if(titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { ++update[titem->getParentUUID()]; @@ -3903,18 +3903,18 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - } - } - else - { - cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); - } - } - gInventory.accountForUpdate(update); - - for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) - { + } + } + } + else + { + cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); + } + } + gInventory.accountForUpdate(update); + + for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) + { gInventory.updateCategory(*cit); if ((*cit)->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { @@ -3924,100 +3924,100 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); } // else already called fetch() above - } - for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) - { - gInventory.updateItem(*iit); + } + for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) + { + gInventory.updateItem(*iit); // Temporary workaround: just fetch the item using AIS to get missing fields. // If this works fine we might want to extract 'ids only' from the message // then use AIS as a primary fetcher LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true); - } - gInventory.notifyObservers(); - - // The incoming inventory could span more than one BulkInventoryUpdate packet, - // so record the transaction ID for this purchase, then wear all clothing - // that comes in as part of that transaction ID. JC - if (LLInventoryState::sWearNewClothing) - { - LLInventoryState::sWearNewClothingTransactionID = tid; - LLInventoryState::sWearNewClothing = FALSE; - } - - if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) - { - count = wearable_ids.size(); - for (i = 0; i < count; ++i) - { - LLViewerInventoryItem* wearable_item; - wearable_item = gInventory.getItem(wearable_ids[i]); - LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); - } - } - - std::list<InventoryCallbackInfo>::iterator inv_it; - for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) - { - InventoryCallbackInfo cbinfo = (*inv_it); - gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); - } + } + gInventory.notifyObservers(); + + // The incoming inventory could span more than one BulkInventoryUpdate packet, + // so record the transaction ID for this purchase, then wear all clothing + // that comes in as part of that transaction ID. JC + if (LLInventoryState::sWearNewClothing) + { + LLInventoryState::sWearNewClothingTransactionID = tid; + LLInventoryState::sWearNewClothing = FALSE; + } + + if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) + { + count = wearable_ids.size(); + for (i = 0; i < count; ++i) + { + LLViewerInventoryItem* wearable_item; + wearable_item = gInventory.getItem(wearable_ids[i]); + LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); + } + } + + std::list<InventoryCallbackInfo>::iterator inv_it; + for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) + { + InventoryCallbackInfo cbinfo = (*inv_it); + gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); + } } // static void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) { - LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." - << LL_ENDL; - return; - } - - LLUUID item_id; - LLUUID folder_id; - std::string new_name; - bool anything_changed = false; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if(item) - { - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); - msg->getString("InventoryData", "NewName", new_name, i); - - LL_DEBUGS() << "moving item " << item_id << " to folder " - << folder_id << LL_ENDL; - update_list_t update; - LLCategoryUpdate old_folder(item->getParentUUID(), -1); - update.push_back(old_folder); - LLCategoryUpdate new_folder(folder_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - new_item->setParent(folder_id); - if (new_name.length() > 0) - { - new_item->rename(new_name); - } - gInventory.updateItem(new_item); - anything_changed = true; - } - else - { - LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; - } - } - if(anything_changed) - { - gInventory.notifyObservers(); - } + LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." + << LL_ENDL; + return; + } + + LLUUID item_id; + LLUUID folder_id; + std::string new_name; + bool anything_changed = false; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if(item) + { + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); + msg->getString("InventoryData", "NewName", new_name, i); + + LL_DEBUGS() << "moving item " << item_id << " to folder " + << folder_id << LL_ENDL; + update_list_t update; + LLCategoryUpdate old_folder(item->getParentUUID(), -1); + update.push_back(old_folder); + LLCategoryUpdate new_folder(folder_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + new_item->setParent(folder_id); + if (new_name.length() > 0) + { + new_item->rename(new_name); + } + gInventory.updateItem(new_item); + anything_changed = true; + } + else + { + LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; + } + } + if(anything_changed) + { + gInventory.notifyObservers(); + } } //---------------------------------------------------------------------------- @@ -4026,274 +4026,274 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purge_descendents_of(folder_id, NULL); + } + return false; } void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderType::EType preferred_type) { - if (!notification.empty()) - { - LLSD args; - if(LLFolderType::FT_TRASH == preferred_type) - { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - const LLUUID trash_id = findCategoryUUIDForType(preferred_type); - gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants - S32 item_count = items.size() + cats.size(); - args["COUNT"] = item_count; - } - LLNotificationsUtil::add(notification, args, LLSD(), - boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); - } - else - { - const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); - } + if (!notification.empty()) + { + LLSD args; + if(LLFolderType::FT_TRASH == preferred_type) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + const LLUUID trash_id = findCategoryUUIDForType(preferred_type); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants + S32 item_count = items.size() + cats.size(); + args["COUNT"] = item_count; + } + LLNotificationsUtil::add(notification, args, LLSD(), + boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); + } + else + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purge_descendents_of(folder_id, NULL); + } } //---------------------------------------------------------------------------- void LLInventoryModel::removeItem(const LLUUID& item_id) { - LLViewerInventoryItem* item = getItem(item_id); - if (! item) - { - LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; - } - else - { - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (new_parent.notNull()) - { - LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; - changeItemParent(item, new_parent, TRUE); - } - } + LLViewerInventoryItem* item = getItem(item_id); + if (! item) + { + LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (new_parent.notNull()) + { + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); + } + } } void LLInventoryModel::removeCategory(const LLUUID& category_id) { - if (! get_is_category_removable(this, category_id)) - { - return; - } - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - collectDescendents(category_id, descendent_categories, descendent_items, FALSE); - - for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); - iter != descendent_items.end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - const LLUUID& item_id = item->getUUID(); - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item_id)) - { - LLGestureMgr::instance().deactivateGesture(item_id); - } - } - - LLViewerInventoryCategory* cat = getCategory(category_id); - if (cat) - { - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (trash_id.notNull()) - { - changeCategoryParent(cat, trash_id, TRUE); - } - } - - checkTrashOverflow(); + if (! get_is_category_removable(this, category_id)) + { + return; + } + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + collectDescendents(category_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + const LLUUID& item_id = item->getUUID(); + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item_id)) + { + LLGestureMgr::instance().deactivateGesture(item_id); + } + } + + LLViewerInventoryCategory* cat = getCategory(category_id); + if (cat) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull()) + { + changeCategoryParent(cat, trash_id, TRUE); + } + } + + checkTrashOverflow(); } void LLInventoryModel::removeObject(const LLUUID& object_id) { - if(object_id.isNull()) - { - return; - } - - LLInventoryObject* obj = getObject(object_id); - if (dynamic_cast<LLViewerInventoryItem*>(obj)) - { - removeItem(object_id); - } - else if (dynamic_cast<LLViewerInventoryCategory*>(obj)) - { - removeCategory(object_id); - } - else if (obj) - { - LL_WARNS("Inventory") << "object ID " << object_id - << " is an object of unrecognized class " - << typeid(*obj).name() << LL_ENDL; - } - else - { - LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; - } + if(object_id.isNull()) + { + return; + } + + LLInventoryObject* obj = getObject(object_id); + if (dynamic_cast<LLViewerInventoryItem*>(obj)) + { + removeItem(object_id); + } + else if (dynamic_cast<LLViewerInventoryCategory*>(obj)) + { + removeCategory(object_id); + } + else if (obj) + { + LL_WARNS("Inventory") << "object ID " << object_id + << " is an object of unrecognized class " + << typeid(*obj).name() << LL_ENDL; + } + else + { + LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; + } } bool callback_preview_trash_folder(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - LLFloaterPreviewTrash::show(); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + LLFloaterPreviewTrash::show(); + } + return false; } void LLInventoryModel::checkTrashOverflow() { - static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); - - // Collect all descendants including those in subfolders. - // - // Note: Do we really need content of subfolders? - // This was made to prevent download of trash folder timeouting - // viewer and sub-folders are supposed to download independently. - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); - S32 item_count = items.size() + cats.size(); - - if (item_count >= trash_max_capacity) - { - if (LLFloaterPreviewTrash::isVisible()) - { - // bring to front - LLFloaterPreviewTrash::show(); - } - else - { - LLNotificationsUtil::add("TrashIsFull", LLSD(), LLSD(), - boost::bind(callback_preview_trash_folder, _1, _2)); - } - } + static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); + + // Collect all descendants including those in subfolders. + // + // Note: Do we really need content of subfolders? + // This was made to prevent download of trash folder timeouting + // viewer and sub-folders are supposed to download independently. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + S32 item_count = items.size() + cats.size(); + + if (item_count >= trash_max_capacity) + { + if (LLFloaterPreviewTrash::isVisible()) + { + // bring to front + LLFloaterPreviewTrash::show(); + } + else + { + LLNotificationsUtil::add("TrashIsFull", LLSD(), LLSD(), + boost::bind(callback_preview_trash_folder, _1, _2)); + } + } } const LLUUID &LLInventoryModel::getRootFolderID() const { - return mRootFolderID; + return mRootFolderID; } void LLInventoryModel::setRootFolderID(const LLUUID& val) { - mRootFolderID = val; + mRootFolderID = val; } const LLUUID &LLInventoryModel::getLibraryRootFolderID() const { - return mLibraryRootFolderID; + return mLibraryRootFolderID; } void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val) { - mLibraryRootFolderID = val; + mLibraryRootFolderID = val; } const LLUUID &LLInventoryModel::getLibraryOwnerID() const { - return mLibraryOwnerID; + return mLibraryOwnerID; } void LLInventoryModel::setLibraryOwnerID(const LLUUID& val) { - mLibraryOwnerID = val; + mLibraryOwnerID = val; } // static BOOL LLInventoryModel::getIsFirstTimeInViewer2() { - // Do not call this before parentchild map is built. - if (!gInventory.mIsAgentInvUsable) - { - LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; - return TRUE; - } - - return sFirstTimeInViewer2; + // Do not call this before parentchild map is built. + if (!gInventory.mIsAgentInvUsable) + { + LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; + return TRUE; + } + + return sFirstTimeInViewer2; } LLInventoryModel::item_array_t::iterator LLInventoryModel::findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) { - LLInventoryModel::item_array_t::iterator curr_item = items.begin(); - - while (curr_item != items.end()) - { - if ((*curr_item)->getUUID() == id) - { - break; - } - ++curr_item; - } - - return curr_item; + LLInventoryModel::item_array_t::iterator curr_item = items.begin(); + + while (curr_item != items.end()) + { + if ((*curr_item)->getUUID() == id) + { + break; + } + ++curr_item; + } + + return curr_item; } // static // * @param[in, out] items - vector with items to be updated. It should be sorted in a right way // * before calling this method. // * @param src_item_id - LLUUID of inventory item to be moved in new position -// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should +// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should // * be placed. -// * @param insert_before - bool indicating if src_item_id should be placed before or after +// * @param insert_before - bool indicating if src_item_id should be placed before or after // * dest_item_id. Default is true. void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id, bool insert_before) { - LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); - LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); - - // If one of the passed UUID is not in the item list, bail out - if ((it_src == items.end()) || (it_dest == items.end())) - return; - - // Erase the source element from the list, keep a copy before erasing. - LLViewerInventoryItem* src_item = *it_src; - items.erase(it_src); - - // Note: Target iterator is not valid anymore because the container was changed, so update it. - it_dest = findItemIterByUUID(items, dest_item_id); - - // Go to the next element if one wishes to insert after the dest element - if (!insert_before) - { - ++it_dest; - } - - // Reinsert the source item in the right place - if (it_dest != items.end()) - { - items.insert(it_dest, src_item); - } - else - { - // Append to the list if it_dest reached the end - items.push_back(src_item); - } + LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); + LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); + + // If one of the passed UUID is not in the item list, bail out + if ((it_src == items.end()) || (it_dest == items.end())) + return; + + // Erase the source element from the list, keep a copy before erasing. + LLViewerInventoryItem* src_item = *it_src; + items.erase(it_src); + + // Note: Target iterator is not valid anymore because the container was changed, so update it. + it_dest = findItemIterByUUID(items, dest_item_id); + + // Go to the next element if one wishes to insert after the dest element + if (!insert_before) + { + ++it_dest; + } + + // Reinsert the source item in the right place + if (it_dest != items.end()) + { + items.insert(it_dest, src_item); + } + else + { + // Append to the list if it_dest reached the end + items.push_back(src_item); + } } // See also LLInventorySort where landmarks in the Favorites folder are sorted. class LLViewerInventoryItemSort { public: - bool operator()(const LLPointer<LLViewerInventoryItem>& a, const LLPointer<LLViewerInventoryItem>& b) - { - return a->getSortField() < b->getSortField(); - } + bool operator()(const LLPointer<LLViewerInventoryItem>& a, const LLPointer<LLViewerInventoryItem>& b) + { + return a->getSortField() < b->getSortField(); + } }; //---------------------------------------------------------------------------- @@ -4301,95 +4301,95 @@ public: // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() const { - LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; - LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - const LLViewerInventoryCategory* cat = cit->second; - if(cat) - { - LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " - << cat->getVersion() << " " << cat->getDescendentCount() - << LL_ENDL; - } - else - { - LL_INFOS() << " NULL!" << LL_ENDL; - } - } - LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - const LLViewerInventoryItem* item = iit->second; - if(item) - { - LL_INFOS() << " " << item->getUUID() << " " - << item->getName() << LL_ENDL; - } - else - { - LL_INFOS() << " NULL!" << LL_ENDL; - } - } - LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; + LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; + LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLViewerInventoryCategory* cat = cit->second; + if(cat) + { + LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " + << cat->getVersion() << " " << cat->getDescendentCount() + << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLViewerInventoryItem* item = iit->second; + if(item) + { + LL_INFOS() << " " << item->getUUID() << " " + << item->getName() << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; } // Do various integrity checks on model, logging issues found and -// returning an overall good/bad flag. +// returning an overall good/bad flag. LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { - LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; - S32 fatal_errs = 0; - S32 warning_count= 0; + LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; + S32 fatal_errs = 0; + S32 warning_count= 0; S32 loop_count = 0; S32 orphaned_count = 0; - if (getRootFolderID().isNull()) - { - LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; - validation_info->mFatalNoRootFolder = true; + if (getRootFolderID().isNull()) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; + validation_info->mFatalNoRootFolder = true; fatal_errs++; - } - if (getLibraryRootFolderID().isNull()) - { - // Probably shouldn't be a fatality, inventory can function without a library - LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; - validation_info->mFatalNoLibraryRootFolder = true; + } + if (getLibraryRootFolderID().isNull()) + { + // Probably shouldn't be a fatality, inventory can function without a library + LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; + validation_info->mFatalNoLibraryRootFolder = true; fatal_errs++; - } - - if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) - { - // ParentChild should be one larger because of the special entry for null uuid. - LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() - << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; - - validation_info->mWarnings["category_map_size"]++; - warning_count++; - } - S32 cat_lock = 0; - S32 item_lock = 0; - S32 desc_unknown_count = 0; - S32 version_unknown_count = 0; - - typedef std::map<LLFolderType::EType, S32> ft_count_map; - ft_count_map ft_counts_under_root; - ft_count_map ft_counts_elsewhere; - - // Loop over all categories and check. - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - const LLUUID& cat_id = cit->first; - const LLViewerInventoryCategory *cat = cit->second; - if (!cat) - { - LL_WARNS("Inventory") << "null cat" << LL_ENDL; - validation_info->mWarnings["null_cat"]++; - warning_count++; - continue; - } - LLUUID topmost_ancestor_id; - // Will leave as null uuid on failure + } + + if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) + { + // ParentChild should be one larger because of the special entry for null uuid. + LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + + validation_info->mWarnings["category_map_size"]++; + warning_count++; + } + S32 cat_lock = 0; + S32 item_lock = 0; + S32 desc_unknown_count = 0; + S32 version_unknown_count = 0; + + typedef std::map<LLFolderType::EType, S32> ft_count_map; + ft_count_map ft_counts_under_root; + ft_count_map ft_counts_elsewhere; + + // Loop over all categories and check. + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLUUID& cat_id = cit->first; + const LLViewerInventoryCategory *cat = cit->second; + if (!cat) + { + LL_WARNS("Inventory") << "null cat" << LL_ENDL; + validation_info->mWarnings["null_cat"]++; + warning_count++; + continue; + } + LLUUID topmost_ancestor_id; + // Will leave as null uuid on failure EAncestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id); switch (res) { @@ -4403,361 +4403,361 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const break; default: LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL; - validation_info->mWarnings["unknown_ancestor_status"]++; + validation_info->mWarnings["unknown_ancestor_status"]++; warning_count++; break; } - if (cat_id != cat->getUUID()) - { - LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; - validation_info->mWarnings["cat_id_index_mismatch"]++; - warning_count++; - } - - if (cat->getParentUUID().isNull()) - { - if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" - << getRootFolderID() << ") or library root (" - << getLibraryRootFolderID() << ")" << LL_ENDL; - validation_info->mWarnings["null_parent"]++; - warning_count++; - } - } - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(cat_id,cats,items); - if (!cats || !items) - { - LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; - validation_info->mWarnings["direct_descendents"]++; - warning_count++; - continue; - } - if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) - { - desc_unknown_count++; - } - else if (cats->size() + items->size() != cat->getDescendentCount()) - { - // In the case of library this is not unexpected, since - // different user accounts may be getting the library - // contents from different inventory hosts. - if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() +items->size() << LL_ENDL; - validation_info->mWarnings["invalid_descendent_count"]++; - warning_count++; - } - } - if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) - { - version_unknown_count++; - } - auto cat_lock_it = mCategoryLock.find(cat_id); - if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) - { - cat_lock++; - } - auto item_lock_it = mItemLock.find(cat_id); - if (item_lock_it != mItemLock.end() && item_lock_it->second) - { - item_lock++; - } - for (S32 i = 0; i<items->size(); i++) - { - LLViewerInventoryItem *item = items->at(i); - - if (!item) - { - LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; - validation_info->mWarnings["null_item_at_index"]++; - warning_count++; - continue; - } - - const LLUUID& item_id = item->getUUID(); - - if (item->getParentUUID() != cat_id) - { - LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " - << item->getParentUUID() << " expected " << cat_id - << LL_ENDL; - validation_info->mWarnings["wrong_parent_for_item"]++; - warning_count++; - } - - - // Entries in items and mItemMap should correspond. - item_map_t::const_iterator it = mItemMap.find(item_id); - if (it == mItemMap.end()) - { - LL_WARNS("Inventory") << "item " << item_id << " found as child of " - << cat_id << " but not in top level mItemMap" << LL_ENDL; - validation_info->mWarnings["item_not_in_top_map"]++; - warning_count++; - } - else - { - LLViewerInventoryItem *top_item = it->second; - if (top_item != item) - { - LL_WARNS("Inventory") << "item mismatch, item_id " << item_id - << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; - } - } - - // Topmost ancestor should be root or library. - LLUUID topmost_ancestor_id; + if (cat_id != cat->getUUID()) + { + LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + validation_info->mWarnings["cat_id_index_mismatch"]++; + warning_count++; + } + + if (cat->getParentUUID().isNull()) + { + if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + validation_info->mWarnings["null_parent"]++; + warning_count++; + } + } + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(cat_id,cats,items); + if (!cats || !items) + { + LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; + validation_info->mWarnings["direct_descendents"]++; + warning_count++; + continue; + } + if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + { + desc_unknown_count++; + } + else if (cats->size() + items->size() != cat->getDescendentCount()) + { + // In the case of library this is not unexpected, since + // different user accounts may be getting the library + // contents from different inventory hosts. + if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + validation_info->mWarnings["invalid_descendent_count"]++; + warning_count++; + } + } + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + version_unknown_count++; + } + auto cat_lock_it = mCategoryLock.find(cat_id); + if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) + { + cat_lock++; + } + auto item_lock_it = mItemLock.find(cat_id); + if (item_lock_it != mItemLock.end() && item_lock_it->second) + { + item_lock++; + } + for (S32 i = 0; i<items->size(); i++) + { + LLViewerInventoryItem *item = items->at(i); + + if (!item) + { + LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + validation_info->mWarnings["null_item_at_index"]++; + warning_count++; + continue; + } + + const LLUUID& item_id = item->getUUID(); + + if (item->getParentUUID() != cat_id) + { + LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + validation_info->mWarnings["wrong_parent_for_item"]++; + warning_count++; + } + + + // Entries in items and mItemMap should correspond. + item_map_t::const_iterator it = mItemMap.find(item_id); + if (it == mItemMap.end()) + { + LL_WARNS("Inventory") << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + validation_info->mWarnings["item_not_in_top_map"]++; + warning_count++; + } + else + { + LLViewerInventoryItem *top_item = it->second; + if (top_item != item) + { + LL_WARNS("Inventory") << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + } + } + + // Topmost ancestor should be root or library. + LLUUID topmost_ancestor_id; EAncestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); - if (found != ANCESTOR_OK) - { - LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; - validation_info->mWarnings["topmost_ancestor_not_found"]++; - warning_count++; - } - else - { - if (topmost_ancestor_id != getRootFolderID() && - topmost_ancestor_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id - << " got " << topmost_ancestor_id - << " expected " << getRootFolderID() - << " or " << getLibraryRootFolderID() << LL_ENDL; - validation_info->mWarnings["topmost_ancestor_not_recognized"]++; - warning_count++; - } - } - } - - // Does this category appear as a child of its supposed parent? - const LLUUID& parent_id = cat->getParentUUID(); - if (!parent_id.isNull()) - { - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(parent_id,cats,items); - if (!cats) - { - LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + if (found != ANCESTOR_OK) + { + LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; + validation_info->mWarnings["topmost_ancestor_not_found"]++; + warning_count++; + } + else + { + if (topmost_ancestor_id != getRootFolderID() && + topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + validation_info->mWarnings["topmost_ancestor_not_recognized"]++; + warning_count++; + } + } + } + + // Does this category appear as a child of its supposed parent? + const LLUUID& parent_id = cat->getParentUUID(); + if (!parent_id.isNull()) + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!cats) + { + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - else - { - bool found = false; - for (S32 i = 0; i<cats->size(); i++) - { - LLViewerInventoryCategory *kid_cat = cats->at(i); - if (kid_cat == cat) - { - found = true; - break; - } - } - if (!found) - { - LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i = 0; i<cats->size(); i++) + { + LLViewerInventoryCategory *kid_cat = cats->at(i); + if (kid_cat == cat) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - } - } - - // Update count of preferred types - LLFolderType::EType folder_type = cat->getPreferredType(); - bool cat_is_in_library = false; - LLUUID topmost_id; - if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID()) - { - cat_is_in_library = true; - } - if (!cat_is_in_library) - { - if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) - { - ft_counts_under_root[folder_type]++; - if (folder_type != LLFolderType::FT_NONE) - { - LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; - } - } - else - { - ft_counts_elsewhere[folder_type]++; - if (folder_type != LLFolderType::FT_NONE) - { - LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; - } - } - } - } - - // Loop over all items and check - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - const LLUUID& item_id = iit->first; - LLViewerInventoryItem *item = iit->second; - if (item->getUUID() != item_id) - { - LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; - validation_info->mWarnings["item_id_mismatch"]++; - warning_count++; - } - - const LLUUID& parent_id = item->getParentUUID(); - if (parent_id.isNull()) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + } + } + } + + // Update count of preferred types + LLFolderType::EType folder_type = cat->getPreferredType(); + bool cat_is_in_library = false; + LLUUID topmost_id; + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID()) + { + cat_is_in_library = true; + } + if (!cat_is_in_library) + { + if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) + { + ft_counts_under_root[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + else + { + ft_counts_elsewhere[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + } + } + + // Loop over all items and check + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLUUID& item_id = iit->first; + LLViewerInventoryItem *item = iit->second; + if (item->getUUID() != item_id) + { + LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + validation_info->mWarnings["item_id_mismatch"]++; + warning_count++; + } + + const LLUUID& parent_id = item->getParentUUID(); + if (parent_id.isNull()) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; orphaned_count++; - } - else - { - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(parent_id,cats,items); - if (!items) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() - << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + } + else + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!items) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; orphaned_count++; - } - else - { - bool found = false; - for (S32 i=0; i<items->size(); ++i) - { - if (items->at(i) == item) - { - found = true; - break; - } - } - if (!found) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() - << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i=0; i<items->size(); ++i) + { + if (items->at(i) == item) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - } - - } - // Link checking - if (item->getIsLinkType()) - { - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - LLViewerInventoryItem *target_item = getItem(target_id); - LLViewerInventoryCategory *target_cat = getCategory(target_id); - // Linked-to UUID should have back reference to this link. - if (!hasBacklinkInfo(link_id, target_id)) - { - LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() - << " missing backlink info at target_id " << target_id - << LL_ENDL; + } + } + + } + // Link checking + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; orphaned_count++; - } - // Links should have referents. - if (item->getActualType() == LLAssetType::AT_LINK && !target_item) - { - LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; orphaned_count++; - } - else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) - { - LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; orphaned_count++; - } - if (target_item && target_item->getIsLinkType()) - { - LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " - << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; - } - - // Links should not have backlinks. - std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); - if (range.first != range.second) - { - LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; - } - } - else - { - // Check the backlinks of a non-link item. - const LLUUID& target_id = item->getUUID(); - std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - const LLUUID& link_id = it->second; - LLViewerInventoryItem *link_item = getItem(link_id); - if (!link_item || !link_item->getIsLinkType()) - { - LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; - } - } - } - } - - // Check system folders - for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) - { - LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; - } - for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) - { - LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; - } - - static LLCachedControl<bool> fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); - static std::default_random_engine e{}; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } + } + else + { + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } + } + } + + // Check system folders + for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; + } + for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; + } + + static LLCachedControl<bool> fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); + static std::default_random_engine e{}; static std::uniform_int_distribution<> distrib(0, 1); - for (S32 ft=LLFolderType::FT_TEXTURE; ft<LLFolderType::FT_COUNT; ft++) - { - LLFolderType::EType folder_type = static_cast<LLFolderType::EType>(ft); - if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) - { - continue; - } - bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); - bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); - S32 count_under_root = ft_counts_under_root[folder_type]; - S32 count_elsewhere = ft_counts_elsewhere[folder_type]; - if (fake_system_folder_issues) - { - // Force all counts to be either 0 or 2, thus flagged as an error. - count_under_root = 2*distrib(e); - count_elsewhere = 2*distrib(e); - validation_info->mFatalQADebugMode = true; - } - if (is_singleton) - { - if (count_under_root==0) - { - LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; - // Need to create, if allowed. - if (is_automatic) - { - LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; - validation_info->mMissingRequiredSystemFolders.insert(folder_type); + for (S32 ft=LLFolderType::FT_TEXTURE; ft<LLFolderType::FT_COUNT; ft++) + { + LLFolderType::EType folder_type = static_cast<LLFolderType::EType>(ft); + if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) + { + continue; + } + bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); + bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); + S32 count_under_root = ft_counts_under_root[folder_type]; + S32 count_elsewhere = ft_counts_elsewhere[folder_type]; + if (fake_system_folder_issues) + { + // Force all counts to be either 0 or 2, thus flagged as an error. + count_under_root = 2*distrib(e); + count_elsewhere = 2*distrib(e); + validation_info->mFatalQADebugMode = true; + } + if (is_singleton) + { + if (count_under_root==0) + { + LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; + // Need to create, if allowed. + if (is_automatic) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; + validation_info->mMissingRequiredSystemFolders.insert(folder_type); fatal_errs++; - } - else - { - // Can create, and will when needed. - // (Not sure this is really a warning, but worth logging) - validation_info->mWarnings["missing_system_folder_can_create"]++; - warning_count++; - } - } - else if (count_under_root > 1) - { - validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); + } + else + { + // Can create, and will when needed. + // (Not sure this is really a warning, but worth logging) + validation_info->mWarnings["missing_system_folder_can_create"]++; + warning_count++; + } + } + else if (count_under_root > 1) + { + validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS // FT_MATERIAL might need to be automatic like the rest of upload folders @@ -4766,7 +4766,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { // It is a fatal problem or can lead to fatal problems for COF, // outfits, trash and other non-automatic folders. - validation_info->mFatalSystemDuplicate++; + validation_info->mFatalSystemDuplicate++; fatal_errs++; LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; } @@ -4775,74 +4775,74 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const // For automatic folders it's not a fatal issue and shouldn't // break inventory or other functionality further // Exception: FT_SETTINGS is not automatic, but only deserves a warning. - validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++; + validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++; warning_count++; LL_WARNS("Inventory") << "System folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; } - } - if (count_elsewhere > 0) - { - LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; - validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++; - warning_count++; - } - } - } - - - if (cat_lock > 0 || item_lock > 0) - { - LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " - << cat_lock << ", item arrays " << item_lock << LL_ENDL; - } - if (desc_unknown_count != 0) - { - LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; - } - if (version_unknown_count != 0) - { - LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; - } - - // FIXME need to fail login and tell user to retry, contact support if problem persists. - bool valid = (fatal_errs == 0); - LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL; - - validation_info->mFatalErrorCount = fatal_errs; - validation_info->mWarningCount = warning_count; + } + if (count_elsewhere > 0) + { + LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; + validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++; + warning_count++; + } + } + } + + + if (cat_lock > 0 || item_lock > 0) + { + LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " + << cat_lock << ", item arrays " << item_lock << LL_ENDL; + } + if (desc_unknown_count != 0) + { + LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + } + if (version_unknown_count != 0) + { + LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + } + + // FIXME need to fail login and tell user to retry, contact support if problem persists. + bool valid = (fatal_errs == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL; + + validation_info->mFatalErrorCount = fatal_errs; + validation_info->mWarningCount = warning_count; validation_info->mLoopCount = loop_count; validation_info->mOrphanedCount = orphaned_count; - return validation_info; + return validation_info; } // Provides a unix-style path from root, like "/My Inventory/Clothing/.../myshirt" std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const { - std::vector<std::string> path_elts; - std::map<LLUUID,bool> visited; - while (obj != NULL && !visited[obj->getUUID()]) - { - path_elts.push_back(obj->getName()); - // avoid infinite loop in the unlikely event of a cycle - visited[obj->getUUID()] = true; - obj = getObject(obj->getParentUUID()); - } - std::stringstream s; - std::string delim("/"); - std::reverse(path_elts.begin(), path_elts.end()); - std::string result = "/" + boost::algorithm::join(path_elts, delim); - return result; + std::vector<std::string> path_elts; + std::map<LLUUID,bool> visited; + while (obj != NULL && !visited[obj->getUUID()]) + { + path_elts.push_back(obj->getName()); + // avoid infinite loop in the unlikely event of a cycle + visited[obj->getUUID()] = true; + obj = getObject(obj->getParentUUID()); + } + std::stringstream s; + std::string delim("/"); + std::reverse(path_elts.begin(), path_elts.end()); + std::string result = "/" + boost::algorithm::join(path_elts, delim); + return result; } /* const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& path) { - vector<std::string> path_elts; - boost::algorithm::split(path_elts, path, boost::is_any_of("/")); - for(path_elts, auto e) - { - } + vector<std::string> path_elts; + boost::algorithm::split(path_elts, path, boost::is_any_of("/")); + for(path_elts, auto e) + { + } } */ @@ -4854,41 +4854,41 @@ const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& pat #if 0 BOOL decompress_file(const char* src_filename, const char* dst_filename) { - BOOL rv = FALSE; - gzFile src = NULL; - U8* buffer = NULL; - LLFILE* dst = NULL; - S32 bytes = 0; - const S32 DECOMPRESS_BUFFER_SIZE = 32000; - - // open the files - src = gzopen(src_filename, "rb"); - if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, "wb"); - if(!dst) goto err_decompress; - - // decompress. - buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; - - do - { - bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE); - if (bytes < 0) - { - goto err_decompress; - } - - fwrite(buffer, bytes, 1, dst); - } while(gzeof(src) == 0); - - // success - rv = TRUE; + BOOL rv = FALSE; + gzFile src = NULL; + U8* buffer = NULL; + LLFILE* dst = NULL; + S32 bytes = 0; + const S32 DECOMPRESS_BUFFER_SIZE = 32000; + + // open the files + src = gzopen(src_filename, "rb"); + if(!src) goto err_decompress; + dst = LLFile::fopen(dst_filename, "wb"); + if(!dst) goto err_decompress; + + // decompress. + buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; + + do + { + bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE); + if (bytes < 0) + { + goto err_decompress; + } + + fwrite(buffer, bytes, 1, dst); + } while(gzeof(src) == 0); + + // success + rv = TRUE; err_decompress: - if(src != NULL) gzclose(src); - if(buffer != NULL) delete[] buffer; - if(dst != NULL) fclose(dst); - return rv; + if(src != NULL) gzclose(src); + if(buffer != NULL) delete[] buffer; + if(dst != NULL) fclose(dst); + return rv; } #endif @@ -4898,163 +4898,163 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) ///---------------------------------------------------------------------------- LLInventoryModel::FetchItemHttpHandler::FetchItemHttpHandler(const LLSD & request_sd) - : LLCore::HttpHandler(), - mRequestSD(request_sd) + : LLCore::HttpHandler(), + mRequestSD(request_sd) {} LLInventoryModel::FetchItemHttpHandler::~FetchItemHttpHandler() {} void LLInventoryModel::FetchItemHttpHandler::onCompleted(LLCore::HttpHandle handle, - LLCore::HttpResponse * response) + LLCore::HttpResponse * response) { - do // Single-pass do-while used for common exit handling - { - LLCore::HttpStatus status(response->getStatus()); - // status = LLCore::HttpStatus(404); // Dev tool to force error handling - if (! status) - { - processFailure(status, response); - break; // Goto common exit - } - - LLCore::BufferArray * body(response->getBody()); - // body = NULL; // Dev tool to force error handling - if (! body || ! body->size()) - { - LL_WARNS(LOG_INV) << "Missing data in inventory item query." << LL_ENDL; - processFailure("HTTP response for inventory item query missing body", response); - break; // Goto common exit - } - - // body->write(0, "Garbage Response", 16); // Dev tool to force error handling - LLSD body_llsd; - if (! LLCoreHttpUtil::responseToLLSD(response, true, body_llsd)) - { - // INFOS-level logging will occur on the parsed failure - processFailure("HTTP response for inventory item query has malformed LLSD", response); - break; // Goto common exit - } - - // Expect top-level structure to be a map - // body_llsd = LLSD::emptyArray(); // Dev tool to force error handling - if (! body_llsd.isMap()) - { - processFailure("LLSD response for inventory item not a map", response); - break; // Goto common exit - } - - // Check for 200-with-error failures - // - // Original Responder-based serivce model didn't check for these errors. - // It may be more robust to ignore this condition. With aggregated requests, - // an error in one inventory item might take down the entire request. - // So if this instead broke up the aggregated items into single requests, - // maybe that would make progress. Or perhaps there's structured information - // that can tell us what went wrong. Need to dig into this and firm up - // the API. - // - // body_llsd["error"] = LLSD::emptyMap(); // Dev tool to force error handling - // body_llsd["error"]["identifier"] = "Development"; - // body_llsd["error"]["message"] = "You left development code in the viewer"; - if (body_llsd.has("error")) - { - processFailure("Inventory application error (200-with-error)", response); - break; // Goto common exit - } - - // Okay, process data if possible - processData(body_llsd, response); - } - while (false); + do // Single-pass do-while used for common exit handling + { + LLCore::HttpStatus status(response->getStatus()); + // status = LLCore::HttpStatus(404); // Dev tool to force error handling + if (! status) + { + processFailure(status, response); + break; // Goto common exit + } + + LLCore::BufferArray * body(response->getBody()); + // body = NULL; // Dev tool to force error handling + if (! body || ! body->size()) + { + LL_WARNS(LOG_INV) << "Missing data in inventory item query." << LL_ENDL; + processFailure("HTTP response for inventory item query missing body", response); + break; // Goto common exit + } + + // body->write(0, "Garbage Response", 16); // Dev tool to force error handling + LLSD body_llsd; + if (! LLCoreHttpUtil::responseToLLSD(response, true, body_llsd)) + { + // INFOS-level logging will occur on the parsed failure + processFailure("HTTP response for inventory item query has malformed LLSD", response); + break; // Goto common exit + } + + // Expect top-level structure to be a map + // body_llsd = LLSD::emptyArray(); // Dev tool to force error handling + if (! body_llsd.isMap()) + { + processFailure("LLSD response for inventory item not a map", response); + break; // Goto common exit + } + + // Check for 200-with-error failures + // + // Original Responder-based serivce model didn't check for these errors. + // It may be more robust to ignore this condition. With aggregated requests, + // an error in one inventory item might take down the entire request. + // So if this instead broke up the aggregated items into single requests, + // maybe that would make progress. Or perhaps there's structured information + // that can tell us what went wrong. Need to dig into this and firm up + // the API. + // + // body_llsd["error"] = LLSD::emptyMap(); // Dev tool to force error handling + // body_llsd["error"]["identifier"] = "Development"; + // body_llsd["error"]["message"] = "You left development code in the viewer"; + if (body_llsd.has("error")) + { + processFailure("Inventory application error (200-with-error)", response); + break; // Goto common exit + } + + // Okay, process data if possible + processData(body_llsd, response); + } + while (false); } void LLInventoryModel::FetchItemHttpHandler::processData(LLSD & content, LLCore::HttpResponse * response) { - start_new_inventory_observer(); + start_new_inventory_observer(); #if 0 - LLUUID agent_id; - agent_id = content["agent_id"].asUUID(); - if (agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id - << LL_ENDL; - return; - } + LLUUID agent_id; + agent_id = content["agent_id"].asUUID(); + if (agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return; + } #endif - - LLInventoryModel::item_array_t items; - LLInventoryModel::update_map_t update; - LLUUID folder_id; - LLSD content_items(content["items"]); - const S32 count(content_items.size()); - - // Does this loop ever execute more than once? - for (S32 i(0); i < count; ++i) - { - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - titem->unpackMessage(content_items[i]); - - LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " - << titem->getUUID() << LL_ENDL; - items.push_back(titem); - - // examine update for changes. - LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); - - if (itemp) - { - if (titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; - } - - if (folder_id.isNull()) - { - folder_id = titem->getParentUUID(); - } - } - - // as above, this loop never seems to loop more than once per call - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - gInventory.updateItem(*it); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); + + LLInventoryModel::item_array_t items; + LLInventoryModel::update_map_t update; + LLUUID folder_id; + LLSD content_items(content["items"]); + const S32 count(content_items.size()); + + // Does this loop ever execute more than once? + for (S32 i(0); i < count; ++i) + { + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + titem->unpackMessage(content_items[i]); + + LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + + // examine update for changes. + LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); + + if (itemp) + { + if (titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + + if (folder_id.isNull()) + { + folder_id = titem->getParentUUID(); + } + } + + // as above, this loop never seems to loop more than once per call + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + gInventory.updateItem(*it); + } + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); } void LLInventoryModel::FetchItemHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::HttpResponse * response) { - const std::string & ct(response->getContentType()); - LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" - << "[Status: " << status.toTerseString() << "]\n" - << "[Reason: " << status.toString() << "]\n" - << "[Content-type: " << ct << "]\n" - << "[Content (abridged): " - << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; - gInventory.notifyObservers(); + const std::string & ct(response->getContentType()); + LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" + << "[Status: " << status.toTerseString() << "]\n" + << "[Reason: " << status.toString() << "]\n" + << "[Content-type: " << ct << "]\n" + << "[Content (abridged): " + << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; + gInventory.notifyObservers(); } void LLInventoryModel::FetchItemHttpHandler::processFailure(const char * const reason, LLCore::HttpResponse * response) { - LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" - << "[Status: internal error]\n" - << "[Reason: " << reason << "]\n" - << "[Content (abridged): " - << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; - gInventory.notifyObservers(); + LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" + << "[Status: internal error]\n" + << "[Reason: " << reason << "]\n" + << "[Content (abridged): " + << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; + gInventory.notifyObservers(); } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 60edbfee88..a2a6210572 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lllocalbitmaps.cpp * @author Vaalith Jinn * @brief Local Bitmaps source @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -69,7 +69,7 @@ /*=======================================*/ /* Formal declarations, constants, etc. */ -/*=======================================*/ +/*=======================================*/ static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; static const BOOL LL_LOCAL_USE_MIPMAPS = true; @@ -80,57 +80,57 @@ static const S32 LL_LOCAL_UPDATE_RETRIES = 5; /*=======================================*/ /* LLLocalBitmap: unit class */ -/*=======================================*/ +/*=======================================*/ LLLocalBitmap::LLLocalBitmap(std::string filename) - : mFilename(filename) - , mShortName(gDirUtilp->getBaseFileName(filename, true)) - , mValid(false) - , mLastModified() - , mLinkStatus(LS_ON) - , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) + : mFilename(filename) + , mShortName(gDirUtilp->getBaseFileName(filename, true)) + , mValid(false) + , mLastModified() + , mLinkStatus(LS_ON) + , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) { - mTrackingID.generate(); - - /* extension */ - std::string temp_exten = gDirUtilp->getExtension(mFilename); - - if (temp_exten == "bmp") - { - mExtension = ET_IMG_BMP; - } - else if (temp_exten == "tga") - { - mExtension = ET_IMG_TGA; - } - else if (temp_exten == "jpg" || temp_exten == "jpeg") - { - mExtension = ET_IMG_JPG; - } - else if (temp_exten == "png") - { - mExtension = ET_IMG_PNG; - } - else - { - LL_WARNS() << "File of no valid extension given, local bitmap creation aborted." << "\n" - << "Filename: " << mFilename << LL_ENDL; - return; // no valid extension. - } - - /* next phase of unit creation is nearly the same as an update cycle. - we're running updateSelf as a special case with the optional UT_FIRSTUSE - which omits the parts associated with removing the outdated texture */ - mValid = updateSelf(UT_FIRSTUSE); + mTrackingID.generate(); + + /* extension */ + std::string temp_exten = gDirUtilp->getExtension(mFilename); + + if (temp_exten == "bmp") + { + mExtension = ET_IMG_BMP; + } + else if (temp_exten == "tga") + { + mExtension = ET_IMG_TGA; + } + else if (temp_exten == "jpg" || temp_exten == "jpeg") + { + mExtension = ET_IMG_JPG; + } + else if (temp_exten == "png") + { + mExtension = ET_IMG_PNG; + } + else + { + LL_WARNS() << "File of no valid extension given, local bitmap creation aborted." << "\n" + << "Filename: " << mFilename << LL_ENDL; + return; // no valid extension. + } + + /* next phase of unit creation is nearly the same as an update cycle. + we're running updateSelf as a special case with the optional UT_FIRSTUSE + which omits the parts associated with removing the outdated texture */ + mValid = updateSelf(UT_FIRSTUSE); } LLLocalBitmap::~LLLocalBitmap() { - // replace IDs with defaults, if set to do so. - if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 - { - replaceIDs(mWorldID, IMG_DEFAULT); - LLLocalBitmapMgr::getInstance()->doRebake(); - } + // replace IDs with defaults, if set to do so. + if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 + { + replaceIDs(mWorldID, IMG_DEFAULT); + LLLocalBitmapMgr::getInstance()->doRebake(); + } for (LLPointer<LLGLTFMaterial> &mat : mGLTFMaterialWithLocalTextures) { @@ -140,146 +140,146 @@ LLLocalBitmap::~LLLocalBitmap() mChangedSignal(getTrackingID(), getWorldID(), LLUUID()); mChangedSignal.disconnect_all_slots(); - // delete self from gimagelist - LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD); - gTextureList.deleteImage(image); + // delete self from gimagelist + LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD); + gTextureList.deleteImage(image); - if (image) - { - image->unref(); - } + if (image) + { + image->unref(); + } } /* accessors */ std::string LLLocalBitmap::getFilename() const { - return mFilename; + return mFilename; } std::string LLLocalBitmap::getShortName() const { - return mShortName; + return mShortName; } LLUUID LLLocalBitmap::getTrackingID() const { - return mTrackingID; + return mTrackingID; } LLUUID LLLocalBitmap::getWorldID() const { - return mWorldID; + return mWorldID; } bool LLLocalBitmap::getValid() const { - return mValid; + return mValid; } /* update functions */ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) { - bool updated = false; - - if (mLinkStatus == LS_ON) - { - // verifying that the file exists - if (gDirUtilp->fileExists(mFilename)) - { - // verifying that the file has indeed been modified + bool updated = false; + + if (mLinkStatus == LS_ON) + { + // verifying that the file exists + if (gDirUtilp->fileExists(mFilename)) + { + // verifying that the file has indeed been modified #ifndef LL_WINDOWS - const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); #else - const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); #endif - LLSD new_last_modified = asctime(localtime(&temp_time)); - - if (mLastModified.asString() != new_last_modified.asString()) - { - /* loading the image file and decoding it, here is a critical point which, - if fails, invalidates the whole update (or unit creation) process. */ - LLPointer<LLImageRaw> raw_image = new LLImageRaw(); - if (decodeBitmap(raw_image)) - { - // decode is successful, we can safely proceed. - LLUUID old_id = LLUUID::null; - if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) - { - old_id = mWorldID; - } - mWorldID.generate(); - mLastModified = new_last_modified; - - LLPointer<LLViewerFetchedTexture> texture = new LLViewerFetchedTexture - ("file://"+mFilename, FTT_LOCAL_FILE, mWorldID, LL_LOCAL_USE_MIPMAPS); - - texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image); - texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); - texture->ref(); - - gTextureList.addImage(texture, TEX_LIST_STANDARD); - - if (optional_firstupdate != UT_FIRSTUSE) - { - // seek out everything old_id uses and replace it with mWorldID - replaceIDs(old_id, mWorldID); - - // remove old_id from gimagelist - LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_STANDARD); - if (image != NULL) - { - gTextureList.deleteImage(image); - image->unref(); - } - } - - mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; - updated = true; - } - - // if decoding failed, we get here and it will attempt to decode it in the next cycles - // until mUpdateRetries runs out. this is done because some software lock the bitmap while writing to it - else - { - if (mUpdateRetries) - { - mUpdateRetries--; - } - else - { - LL_WARNS() << "During the update process the following file was found" << "\n" - << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" - << "Filename: " << mFilename << "\n" - << "Disabling further update attempts for this file." << LL_ENDL; - - LLSD notif_args; - notif_args["FNAME"] = mFilename; - notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; - LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); - - mLinkStatus = LS_BROKEN; - } - } - } - - } // end if file exists - - else - { - LL_WARNS() << "During the update process, the following file was not found." << "\n" - << "Filename: " << mFilename << "\n" - << "Disabling further update attempts for this file." << LL_ENDL; - - LLSD notif_args; - notif_args["FNAME"] = mFilename; - LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); - - mLinkStatus = LS_BROKEN; - } - } - - return updated; + LLSD new_last_modified = asctime(localtime(&temp_time)); + + if (mLastModified.asString() != new_last_modified.asString()) + { + /* loading the image file and decoding it, here is a critical point which, + if fails, invalidates the whole update (or unit creation) process. */ + LLPointer<LLImageRaw> raw_image = new LLImageRaw(); + if (decodeBitmap(raw_image)) + { + // decode is successful, we can safely proceed. + LLUUID old_id = LLUUID::null; + if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) + { + old_id = mWorldID; + } + mWorldID.generate(); + mLastModified = new_last_modified; + + LLPointer<LLViewerFetchedTexture> texture = new LLViewerFetchedTexture + ("file://"+mFilename, FTT_LOCAL_FILE, mWorldID, LL_LOCAL_USE_MIPMAPS); + + texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image); + texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); + texture->ref(); + + gTextureList.addImage(texture, TEX_LIST_STANDARD); + + if (optional_firstupdate != UT_FIRSTUSE) + { + // seek out everything old_id uses and replace it with mWorldID + replaceIDs(old_id, mWorldID); + + // remove old_id from gimagelist + LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_STANDARD); + if (image != NULL) + { + gTextureList.deleteImage(image); + image->unref(); + } + } + + mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; + updated = true; + } + + // if decoding failed, we get here and it will attempt to decode it in the next cycles + // until mUpdateRetries runs out. this is done because some software lock the bitmap while writing to it + else + { + if (mUpdateRetries) + { + mUpdateRetries--; + } + else + { + LL_WARNS() << "During the update process the following file was found" << "\n" + << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; + LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + } + + } // end if file exists + + else + { + LL_WARNS() << "During the update process, the following file was not found." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + + return updated; } boost::signals2::connection LLLocalBitmap::setChangedCallback(const LLLocalTextureCallback& cb) @@ -319,114 +319,114 @@ void LLLocalBitmap::addGLTFMaterial(LLGLTFMaterial* mat) bool LLLocalBitmap::decodeBitmap(LLPointer<LLImageRaw> rawimg) { - bool decode_successful = false; - - switch (mExtension) - { - case ET_IMG_BMP: - { - LLPointer<LLImageBMP> bmp_image = new LLImageBMP; - if (bmp_image->load(mFilename) && bmp_image->decode(rawimg, 0.0f)) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - case ET_IMG_TGA: - { - LLPointer<LLImageTGA> tga_image = new LLImageTGA; - if ((tga_image->load(mFilename) && tga_image->decode(rawimg)) - && ((tga_image->getComponents() == 3) || (tga_image->getComponents() == 4))) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - case ET_IMG_JPG: - { - LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG; - if (jpeg_image->load(mFilename) && jpeg_image->decode(rawimg, 0.0f)) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - case ET_IMG_PNG: - { - LLPointer<LLImagePNG> png_image = new LLImagePNG; - if (png_image->load(mFilename) && png_image->decode(rawimg, 0.0f)) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - default: - { - // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens - // accessing mFilename and any other object properties might very well crash the viewer. - // getting here should be impossible, or there's been a pretty serious bug. - - LL_WARNS() << "During a decode attempt, the following local bitmap had no properly assigned extension." << LL_ENDL; - LL_WARNS() << "Filename: " << mFilename << LL_ENDL; - LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL; - mLinkStatus = LS_BROKEN; - } - } - - return decode_successful; + bool decode_successful = false; + + switch (mExtension) + { + case ET_IMG_BMP: + { + LLPointer<LLImageBMP> bmp_image = new LLImageBMP; + if (bmp_image->load(mFilename) && bmp_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_TGA: + { + LLPointer<LLImageTGA> tga_image = new LLImageTGA; + if ((tga_image->load(mFilename) && tga_image->decode(rawimg)) + && ((tga_image->getComponents() == 3) || (tga_image->getComponents() == 4))) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_JPG: + { + LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG; + if (jpeg_image->load(mFilename) && jpeg_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_PNG: + { + LLPointer<LLImagePNG> png_image = new LLImagePNG; + if (png_image->load(mFilename) && png_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + default: + { + // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens + // accessing mFilename and any other object properties might very well crash the viewer. + // getting here should be impossible, or there's been a pretty serious bug. + + LL_WARNS() << "During a decode attempt, the following local bitmap had no properly assigned extension." << LL_ENDL; + LL_WARNS() << "Filename: " << mFilename << LL_ENDL; + LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL; + mLinkStatus = LS_BROKEN; + } + } + + return decode_successful; } void LLLocalBitmap::replaceIDs(const LLUUID& old_id, LLUUID new_id) { - // checking for misuse. - if (old_id == new_id) - { - LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" - << "Texture UUID: " << old_id.asString() << LL_ENDL; - return; - } + // checking for misuse. + if (old_id == new_id) + { + LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" + << "Texture UUID: " << old_id.asString() << LL_ENDL; + return; + } mChangedSignal(getTrackingID(), old_id, new_id); - // processing updates per channel; makes the process scalable. - // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. - updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); - updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); - updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); - - updateUserVolumes(old_id, new_id, LLRender::LIGHT_TEX); - updateUserVolumes(old_id, new_id, LLRender::SCULPT_TEX); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something? - - // default safeguard image for layers - if( new_id == IMG_DEFAULT ) - { - new_id = IMG_DEFAULT_AVATAR; - } - - /* It doesn't actually update all of those, it merely checks if any of them - contain the referenced ID and if so, updates. */ - updateUserLayers(old_id, new_id, LLWearableType::WT_ALPHA); - updateUserLayers(old_id, new_id, LLWearableType::WT_EYES); - updateUserLayers(old_id, new_id, LLWearableType::WT_GLOVES); - updateUserLayers(old_id, new_id, LLWearableType::WT_JACKET); - updateUserLayers(old_id, new_id, LLWearableType::WT_PANTS); - updateUserLayers(old_id, new_id, LLWearableType::WT_SHIRT); - updateUserLayers(old_id, new_id, LLWearableType::WT_SHOES); - updateUserLayers(old_id, new_id, LLWearableType::WT_SKIN); - updateUserLayers(old_id, new_id, LLWearableType::WT_SKIRT); - updateUserLayers(old_id, new_id, LLWearableType::WT_SOCKS); - updateUserLayers(old_id, new_id, LLWearableType::WT_TATTOO); - updateUserLayers(old_id, new_id, LLWearableType::WT_UNIVERSAL); - updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS); - updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT); + // processing updates per channel; makes the process scalable. + // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. + updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); + updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); + updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); + + updateUserVolumes(old_id, new_id, LLRender::LIGHT_TEX); + updateUserVolumes(old_id, new_id, LLRender::SCULPT_TEX); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something? + + // default safeguard image for layers + if( new_id == IMG_DEFAULT ) + { + new_id = IMG_DEFAULT_AVATAR; + } + + /* It doesn't actually update all of those, it merely checks if any of them + contain the referenced ID and if so, updates. */ + updateUserLayers(old_id, new_id, LLWearableType::WT_ALPHA); + updateUserLayers(old_id, new_id, LLWearableType::WT_EYES); + updateUserLayers(old_id, new_id, LLWearableType::WT_GLOVES); + updateUserLayers(old_id, new_id, LLWearableType::WT_JACKET); + updateUserLayers(old_id, new_id, LLWearableType::WT_PANTS); + updateUserLayers(old_id, new_id, LLWearableType::WT_SHIRT); + updateUserLayers(old_id, new_id, LLWearableType::WT_SHOES); + updateUserLayers(old_id, new_id, LLWearableType::WT_SKIN); + updateUserLayers(old_id, new_id, LLWearableType::WT_SKIRT); + updateUserLayers(old_id, new_id, LLWearableType::WT_SOCKS); + updateUserLayers(old_id, new_id, LLWearableType::WT_TATTOO); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNIVERSAL); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT); updateGLTFMaterials(old_id, new_id); } @@ -435,195 +435,195 @@ void LLLocalBitmap::replaceIDs(const LLUUID& old_id, LLUUID new_id) // in order to prevent multiple sendTEUpdate calls per object during updateUserPrims std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id, U32 channel) { - std::vector<LLViewerObject*> obj_list; - LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); - - for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) - { - // getting an object from a face - LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; - - if(face_to_object) - { - LLViewerObject* affected_object = face_to_object->getViewerObject(); - - if(affected_object) - { - - // we have an object, we'll take it's UUID and compare it to - // whatever we already have in the returnable object list. - // if there is a match - we do not add (to prevent duplicates) - LLUUID mainlist_obj_id = affected_object->getID(); - bool add_object = true; - - // begin looking for duplicates - std::vector<LLViewerObject*>::iterator objlist_iter = obj_list.begin(); - for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) - { - LLViewerObject* obj = *objlist_iter; - if (obj->getID() == mainlist_obj_id) - { - add_object = false; // duplicate found. - } - } - // end looking for duplicates - - if(add_object) - { - obj_list.push_back(affected_object); - } - - } - - } - - } // end of face-iterating for() - - return obj_list; + std::vector<LLViewerObject*> obj_list; + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); + + for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) + { + // getting an object from a face + LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; + + if(face_to_object) + { + LLViewerObject* affected_object = face_to_object->getViewerObject(); + + if(affected_object) + { + + // we have an object, we'll take it's UUID and compare it to + // whatever we already have in the returnable object list. + // if there is a match - we do not add (to prevent duplicates) + LLUUID mainlist_obj_id = affected_object->getID(); + bool add_object = true; + + // begin looking for duplicates + std::vector<LLViewerObject*>::iterator objlist_iter = obj_list.begin(); + for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) + { + LLViewerObject* obj = *objlist_iter; + if (obj->getID() == mainlist_obj_id) + { + add_object = false; // duplicate found. + } + } + // end looking for duplicates + + if(add_object) + { + obj_list.push_back(affected_object); + } + + } + + } + + } // end of face-iterating for() + + return obj_list; } void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel) { - std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id, channel); - - for(std::vector<LLViewerObject*>::iterator object_iterator = objectlist.begin(); - object_iterator != objectlist.end(); object_iterator++) - { - LLViewerObject* object = *object_iterator; - - if(object) - { - bool update_tex = false; - bool update_mat = false; - S32 num_faces = object->getNumFaces(); - - for (U8 face_iter = 0; face_iter < num_faces; face_iter++) - { - if (object->mDrawable) - { - LLFace* face = object->mDrawable->getFace(face_iter); - if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) - { - // these things differ per channel, unless there already is a universal - // texture setting function to setTE that takes channel as a param? - // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap - switch(channel) - { - case LLRender::DIFFUSE_MAP: - { + std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id, channel); + + for(std::vector<LLViewerObject*>::iterator object_iterator = objectlist.begin(); + object_iterator != objectlist.end(); object_iterator++) + { + LLViewerObject* object = *object_iterator; + + if(object) + { + bool update_tex = false; + bool update_mat = false; + S32 num_faces = object->getNumFaces(); + + for (U8 face_iter = 0; face_iter < num_faces; face_iter++) + { + if (object->mDrawable) + { + LLFace* face = object->mDrawable->getFace(face_iter); + if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) + { + // these things differ per channel, unless there already is a universal + // texture setting function to setTE that takes channel as a param? + // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap + switch(channel) + { + case LLRender::DIFFUSE_MAP: + { object->setTETexture(face_iter, new_id); update_tex = true; - break; - } - - case LLRender::NORMAL_MAP: - { - object->setTENormalMap(face_iter, new_id); - update_mat = true; - update_tex = true; break; - } + } - case LLRender::SPECULAR_MAP: - { - object->setTESpecularMap(face_iter, new_id); + case LLRender::NORMAL_MAP: + { + object->setTENormalMap(face_iter, new_id); update_mat = true; - update_tex = true; + update_tex = true; break; - } - } - // end switch - - } - } - } - - if (update_tex) - { - object->sendTEUpdate(); - } - - if (update_mat) - { + } + + case LLRender::SPECULAR_MAP: + { + object->setTESpecularMap(face_iter, new_id); + update_mat = true; + update_tex = true; + break; + } + } + // end switch + + } + } + } + + if (update_tex) + { + object->sendTEUpdate(); + } + + if (update_mat) + { object->mDrawable->getVOVolume()->faceMappingChanged(); - } - } - } + } + } + } } void LLLocalBitmap::updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel) { - LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); - for (U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(channel); volume_iter++) - { - LLVOVolume* volobjp = (*old_texture->getVolumeList(channel))[volume_iter]; - switch (channel) - { - case LLRender::LIGHT_TEX: - { - if (volobjp->getLightTextureID() == old_id) - { - volobjp->setLightTextureID(new_id); - } - break; - } - case LLRender::SCULPT_TEX: - { - LLViewerObject* object = (LLViewerObject*)volobjp; - - if (object) - { - if (object->isSculpted() && object->getVolume() && - object->getVolume()->getParams().getSculptID() == old_id) - { - LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLSculptParams new_params(*old_params); - new_params.setSculptTexture(new_id, (*old_params).getSculptType()); - object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE); - } - } - } - } - } + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); + for (U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(channel); volume_iter++) + { + LLVOVolume* volobjp = (*old_texture->getVolumeList(channel))[volume_iter]; + switch (channel) + { + case LLRender::LIGHT_TEX: + { + if (volobjp->getLightTextureID() == old_id) + { + volobjp->setLightTextureID(new_id); + } + break; + } + case LLRender::SCULPT_TEX: + { + LLViewerObject* object = (LLViewerObject*)volobjp; + + if (object) + { + if (object->isSculpted() && object->getVolume() && + object->getVolume()->getParams().getSculptID() == old_id) + { + LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams new_params(*old_params); + new_params.setSculptTexture(new_id, (*old_params).getSculptType()); + object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE); + } + } + } + } + } } void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type) { - U32 count = gAgentWearables.getWearableCount(type); - for(U32 wearable_iter = 0; wearable_iter < count; wearable_iter++) - { - LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_iter); - if (wearable) - { - std::vector<LLLocalTextureObject*> texture_list = wearable->getLocalTextureListSeq(); - for(std::vector<LLLocalTextureObject*>::iterator texture_iter = texture_list.begin(); - texture_iter != texture_list.end(); texture_iter++) - { - LLLocalTextureObject* lto = *texture_iter; - - if (lto && lto->getID() == old_id) - { - U32 local_texlayer_index = 0; /* can't keep that as static const, gives errors, so i'm leaving this var here */ - LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind = - lto->getTexLayer(local_texlayer_index)->getTexLayerSet()->getBakedTexIndex(); - - LLAvatarAppearanceDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind); - if (reg_texind != LLAvatarAppearanceDefines::TEX_NUM_INDICES) - { - U32 index; - if (gAgentWearables.getWearableIndex(wearable,index)) - { - gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); - gAgentAvatarp->wearableUpdated(type); - /* telling the manager to rebake once update cycle is fully done */ - LLLocalBitmapMgr::getInstance()->setNeedsRebake(); - } - } - - } - } - } - } + U32 count = gAgentWearables.getWearableCount(type); + for(U32 wearable_iter = 0; wearable_iter < count; wearable_iter++) + { + LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_iter); + if (wearable) + { + std::vector<LLLocalTextureObject*> texture_list = wearable->getLocalTextureListSeq(); + for(std::vector<LLLocalTextureObject*>::iterator texture_iter = texture_list.begin(); + texture_iter != texture_list.end(); texture_iter++) + { + LLLocalTextureObject* lto = *texture_iter; + + if (lto && lto->getID() == old_id) + { + U32 local_texlayer_index = 0; /* can't keep that as static const, gives errors, so i'm leaving this var here */ + LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind = + lto->getTexLayer(local_texlayer_index)->getTexLayerSet()->getBakedTexIndex(); + + LLAvatarAppearanceDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind); + if (reg_texind != LLAvatarAppearanceDefines::TEX_NUM_INDICES) + { + U32 index; + if (gAgentWearables.getWearableIndex(wearable,index)) + { + gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); + gAgentAvatarp->wearableUpdated(type); + /* telling the manager to rebake once update cycle is fully done */ + LLLocalBitmapMgr::getInstance()->setNeedsRebake(); + } + } + + } + } + } + } } void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) @@ -688,304 +688,304 @@ void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) } LLAvatarAppearanceDefines::ETextureIndex LLLocalBitmap::getTexIndex( - LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind) + LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind) { - LLAvatarAppearanceDefines::ETextureIndex result = LLAvatarAppearanceDefines::TEX_NUM_INDICES; // using as a default/fail return. - - switch(type) - { - case LLWearableType::WT_ALPHA: - { - switch(baked_texind) - { - case LLAvatarAppearanceDefines::BAKED_EYES: - { - result = LLAvatarAppearanceDefines::TEX_EYES_ALPHA; - break; - } - - case LLAvatarAppearanceDefines::BAKED_HAIR: - { - result = LLAvatarAppearanceDefines::TEX_HAIR_ALPHA; - break; - } - - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_ALPHA; - break; - } - - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_ALPHA; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_ALPHA; - break; - } - - default: - { - break; - } - - } - break; - - } - - case LLWearableType::WT_EYES: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_EYES) - { - result = LLAvatarAppearanceDefines::TEX_EYES_IRIS; - } - - break; - } - - case LLWearableType::WT_GLOVES: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_GLOVES; - } - - break; - } - - case LLWearableType::WT_JACKET: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_JACKET; - } - else if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_JACKET; - } - - break; - } - - case LLWearableType::WT_PANTS: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_PANTS; - } - - break; - } - - case LLWearableType::WT_SHIRT: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_SHIRT; - } - - break; - } - - case LLWearableType::WT_SHOES: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_SHOES; - } - - break; - } - - case LLWearableType::WT_SKIN: - { - switch(baked_texind) - { - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_BODYPAINT; - break; - } - - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_BODYPAINT; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_BODYPAINT; - break; - } - - default: - { - break; - } - - } - break; - } - - case LLWearableType::WT_SKIRT: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_SKIRT) - { - result = LLAvatarAppearanceDefines::TEX_SKIRT; - } - - break; - } - - case LLWearableType::WT_SOCKS: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_SOCKS; - } - - break; - } - - case LLWearableType::WT_TATTOO: - { - switch (baked_texind) - { - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_TATTOO; - break; - } - - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_TATTOO; - break; - } - default: - { - break; - } - } - break; - - } - case LLWearableType::WT_UNIVERSAL: - { - switch (baked_texind) - { - - case LLAvatarAppearanceDefines::BAKED_SKIRT: - { - result = LLAvatarAppearanceDefines::TEX_SKIRT_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_EYES: - { - result = LLAvatarAppearanceDefines::TEX_EYES_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_HAIR: - { - result = LLAvatarAppearanceDefines::TEX_HAIR_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_LEFT_ARM: - { - result = LLAvatarAppearanceDefines::TEX_LEFT_ARM_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_LEFT_LEG: - { - result = LLAvatarAppearanceDefines::TEX_LEFT_LEG_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_AUX1: - { - result = LLAvatarAppearanceDefines::TEX_AUX1_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_AUX2: - { - result = LLAvatarAppearanceDefines::TEX_AUX2_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_AUX3: - { - result = LLAvatarAppearanceDefines::TEX_AUX3_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_UNIVERSAL_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_UNIVERSAL_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_UNIVERSAL_TATTOO; - break; - } - - - default: - { - break; - } - - } - break; - } - - case LLWearableType::WT_UNDERPANTS: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_UNDERPANTS; - } - - break; - } - - case LLWearableType::WT_UNDERSHIRT: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_UNDERSHIRT; - } - - break; - } - - default: - { - LL_WARNS() << "Unknown wearable type: " << (int)type << "\n" - << "Baked Texture Index: " << (int)baked_texind << "\n" - << "Filename: " << mFilename << "\n" - << "TrackingID: " << mTrackingID << "\n" - << "InworldID: " << mWorldID << LL_ENDL; - } - - } - return result; + LLAvatarAppearanceDefines::ETextureIndex result = LLAvatarAppearanceDefines::TEX_NUM_INDICES; // using as a default/fail return. + + switch(type) + { + case LLWearableType::WT_ALPHA: + { + switch(baked_texind) + { + case LLAvatarAppearanceDefines::BAKED_EYES: + { + result = LLAvatarAppearanceDefines::TEX_EYES_ALPHA; + break; + } + + case LLAvatarAppearanceDefines::BAKED_HAIR: + { + result = LLAvatarAppearanceDefines::TEX_HAIR_ALPHA; + break; + } + + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_ALPHA; + break; + } + + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_ALPHA; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_ALPHA; + break; + } + + default: + { + break; + } + + } + break; + + } + + case LLWearableType::WT_EYES: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_EYES) + { + result = LLAvatarAppearanceDefines::TEX_EYES_IRIS; + } + + break; + } + + case LLWearableType::WT_GLOVES: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_GLOVES; + } + + break; + } + + case LLWearableType::WT_JACKET: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_JACKET; + } + else if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_JACKET; + } + + break; + } + + case LLWearableType::WT_PANTS: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_PANTS; + } + + break; + } + + case LLWearableType::WT_SHIRT: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_SHIRT; + } + + break; + } + + case LLWearableType::WT_SHOES: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_SHOES; + } + + break; + } + + case LLWearableType::WT_SKIN: + { + switch(baked_texind) + { + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_BODYPAINT; + break; + } + + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_BODYPAINT; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_BODYPAINT; + break; + } + + default: + { + break; + } + + } + break; + } + + case LLWearableType::WT_SKIRT: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_SKIRT) + { + result = LLAvatarAppearanceDefines::TEX_SKIRT; + } + + break; + } + + case LLWearableType::WT_SOCKS: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_SOCKS; + } + + break; + } + + case LLWearableType::WT_TATTOO: + { + switch (baked_texind) + { + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_TATTOO; + break; + } + + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_TATTOO; + break; + } + default: + { + break; + } + } + break; + + } + case LLWearableType::WT_UNIVERSAL: + { + switch (baked_texind) + { + + case LLAvatarAppearanceDefines::BAKED_SKIRT: + { + result = LLAvatarAppearanceDefines::TEX_SKIRT_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_EYES: + { + result = LLAvatarAppearanceDefines::TEX_EYES_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_HAIR: + { + result = LLAvatarAppearanceDefines::TEX_HAIR_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_LEFT_ARM: + { + result = LLAvatarAppearanceDefines::TEX_LEFT_ARM_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_LEFT_LEG: + { + result = LLAvatarAppearanceDefines::TEX_LEFT_LEG_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_AUX1: + { + result = LLAvatarAppearanceDefines::TEX_AUX1_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_AUX2: + { + result = LLAvatarAppearanceDefines::TEX_AUX2_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_AUX3: + { + result = LLAvatarAppearanceDefines::TEX_AUX3_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_UNIVERSAL_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_UNIVERSAL_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_UNIVERSAL_TATTOO; + break; + } + + + default: + { + break; + } + + } + break; + } + + case LLWearableType::WT_UNDERPANTS: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_UNDERPANTS; + } + + break; + } + + case LLWearableType::WT_UNDERSHIRT: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_UNDERSHIRT; + } + + break; + } + + default: + { + LL_WARNS() << "Unknown wearable type: " << (int)type << "\n" + << "Baked Texture Index: " << (int)baked_texind << "\n" + << "Filename: " << mFilename << "\n" + << "TrackingID: " << mTrackingID << "\n" + << "InworldID: " << mWorldID << LL_ENDL; + } + + } + return result; } /*=======================================*/ /* LLLocalBitmapTimer: timer class */ -/*=======================================*/ +/*=======================================*/ LLLocalBitmapTimer::LLLocalBitmapTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT) { } @@ -996,23 +996,23 @@ LLLocalBitmapTimer::~LLLocalBitmapTimer() void LLLocalBitmapTimer::startTimer() { - start(); + start(); } void LLLocalBitmapTimer::stopTimer() { - stop(); + stop(); } bool LLLocalBitmapTimer::tick() { - LLLocalBitmapMgr::getInstance()->doUpdates(); - return false; + LLLocalBitmapMgr::getInstance()->doUpdates(); + return false; } /*=======================================*/ /* LLLocalBitmapMgr: manager class */ -/*=======================================*/ +/*=======================================*/ LLLocalBitmapMgr::LLLocalBitmapMgr() { } @@ -1070,12 +1070,12 @@ LLUUID LLLocalBitmapMgr::addUnit(const std::string& filename) bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) { - std::string exten = gDirUtilp->getExtension(filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - std::string mImageLoadError; - LLImageDimensionsInfo image_info; - if (!image_info.load(filename,codec)) - { + std::string exten = gDirUtilp->getExtension(filename); + U32 codec = LLImageBase::getCodecFromExtension(exten); + std::string mImageLoadError; + LLImageDimensionsInfo image_info; + if (!image_info.load(filename,codec)) + { LLSD args; args["NAME"] = gDirUtilp->getBaseFileName(filename); if (!image_info.getWarningName().empty()) @@ -1083,69 +1083,69 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) args["REASON"] = LLTrans::getString(image_info.getWarningName()); } LLNotificationsUtil::add("CannotUploadTexture", args); - return false; - } + return false; + } - S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); - S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); + S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); - 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); - mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); + 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); + mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); - LLSD notif_args; - notif_args["REASON"] = mImageLoadError; + LLSD notif_args; + notif_args["REASON"] = mImageLoadError; notif_args["NAME"] = gDirUtilp->getBaseFileName(filename); - LLNotificationsUtil::add("CannotUploadTexture", notif_args); + LLNotificationsUtil::add("CannotUploadTexture", notif_args); - return false; - } + return false; + } - return true; + return true; } void LLLocalBitmapMgr::delUnit(LLUUID tracking_id) { - if (!mBitmapList.empty()) - { - std::vector<LLLocalBitmap*> to_delete; - for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { /* finding which ones we want deleted and making a separate list */ - LLLocalBitmap* unit = *iter; - if (unit->getTrackingID() == tracking_id) - { - to_delete.push_back(unit); - } - } - - for(std::vector<LLLocalBitmap*>::iterator del_iter = to_delete.begin(); - del_iter != to_delete.end(); del_iter++) - { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ - LLLocalBitmap* unit = *del_iter; - mBitmapList.remove(unit); - delete unit; - unit = NULL; - } - } + if (!mBitmapList.empty()) + { + std::vector<LLLocalBitmap*> to_delete; + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { /* finding which ones we want deleted and making a separate list */ + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + to_delete.push_back(unit); + } + } + + for(std::vector<LLLocalBitmap*>::iterator del_iter = to_delete.begin(); + del_iter != to_delete.end(); del_iter++) + { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ + LLLocalBitmap* unit = *del_iter; + mBitmapList.remove(unit); + delete unit; + unit = NULL; + } + } } LLUUID LLLocalBitmapMgr::getWorldID(const LLUUID &tracking_id) const { - LLUUID world_id = LLUUID::null; - - for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { - LLLocalBitmap* unit = *iter; - if (unit->getTrackingID() == tracking_id) - { - world_id = unit->getWorldID(); - } - } - - return world_id; + LLUUID world_id = LLUUID::null; + + for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + world_id = unit->getWorldID(); + } + } + + return world_id; } bool LLLocalBitmapMgr::isLocal(const LLUUID &world_id) const @@ -1163,18 +1163,18 @@ bool LLLocalBitmapMgr::isLocal(const LLUUID &world_id) const std::string LLLocalBitmapMgr::getFilename(const LLUUID &tracking_id) const { - std::string filename = ""; - - for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { - LLLocalBitmap* unit = *iter; - if (unit->getTrackingID() == tracking_id) - { - filename = unit->getFilename(); - } - } - - return filename; + std::string filename = ""; + + for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + filename = unit->getFilename(); + } + } + + return filename; } boost::signals2::connection LLLocalBitmapMgr::setOnChangedCallback(const LLUUID tracking_id, const LLLocalBitmap::LLLocalTextureCallback &cb) @@ -1205,18 +1205,18 @@ void LLLocalBitmapMgr::associateGLTFMaterial(const LLUUID tracking_id, LLGLTFMat void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) { - if (ctrl) - { + if (ctrl) + { std::string icon_name = LLInventoryIcon::getIconName( LLAssetType::AT_TEXTURE, LLInventoryType::IT_NONE); - if (!mBitmapList.empty()) - { - for (local_list_iter iter = mBitmapList.begin(); - iter != mBitmapList.end(); iter++) - { - LLSD element; + if (!mBitmapList.empty()) + { + for (local_list_iter iter = mBitmapList.begin(); + iter != mBitmapList.end(); iter++) + { + LLSD element; element["columns"][0]["column"] = "icon"; element["columns"][0]["type"] = "icon"; @@ -1231,39 +1231,39 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) data["type"] = (S32)LLAssetType::AT_TEXTURE; element["value"] = data; - ctrl->addElement(element); - } - } - } + ctrl->addElement(element); + } + } + } } void LLLocalBitmapMgr::doUpdates() { - // preventing theoretical overlap in cases with huge number of loaded images. - mTimer.stopTimer(); - mNeedsRebake = false; + // preventing theoretical overlap in cases with huge number of loaded images. + mTimer.stopTimer(); + mNeedsRebake = false; - for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { - (*iter)->updateSelf(); - } + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + (*iter)->updateSelf(); + } - doRebake(); - mTimer.startTimer(); + doRebake(); + mTimer.startTimer(); } void LLLocalBitmapMgr::setNeedsRebake() { - mNeedsRebake = true; + mNeedsRebake = true; } void LLLocalBitmapMgr::doRebake() { /* separated that from doUpdates to insure a rebake can be called separately during deletion */ - if (mNeedsRebake) - { - gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); - mNeedsRebake = false; - } + if (mNeedsRebake) + { + gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); + mNeedsRebake = false; + } } diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 96a39a3d66..84811ee14a 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -1,4 +1,4 @@ -/** +/** * @file lllocalbitmaps.h * @author Vaalith Jinn * @brief Local Bitmaps header @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,25 +40,25 @@ class LLGLTFMaterial; class LLLocalBitmap { - public: /* main */ - LLLocalBitmap(std::string filename); - ~LLLocalBitmap(); - - public: /* accessors */ - std::string getFilename() const; - std::string getShortName() const; - LLUUID getTrackingID() const; - LLUUID getWorldID() const; - bool getValid() const; - - public: /* self update public section */ - enum EUpdateType - { - UT_FIRSTUSE, - UT_REGUPDATE - }; - - bool updateSelf(EUpdateType = UT_REGUPDATE); + public: /* main */ + LLLocalBitmap(std::string filename); + ~LLLocalBitmap(); + + public: /* accessors */ + std::string getFilename() const; + std::string getShortName() const; + LLUUID getTrackingID() const; + LLUUID getWorldID() const; + bool getValid() const; + + public: /* self update public section */ + enum EUpdateType + { + UT_FIRSTUSE, + UT_REGUPDATE + }; + + bool updateSelf(EUpdateType = UT_REGUPDATE); typedef boost::signals2::signal<void(const LLUUID& tracking_id, const LLUUID& old_id, @@ -67,42 +67,42 @@ class LLLocalBitmap boost::signals2::connection setChangedCallback(const LLLocalTextureCallback& cb); void addGLTFMaterial(LLGLTFMaterial* mat); - private: /* self update private section */ - bool decodeBitmap(LLPointer<LLImageRaw> raw); + private: /* self update private section */ + bool decodeBitmap(LLPointer<LLImageRaw> raw); void replaceIDs(const LLUUID &old_id, LLUUID new_id); - std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id, U32 channel); - void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); - void updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel); - void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type); + std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id, U32 channel); + void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); + void updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel); + void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type); void updateGLTFMaterials(LLUUID old_id, LLUUID new_id); - LLAvatarAppearanceDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind); - - private: /* private enums */ - enum ELinkStatus - { - LS_ON, - LS_BROKEN, - }; - - enum EExtension - { - ET_IMG_BMP, - ET_IMG_TGA, - ET_IMG_JPG, - ET_IMG_PNG - }; - - private: /* members */ - std::string mFilename; - std::string mShortName; - LLUUID mTrackingID; - LLUUID mWorldID; - bool mValid; - LLSD mLastModified; - EExtension mExtension; - ELinkStatus mLinkStatus; - S32 mUpdateRetries; - LLLocalTextureChangedSignal mChangedSignal; + LLAvatarAppearanceDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind); + + private: /* private enums */ + enum ELinkStatus + { + LS_ON, + LS_BROKEN, + }; + + enum EExtension + { + ET_IMG_BMP, + ET_IMG_TGA, + ET_IMG_JPG, + ET_IMG_PNG + }; + + private: /* members */ + std::string mFilename; + std::string mShortName; + LLUUID mTrackingID; + LLUUID mWorldID; + bool mValid; + LLSD mLastModified; + EExtension mExtension; + ELinkStatus mLinkStatus; + S32 mUpdateRetries; + LLLocalTextureChangedSignal mChangedSignal; // Store a list of accosiated materials // Might be a better idea to hold this in LLGLTFMaterialList @@ -113,43 +113,43 @@ class LLLocalBitmap class LLLocalBitmapTimer : public LLEventTimer { - public: - LLLocalBitmapTimer(); - ~LLLocalBitmapTimer(); + public: + LLLocalBitmapTimer(); + ~LLLocalBitmapTimer(); - public: - void startTimer(); - void stopTimer(); - bool tick() override; + public: + void startTimer(); + void stopTimer(); + bool tick() override; }; class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr> { - LLSINGLETON(LLLocalBitmapMgr); - ~LLLocalBitmapMgr(); + LLSINGLETON(LLLocalBitmapMgr); + ~LLLocalBitmapMgr(); public: bool addUnit(const std::vector<std::string>& filenames); LLUUID addUnit(const std::string& filename); - void delUnit(LLUUID tracking_id); - bool checkTextureDimensions(std::string filename); + void delUnit(LLUUID tracking_id); + bool checkTextureDimensions(std::string filename); - LLUUID getWorldID(const LLUUID &tracking_id) const; + LLUUID getWorldID(const LLUUID &tracking_id) const; bool isLocal(const LLUUID& world_id) const; - std::string getFilename(const LLUUID &tracking_id) const; + std::string getFilename(const LLUUID &tracking_id) const; boost::signals2::connection setOnChangedCallback(const LLUUID tracking_id, const LLLocalBitmap::LLLocalTextureCallback& cb); void associateGLTFMaterial(const LLUUID tracking_id, LLGLTFMaterial* mat); - void feedScrollList(LLScrollListCtrl* ctrl); - void doUpdates(); - void setNeedsRebake(); - void doRebake(); - + void feedScrollList(LLScrollListCtrl* ctrl); + void doUpdates(); + void setNeedsRebake(); + void doRebake(); + private: - std::list<LLLocalBitmap*> mBitmapList; - LLLocalBitmapTimer mTimer; - bool mNeedsRebake; - typedef std::list<LLLocalBitmap*>::iterator local_list_iter; + std::list<LLLocalBitmap*> mBitmapList; + LLLocalBitmapTimer mTimer; + bool mNeedsRebake; + typedef std::list<LLLocalBitmap*>::iterator local_list_iter; typedef std::list<LLLocalBitmap*>::const_iterator local_list_citer; }; diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index ff54d48602..9c2d1bb287 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -1,25 +1,25 @@ -/** +/** * @file lllocalrendermaterials.h * @brief Local GLTF materials header * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,11 +43,11 @@ public: /* main */ virtual ~LLLocalGLTFMaterial(); public: /* accessors */ - std::string getFilename() const; - std::string getShortName() const; - LLUUID getTrackingID() const; - LLUUID getWorldID() const; - S32 getIndexInFile() const; + std::string getFilename() const; + std::string getShortName() const; + LLUUID getTrackingID() const; + LLUUID getWorldID() const; + S32 getIndexInFile() const; public: bool updateSelf(); diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index 5bf587292d..828c0a0747 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmediadataclient.cpp * @brief class for queueing up requests for media data * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,39 +46,39 @@ // // When making a request -// - obtain the "overall interest score" of the object. -// This would be the sum of the impls' interest scores. -// - put the request onto a queue sorted by this score -// (highest score at the front of the queue) -// - On a timer, once a second, pull off the head of the queue and send -// the request. +// - obtain the "overall interest score" of the object. +// This would be the sum of the impls' interest scores. +// - put the request onto a queue sorted by this score +// (highest score at the front of the queue) +// - On a timer, once a second, pull off the head of the queue and send +// the request. // - Any request that gets a 503 still goes through the retry logic // /*************************************************************************************************************** - What's up with this queueing code? + What's up with this queueing code? - First, a bit of background: + First, a bit of background: - Media on a prim was added into the system in the Viewer 2.0 timeframe. In order to avoid changing the - network format of objects, an unused field in the object (the "MediaURL" string) was repurposed to - indicate that the object had media data, and also hold a sequence number and the UUID of the agent - who last updated the data. The actual media data for objects is accessed via the "ObjectMedia" capability. - Due to concerns about sim performance, requests to this capability are rate-limited to 5 requests every - 5 seconds per agent. + Media on a prim was added into the system in the Viewer 2.0 timeframe. In order to avoid changing the + network format of objects, an unused field in the object (the "MediaURL" string) was repurposed to + indicate that the object had media data, and also hold a sequence number and the UUID of the agent + who last updated the data. The actual media data for objects is accessed via the "ObjectMedia" capability. + Due to concerns about sim performance, requests to this capability are rate-limited to 5 requests every + 5 seconds per agent. - The initial implementation of LLMediaDataClient used a single queue to manage requests to the "ObjectMedia" cap. - Requests to the cap were queued so that objects closer to the avatar were loaded in first, since they were most - likely to be the ones the media performance manager would load. + The initial implementation of LLMediaDataClient used a single queue to manage requests to the "ObjectMedia" cap. + Requests to the cap were queued so that objects closer to the avatar were loaded in first, since they were most + likely to be the ones the media performance manager would load. - This worked in some cases, but we found that it was possible for a scripted object that constantly updated its - media data to starve other objects, since the same queue contained both requests to load previously unseen media - data and requests to fetch media data in response to object updates. + This worked in some cases, but we found that it was possible for a scripted object that constantly updated its + media data to starve other objects, since the same queue contained both requests to load previously unseen media + data and requests to fetch media data in response to object updates. - The solution for this we came up with was to have two queues. The sorted queue contains requests to fetch media - data for objects that don't have it yet, and the round-robin queue contains requests to update media data for - objects that have already completed their initial load. When both queues are non-empty, the code ping-pongs - between them so that updates can't completely block initial load-in. + The solution for this we came up with was to have two queues. The sorted queue contains requests to fetch media + data for objects that don't have it yet, and the round-robin queue contains requests to update media data for + objects that have already completed their initial load. When both queues are non-empty, the code ping-pongs + between them so that updates can't completely block initial load-in. **************************************************************************************************************/ // @@ -98,7 +98,7 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q); //========================================================================= /// Uniary Predicate for matching requests in collections by either the request /// or by UUID -/// +/// class PredicateMatchRequest { public: @@ -121,7 +121,7 @@ PredicateMatchRequest::PredicateMatchRequest(const LLMediaDataClient::Request::p mMatchType(matchType), mId() {} - + PredicateMatchRequest::PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType) : mRequest(), mMatchType(matchType), @@ -145,7 +145,7 @@ bool PredicateMatchRequest::operator()(const LLMediaDataClient::Request::ptr_t & } //========================================================================= -/// +/// template <typename T> void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred) { @@ -169,7 +169,7 @@ void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred) // ////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay, +LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay, U32 max_retries, U32 max_sorted_queue_size, U32 max_round_robin_queue_size): mQueueTimerDelay(queue_timer_delay), mRetryTimerDelay(retry_timer_delay), @@ -187,12 +187,12 @@ LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_dela LLMediaDataClient::~LLMediaDataClient() { - stopQueueTimer(); + stopQueueTimer(); } bool LLMediaDataClient::isEmpty() const { - return mQueue.empty(); + return mQueue.empty(); } bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) @@ -203,114 +203,114 @@ bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) return true; if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end()) return true; - - return false; + + return false; } void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) { - LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; PredicateMatchRequest upred(object->getID()); mark_dead_and_remove_if(mQueue, upred); mark_dead_and_remove_if(mUnQueuedRequests, upred); } -void LLMediaDataClient::startQueueTimer() +void LLMediaDataClient::startQueueTimer() { - if (! mQueueTimerIsRunning) - { - LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL; - // LLEventTimer automagically takes care of the lifetime of this object - new QueueTimer(mQueueTimerDelay, this); - } - else { - LL_DEBUGS("LLMediaDataClient") << "queue timer is already running" << LL_ENDL; - } + if (! mQueueTimerIsRunning) + { + LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL; + // LLEventTimer automagically takes care of the lifetime of this object + new QueueTimer(mQueueTimerDelay, this); + } + else { + LL_DEBUGS("LLMediaDataClient") << "queue timer is already running" << LL_ENDL; + } } void LLMediaDataClient::stopQueueTimer() { - mQueueTimerIsRunning = false; + mQueueTimerIsRunning = false; } bool LLMediaDataClient::processQueueTimer() { if (isDoneProcessing()) - return true; + return true; + + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is: " << mQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mQueue << LL_ENDL; - LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is: " << mQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mQueue << LL_ENDL; - - serviceQueue(); + serviceQueue(); serviceHttp(); - LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is: " << mQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mQueue << LL_ENDL; - + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is: " << mQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mQueue << LL_ENDL; + return isDoneProcessing(); } LLMediaDataClient::Request::ptr_t LLMediaDataClient::dequeue() { - Request::ptr_t request; - request_queue_t *queue_p = getQueue(); - - if (queue_p->empty()) - { - LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL; - } - else - { - request = queue_p->front(); - - if(canServiceRequest(request)) - { - // We will be returning this request, so remove it from the queue. - queue_p->pop_front(); - } - else - { - // Don't return this request -- it's not ready to be serviced. + Request::ptr_t request; + request_queue_t *queue_p = getQueue(); + + if (queue_p->empty()) + { + LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL; + } + else + { + request = queue_p->front(); + + if(canServiceRequest(request)) + { + // We will be returning this request, so remove it from the queue. + queue_p->pop_front(); + } + else + { + // Don't return this request -- it's not ready to be serviced. request.reset(); - } - } + } + } - return request; + return request; } void LLMediaDataClient::pushBack(Request::ptr_t request) { - request_queue_t *queue_p = getQueue(); - queue_p->push_front(request); + request_queue_t *queue_p = getQueue(); + queue_p->push_front(request); } void LLMediaDataClient::trackRequest(Request::ptr_t request) { - request_set_t::iterator iter = mUnQueuedRequests.find(request); - - if(iter != mUnQueuedRequests.end()) - { - LL_WARNS("LLMediaDataClient") << "Tracking already tracked request: " << *request << LL_ENDL; - } - else - { - mUnQueuedRequests.insert(request); - } + request_set_t::iterator iter = mUnQueuedRequests.find(request); + + if(iter != mUnQueuedRequests.end()) + { + LL_WARNS("LLMediaDataClient") << "Tracking already tracked request: " << *request << LL_ENDL; + } + else + { + mUnQueuedRequests.insert(request); + } } void LLMediaDataClient::stopTrackingRequest(Request::ptr_t request) { - request_set_t::iterator iter = mUnQueuedRequests.find(request); - - if (iter != mUnQueuedRequests.end()) - { - mUnQueuedRequests.erase(iter); - } - else - { - LL_WARNS("LLMediaDataClient") << "Removing an untracked request: " << *request << LL_ENDL; - } + request_set_t::iterator iter = mUnQueuedRequests.find(request); + + if (iter != mUnQueuedRequests.end()) + { + mUnQueuedRequests.erase(iter); + } + else + { + LL_WARNS("LLMediaDataClient") << "Removing an untracked request: " << *request << LL_ENDL; + } } bool LLMediaDataClient::isDoneProcessing() const @@ -320,39 +320,39 @@ bool LLMediaDataClient::isDoneProcessing() const void LLMediaDataClient::serviceQueue() -{ - // Peel one off of the items from the queue and execute it - Request::ptr_t request; - - do - { - request = dequeue(); - - if(!request) - { - // Queue is empty. - return; - } - - if(request->isDead()) - { - LL_INFOS("LLMediaDataClient") << "Skipping dead request " << *request << LL_ENDL; - continue; - } - - } while(false); - - // try to send the HTTP message to the cap url - std::string url = request->getCapability(); - if (!url.empty()) - { - const LLSD &sd_payload = request->getPayload(); - LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL; - - // Add this request to the non-queued tracking list - trackRequest(request); - - // and make the post +{ + // Peel one off of the items from the queue and execute it + Request::ptr_t request; + + do + { + request = dequeue(); + + if(!request) + { + // Queue is empty. + return; + } + + if(request->isDead()) + { + LL_INFOS("LLMediaDataClient") << "Skipping dead request " << *request << LL_ENDL; + continue; + } + + } while(false); + + // try to send the HTTP message to the cap url + std::string url = request->getCapability(); + if (!url.empty()) + { + const LLSD &sd_payload = request->getPayload(); + LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL; + + // Add this request to the non-queued tracking list + trackRequest(request); + + // and make the post LLCore::HttpHandler::ptr_t handler = request->createHandler(); LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, mHttpPolicy, url, sd_payload, mHttpOpts, mHttpHeaders, handler); @@ -363,25 +363,25 @@ void LLMediaDataClient::serviceQueue() LL_WARNS("LLMediaDataClient") << "'" << url << "' request POST failed. Reason " << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL; } - } - else - { - // Cap url doesn't exist. - - if(request->getRetryCount() < mMaxNumRetries) - { - LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " (empty cap url), will retry." << LL_ENDL; - // Put this request back at the head of its queue, and retry next time the queue timer fires. - request->incRetryCount(); - pushBack(request); - } - else - { - // This request has exceeded its maximum retry count. It will be dropped. - LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL; - } - - } + } + else + { + // Cap url doesn't exist. + + if(request->getRetryCount() < mMaxNumRetries) + { + LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " (empty cap url), will retry." << LL_ENDL; + // Put this request back at the head of its queue, and retry next time the queue timer fires. + request->incRetryCount(); + pushBack(request); + } + else + { + // This request has exceeded its maximum retry count. It will be dropped. + LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL; + } + + } } void LLMediaDataClient::serviceHttp() @@ -392,16 +392,16 @@ void LLMediaDataClient::serviceHttp() // dump the queue std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q) { - int i = 0; - LLMediaDataClient::request_queue_t::const_iterator iter = q.begin(); - LLMediaDataClient::request_queue_t::const_iterator end = q.end(); - while (iter != end) - { - s << "\t" << i << "]: " << (*iter)->getID().asString() << "(" << (*iter)->getObject()->getMediaInterest() << ")"; - iter++; - i++; - } - return s; + int i = 0; + LLMediaDataClient::request_queue_t::const_iterator iter = q.begin(); + LLMediaDataClient::request_queue_t::const_iterator end = q.end(); + while (iter != end) + { + s << "\t" << i << "]: " << (*iter)->getID().asString() << "(" << (*iter)->getObject()->getMediaInterest() << ")"; + iter++; + i++; + } + return s; } ////////////////////////////////////////////////////////////////////////////////////// @@ -414,27 +414,27 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc) : LLEventTimer(time), mMDC(mdc) { - mMDC->setIsRunning(true); + mMDC->setIsRunning(true); } // virtual bool LLMediaDataClient::QueueTimer::tick() { - bool result = TRUE; + bool result = TRUE; - if (!mMDC.isNull()) - { - result = mMDC->processQueueTimer(); - - if(result) - { - // This timer won't fire again. - mMDC->setIsRunning(false); - mMDC = NULL; - } - } + if (!mMDC.isNull()) + { + result = mMDC->processQueueTimer(); - return result; + if(result) + { + // This timer won't fire again. + mMDC->setIsRunning(false); + mMDC = NULL; + } + } + + return result; } @@ -447,29 +447,29 @@ bool LLMediaDataClient::QueueTimer::tick() LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request) : LLEventTimer(time), mRequest(request) { - mRequest->startTracking(); + mRequest->startTracking(); } // virtual bool LLMediaDataClient::RetryTimer::tick() { - mRequest->stopTracking(); + mRequest->stopTracking(); - if(mRequest->isDead()) - { - LL_INFOS("LLMediaDataClient") << "RetryTimer fired for dead request: " << *mRequest << ", aborting." << LL_ENDL; - } - else - { - LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *mRequest << ", retrying." << LL_ENDL; - mRequest->reEnqueue(); - } + if(mRequest->isDead()) + { + LL_INFOS("LLMediaDataClient") << "RetryTimer fired for dead request: " << *mRequest << ", aborting." << LL_ENDL; + } + else + { + LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *mRequest << ", retrying." << LL_ENDL; + mRequest->reEnqueue(); + } - // Release the ref to the request. - mRequest.reset(); + // Release the ref to the request. + mRequest.reset(); - // Don't fire again - return true; + // Don't fire again + return true; } @@ -481,124 +481,124 @@ bool LLMediaDataClient::RetryTimer::tick() /*static*/U32 LLMediaDataClient::Request::sNum = 0; LLMediaDataClient::Request::Request(Type in_type, - LLMediaDataClientObject *obj, - LLMediaDataClient *mdc, - S32 face) + LLMediaDataClientObject *obj, + LLMediaDataClient *mdc, + S32 face) : mType(in_type), mObject(obj), - mNum(++sNum), + mNum(++sNum), mRetryCount(0), mMDC(mdc), mScore((F64)0.0), mFace(face) { - mObjectID = mObject->getID(); + mObjectID = mObject->getID(); } const char *LLMediaDataClient::Request::getCapName() const { - if(mMDC) - return mMDC->getCapabilityName(); - - return ""; + if(mMDC) + return mMDC->getCapabilityName(); + + return ""; } std::string LLMediaDataClient::Request::getCapability() const { - if(mMDC) - { - return getObject()->getCapabilityUrl(getCapName()); - } - - return ""; + if(mMDC) + { + return getObject()->getCapabilityUrl(getCapName()); + } + + return ""; } const char *LLMediaDataClient::Request::getTypeAsString() const { - Type t = getType(); - switch (t) - { - case GET: - return "GET"; - break; - case UPDATE: - return "UPDATE"; - break; - case NAVIGATE: - return "NAVIGATE"; - break; - case ANY: - return "ANY"; - break; - } - return ""; + Type t = getType(); + switch (t) + { + case GET: + return "GET"; + break; + case UPDATE: + return "UPDATE"; + break; + case NAVIGATE: + return "NAVIGATE"; + break; + case ANY: + return "ANY"; + break; + } + return ""; } void LLMediaDataClient::Request::reEnqueue() { - if(mMDC) - { - mMDC->enqueue(shared_from_this()); - } + if(mMDC) + { + mMDC->enqueue(shared_from_this()); + } } F32 LLMediaDataClient::Request::getRetryTimerDelay() const { - if(mMDC) - return mMDC->mRetryTimerDelay; - - return 0.0f; + if(mMDC) + return mMDC->mRetryTimerDelay; + + return 0.0f; } U32 LLMediaDataClient::Request::getMaxNumRetries() const { - if(mMDC) - return mMDC->mMaxNumRetries; - - return 0; + if(mMDC) + return mMDC->mMaxNumRetries; + + return 0; } void LLMediaDataClient::Request::updateScore() -{ - F64 tmp = mObject->getMediaInterest(); - if (tmp != mScore) - { - LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL; - mScore = tmp; - } +{ + F64 tmp = mObject->getMediaInterest(); + if (tmp != mScore) + { + LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL; + mScore = tmp; + } } - -void LLMediaDataClient::Request::markDead() -{ - mMDC = NULL; + +void LLMediaDataClient::Request::markDead() +{ + mMDC = NULL; } -bool LLMediaDataClient::Request::isDead() -{ - return ((mMDC == NULL) || mObject->isDead()); +bool LLMediaDataClient::Request::isDead() +{ + return ((mMDC == NULL) || mObject->isDead()); } -void LLMediaDataClient::Request::startTracking() -{ - if(mMDC) +void LLMediaDataClient::Request::startTracking() +{ + if(mMDC) mMDC->trackRequest(shared_from_this()); } -void LLMediaDataClient::Request::stopTracking() -{ - if(mMDC) +void LLMediaDataClient::Request::stopTracking() +{ + if(mMDC) mMDC->stopTrackingRequest(shared_from_this()); } std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) { - s << "request: num=" << r.getNum() - << " type=" << r.getTypeAsString() - << " ID=" << r.getID() - << " face=" << r.getFace() - << " #retries=" << r.getRetryCount(); - return s; + s << "request: num=" << r.getNum() + << " type=" << r.getTypeAsString() + << " ID=" << r.getID() + << " face=" << r.getFace() + << " #retries=" << r.getRetryCount(); + return s; } //======================================================================== @@ -634,7 +634,7 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo mRequest->incRetryCount(); - if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) + if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) { LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; @@ -642,9 +642,9 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo // InstanceTracker<> and LLEventTimer) new RetryTimer(F32(retry_timeout/*secs*/), mRequest); } - else + else { - LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " + LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; } } @@ -664,223 +664,223 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object) { - // Create a get request and put it in the queue. - enqueue(Request::ptr_t(new RequestGet(object, this))); + // Create a get request and put it in the queue. + enqueue(Request::ptr_t(new RequestGet(object, this))); } -const char *LLObjectMediaDataClient::getCapabilityName() const +const char *LLObjectMediaDataClient::getCapabilityName() const { - return "ObjectMedia"; + return "ObjectMedia"; } LLObjectMediaDataClient::request_queue_t *LLObjectMediaDataClient::getQueue() { - return (mCurrentQueueIsTheSortedQueue) ? &mQueue : &mRoundRobinQueue; + return (mCurrentQueueIsTheSortedQueue) ? &mQueue : &mRoundRobinQueue; } void LLObjectMediaDataClient::sortQueue() { - if(!mQueue.empty()) - { - // score all elements in the sorted queue. - for(request_queue_t::iterator iter = mQueue.begin(); iter != mQueue.end(); iter++) - { - (*iter)->updateScore(); - } - - // Re-sort the list... - mQueue.sort(compareRequestScores); - - // ...then cull items over the max - U32 size = mQueue.size(); - if (size > mMaxSortedQueueSize) - { - U32 num_to_cull = (size - mMaxSortedQueueSize); - LL_INFOS_ONCE("LLMediaDataClient") << "sorted queue MAXED OUT! Culling " - << num_to_cull << " items" << LL_ENDL; - while (num_to_cull-- > 0) - { - mQueue.back()->markDead(); - mQueue.pop_back(); - } - } - } - + if(!mQueue.empty()) + { + // score all elements in the sorted queue. + for(request_queue_t::iterator iter = mQueue.begin(); iter != mQueue.end(); iter++) + { + (*iter)->updateScore(); + } + + // Re-sort the list... + mQueue.sort(compareRequestScores); + + // ...then cull items over the max + U32 size = mQueue.size(); + if (size > mMaxSortedQueueSize) + { + U32 num_to_cull = (size - mMaxSortedQueueSize); + LL_INFOS_ONCE("LLMediaDataClient") << "sorted queue MAXED OUT! Culling " + << num_to_cull << " items" << LL_ENDL; + while (num_to_cull-- > 0) + { + mQueue.back()->markDead(); + mQueue.pop_back(); + } + } + } + } // static bool LLObjectMediaDataClient::compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2) { - if (!o2) return true; - if (!o1) return false; - return ( o1->getScore() > o2->getScore() ); + if (!o2) return true; + if (!o1) return false; + return ( o1->getScore() > o2->getScore() ); } void LLObjectMediaDataClient::enqueue(Request::ptr_t request) { - static LLCachedControl<bool> audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); - if (!audio_streaming_enabled) - { - LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; - return; - } - - if(request->isDead()) - { - LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL; - return; - } - - // Invariants: - // new requests always go into the sorted queue. - // - - bool is_new = request->isNew(); - - if(!is_new && (request->getType() == Request::GET)) - { - // For GET requests that are not new, if a matching request is already in the round robin queue, - // in flight, or being retried, leave it at its current position. + static LLCachedControl<bool> audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); + if (!audio_streaming_enabled) + { + LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; + return; + } + + if(request->isDead()) + { + LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL; + return; + } + + // Invariants: + // new requests always go into the sorted queue. + // + + bool is_new = request->isNew(); + + if(!is_new && (request->getType() == Request::GET)) + { + // For GET requests that are not new, if a matching request is already in the round robin queue, + // in flight, or being retried, leave it at its current position. PredicateMatchRequest upred(request->getID(), Request::GET); request_queue_t::iterator iter = std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), upred); request_set_t::iterator iter2 = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); - if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) ) - { - LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; - - return; - } - } - - // TODO: should an UPDATE cause pending GET requests for the same object to be removed from the queue? - // IF the update will cause an object update message to be sent out at some point in the future, it probably should. - - // Remove any existing requests of this type for this object + if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) ) + { + LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; + + return; + } + } + + // TODO: should an UPDATE cause pending GET requests for the same object to be removed from the queue? + // IF the update will cause an object update message to be sent out at some point in the future, it probably should. + + // Remove any existing requests of this type for this object PredicateMatchRequest upred(request->getID(), request->getType()); mark_dead_and_remove_if(mQueue, upred); mark_dead_and_remove_if(mRoundRobinQueue, upred); mark_dead_and_remove_if(mUnQueuedRequests, upred); - if (is_new) - { - LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL; - - mQueue.push_back(request); - - LL_DEBUGS("LLMediaDataClientQueue") << "SORTED queue:" << mQueue << LL_ENDL; - } - else - { - if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize) - { - LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL; - LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL; - return; - } - - LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL; - // Push the request on the pending queue - mRoundRobinQueue.push_back(request); - - LL_DEBUGS("LLMediaDataClientQueue") << "RR queue:" << mRoundRobinQueue << LL_ENDL; - } - // Start the timer if not already running - startQueueTimer(); -} - -bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request) -{ - if(mCurrentQueueIsTheSortedQueue) - { - if(!request->getObject()->isInterestingEnough()) - { - LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL; - return false; - } - } - - return true; + if (is_new) + { + LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL; + + mQueue.push_back(request); + + LL_DEBUGS("LLMediaDataClientQueue") << "SORTED queue:" << mQueue << LL_ENDL; + } + else + { + if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize) + { + LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL; + return; + } + + LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL; + // Push the request on the pending queue + mRoundRobinQueue.push_back(request); + + LL_DEBUGS("LLMediaDataClientQueue") << "RR queue:" << mRoundRobinQueue << LL_ENDL; + } + // Start the timer if not already running + startQueueTimer(); +} + +bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request) +{ + if(mCurrentQueueIsTheSortedQueue) + { + if(!request->getObject()->isInterestingEnough()) + { + LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL; + return false; + } + } + + return true; }; void LLObjectMediaDataClient::swapCurrentQueue() { - // Swap - mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; - // If its empty, swap back - if (getQueue()->empty()) - { - mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; - } + // Swap + mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; + // If its empty, swap back + if (getQueue()->empty()) + { + mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; + } } bool LLObjectMediaDataClient::isEmpty() const { - return mQueue.empty() && mRoundRobinQueue.empty(); + return mQueue.empty() && mRoundRobinQueue.empty(); } bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) { - // First, call parent impl. - if(LLMediaDataClient::isInQueue(object)) - return true; + // First, call parent impl. + if(LLMediaDataClient::isInQueue(object)) + return true; if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end()) return true; - return false; + return false; } void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) { - // First, call parent impl. - LLMediaDataClient::removeFromQueue(object); - + // First, call parent impl. + LLMediaDataClient::removeFromQueue(object); + mark_dead_and_remove_if(mRoundRobinQueue, PredicateMatchRequest(object->getID())); } bool LLObjectMediaDataClient::processQueueTimer() { if (isDoneProcessing()) - return true; - - LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is: " << mQueue.size() - << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; + return true; -// purgeDeadRequests(); + LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is: " << mQueue.size() + << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; - sortQueue(); +// purgeDeadRequests(); - LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is: " << mQueue << LL_ENDL; - - serviceQueue(); + sortQueue(); + + LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is: " << mQueue << LL_ENDL; + + serviceQueue(); serviceHttp(); - swapCurrentQueue(); - - LL_DEBUGS("LLMediaDataClient") << "finished, SORTED queue size is: " << mQueue.size() - << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; - + swapCurrentQueue(); + + LL_DEBUGS("LLMediaDataClient") << "finished, SORTED queue size is: " << mQueue.size() + << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; + return isDoneProcessing(); } LLObjectMediaDataClient::RequestGet::RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): - LLMediaDataClient::Request(LLMediaDataClient::Request::GET, obj, mdc) + LLMediaDataClient::Request(LLMediaDataClient::Request::GET, obj, mdc) { } LLSD LLObjectMediaDataClient::RequestGet::getPayload() const { - LLSD result; - result["verb"] = "GET"; - result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); - - return result; + LLSD result; + result["verb"] = "GET"; + result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); + + return result; } LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestGet::createHandler() @@ -891,37 +891,37 @@ LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestGet::createHandler() void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object) { - // Create an update request and put it in the queue. - enqueue(Request::ptr_t(new RequestUpdate(object, this))); + // Create an update request and put it in the queue. + enqueue(Request::ptr_t(new RequestUpdate(object, this))); } LLObjectMediaDataClient::RequestUpdate::RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): - LLMediaDataClient::Request(LLMediaDataClient::Request::UPDATE, obj, mdc) + LLMediaDataClient::Request(LLMediaDataClient::Request::UPDATE, obj, mdc) { } LLSD LLObjectMediaDataClient::RequestUpdate::getPayload() const { - LLSD result; - result["verb"] = "UPDATE"; - result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); + LLSD result; + result["verb"] = "UPDATE"; + result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); + + LLSD object_media_data; + int i = 0; + int end = mObject->getMediaDataCount(); + for ( ; i < end ; ++i) + { + object_media_data.append(mObject->getMediaDataLLSD(i)); + } + + result[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; - LLSD object_media_data; - int i = 0; - int end = mObject->getMediaDataCount(); - for ( ; i < end ; ++i) - { - object_media_data.append(mObject->getMediaDataLLSD(i)); - } - - result[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; - - return result; + return result; } LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestUpdate::createHandler() { - // This just uses the base class's responder. + // This just uses the base class's responder. return LLCore::HttpHandler::ptr_t(new LLMediaDataClient::Handler(shared_from_this())); } @@ -947,16 +947,16 @@ void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response if (content.has("error")) { const LLSD &error = content["error"]; - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; // XXX Warn user? } - else + else { // Check the data const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; - if (object_id != getRequest()->getObject()->getID()) + if (object_id != getRequest()->getObject()->getID()) { // NOT good, wrong object id!! LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; @@ -978,87 +978,87 @@ void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response // ////////////////////////////////////////////////////////////////////////////////////// -const char *LLObjectMediaNavigateClient::getCapabilityName() const +const char *LLObjectMediaNavigateClient::getCapabilityName() const { - return "ObjectMediaNavigate"; + return "ObjectMediaNavigate"; } void LLObjectMediaNavigateClient::enqueue(Request::ptr_t request) { - static LLCachedControl<bool> audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); - if (!audio_streaming_enabled) - { - LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; - return; - } - - if(request->isDead()) - { - LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL; - return; - } - + static LLCachedControl<bool> audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); + if (!audio_streaming_enabled) + { + LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; + return; + } + + if(request->isDead()) + { + LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL; + return; + } + PredicateMatchRequest upred(request); - // If there's already a matching request in the queue, remove it. + // If there's already a matching request in the queue, remove it. request_queue_t::iterator iter = std::find_if(mQueue.begin(), mQueue.end(), upred); - if(iter != mQueue.end()) - { - LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; - mQueue.erase(iter); - } - else - { + if(iter != mQueue.end()) + { + LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; + mQueue.erase(iter); + } + else + { request_set_t::iterator set_iter = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); - if(set_iter != mUnQueuedRequests.end()) - { - LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; - mUnQueuedRequests.erase(set_iter); - } - } + if(set_iter != mUnQueuedRequests.end()) + { + LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; + mUnQueuedRequests.erase(set_iter); + } + } #if 0 - // Sadly, this doesn't work. It ends up creating a race condition when the user navigates and then hits the "back" button - // where the navigate-back appears to be spurious and doesn't get broadcast. - if(request->getObject()->isCurrentMediaUrl(request->getFace(), request->getURL())) - { - // This navigate request is trying to send the face to the current URL. Drop it. - LL_DEBUGS("LLMediaDataClient") << "dropping spurious request " << (*request) << LL_ENDL; - } - else + // Sadly, this doesn't work. It ends up creating a race condition when the user navigates and then hits the "back" button + // where the navigate-back appears to be spurious and doesn't get broadcast. + if(request->getObject()->isCurrentMediaUrl(request->getFace(), request->getURL())) + { + // This navigate request is trying to send the face to the current URL. Drop it. + LL_DEBUGS("LLMediaDataClient") << "dropping spurious request " << (*request) << LL_ENDL; + } + else #endif - { - LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL; - mQueue.push_back(request); - - // Start the timer if not already running - startQueueTimer(); - } + { + LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL; + mQueue.push_back(request); + + // Start the timer if not already running + startQueueTimer(); + } } void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url) { -// LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL; - - // Create a get request and put it in the queue. - enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url))); +// LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL; + + // Create a get request and put it in the queue. + enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url))); } LLObjectMediaNavigateClient::RequestNavigate::RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url): - LLMediaDataClient::Request(LLMediaDataClient::Request::NAVIGATE, obj, mdc, (S32)texture_index), - mURL(url) + LLMediaDataClient::Request(LLMediaDataClient::Request::NAVIGATE, obj, mdc, (S32)texture_index), + mURL(url) { } LLSD LLObjectMediaNavigateClient::RequestNavigate::getPayload() const { - LLSD result; - result[LLTextureEntry::OBJECT_ID_KEY] = getID(); - result[LLMediaEntry::CURRENT_URL_KEY] = mURL; - result[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)getFace(); - - return result; + LLSD result; + result[LLTextureEntry::OBJECT_ID_KEY] = getID(); + result[LLMediaEntry::CURRENT_URL_KEY] = mURL; + result[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)getFace(); + + return result; } LLCore::HttpHandler::ptr_t LLObjectMediaNavigateClient::RequestNavigate::createHandler() @@ -1121,7 +1121,7 @@ void LLObjectMediaNavigateClient::Handler::mediaNavigateBounceBack() { LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating or denied." << LL_ENDL; const LLSD &payload = getRequest()->getPayload(); - + // bounce the face back getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 428e85b976..a5f20e51db 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -1,25 +1,25 @@ -/** +/** * @file llmediadataclient.h * @brief class for queueing up requests to the media service * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,35 +41,35 @@ class LLMediaDataClientObject : public LLRefCount { public: - // Get the number of media data items - virtual U8 getMediaDataCount() const = 0; - // Get the media data at index, as an LLSD - virtual LLSD getMediaDataLLSD(U8 index) const = 0; - // Return true if the current URL for the face in the media data matches the specified URL. - virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const = 0; - // Get this object's UUID - virtual LLUUID getID() const = 0; - // Navigate back to previous URL - virtual void mediaNavigateBounceBack(U8 index) = 0; - // Does this object have media? - virtual bool hasMedia() const = 0; - // Update the object's media data to the given array - virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0; - // Return the total "interest" of the media (on-screen area) - virtual F64 getMediaInterest() const = 0; - // Return the given cap url - virtual std::string getCapabilityUrl(const std::string &name) const = 0; - // Return whether the object has been marked dead - virtual bool isDead() const = 0; - // Returns a media version number for the object - virtual U32 getMediaVersion() const = 0; - // Returns whether the object is "interesting enough" to fetch - virtual bool isInterestingEnough() const = 0; - // Returns whether we've seen this object yet or not - virtual bool isNew() const = 0; - - // smart pointer - typedef LLPointer<LLMediaDataClientObject> ptr_t; + // Get the number of media data items + virtual U8 getMediaDataCount() const = 0; + // Get the media data at index, as an LLSD + virtual LLSD getMediaDataLLSD(U8 index) const = 0; + // Return true if the current URL for the face in the media data matches the specified URL. + virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const = 0; + // Get this object's UUID + virtual LLUUID getID() const = 0; + // Navigate back to previous URL + virtual void mediaNavigateBounceBack(U8 index) = 0; + // Does this object have media? + virtual bool hasMedia() const = 0; + // Update the object's media data to the given array + virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0; + // Return the total "interest" of the media (on-screen area) + virtual F64 getMediaInterest() const = 0; + // Return the given cap url + virtual std::string getCapabilityUrl(const std::string &name) const = 0; + // Return whether the object has been marked dead + virtual bool isDead() const = 0; + // Returns a media version number for the object + virtual U32 getMediaVersion() const = 0; + // Returns whether the object is "interesting enough" to fetch + virtual bool isInterestingEnough() const = 0; + // Returns whether we've seen this object yet or not + virtual bool isNew() const = 0; + + // smart pointer + typedef LLPointer<LLMediaDataClientObject> ptr_t; }; @@ -82,40 +82,40 @@ class LLMediaDataClient : public LLRefCount protected: LOG_CLASS(LLMediaDataClient); public: - + const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s) - const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs - const static U32 MAX_RETRIES;// = 4; - const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000; - const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000; - - // Constructor - LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, - F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, - U32 max_retries = MAX_RETRIES, - U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, - U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE); - - F32 getRetryTimerDelay() const { return mRetryTimerDelay; } - - // Returns true iff the queue is empty - virtual bool isEmpty() const; - - // Returns true iff the given object is in the queue - virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); - - // Remove the given object from the queue. Returns true iff the given object is removed. - virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); - - // Called only by the Queue timer and tests (potentially) - virtual bool processQueueTimer(); - + const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs + const static U32 MAX_RETRIES;// = 4; + const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000; + const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000; + + // Constructor + LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE); + + F32 getRetryTimerDelay() const { return mRetryTimerDelay; } + + // Returns true iff the queue is empty + virtual bool isEmpty() const; + + // Returns true iff the given object is in the queue + virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); + + // Remove the given object from the queue. Returns true iff the given object is removed. + virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); + + // Called only by the Queue timer and tests (potentially) + virtual bool processQueueTimer(); + protected: - // Destructor - virtual ~LLMediaDataClient(); // use unref - - // Request (pure virtual base class for requests in the queue) - class Request: + // Destructor + virtual ~LLMediaDataClient(); // use unref + + // Request (pure virtual base class for requests in the queue) + class Request: public std::enable_shared_from_this<Request> { public: @@ -138,66 +138,66 @@ protected: virtual ~Request() { } - protected: - // The only way to create one of these is through a subclass. - Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1); - public: - LLMediaDataClientObject *getObject() const { return mObject; } + protected: + // The only way to create one of these is through a subclass. + Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1); + public: + LLMediaDataClientObject *getObject() const { return mObject; } U32 getNum() const { return mNum; } - U32 getRetryCount() const { return mRetryCount; } - void incRetryCount() { mRetryCount++; } + U32 getRetryCount() const { return mRetryCount; } + void incRetryCount() { mRetryCount++; } Type getType() const { return mType; } - F64 getScore() const { return mScore; } - - // Note: may return empty string! - std::string getCapability() const; - const char *getCapName() const; - const char *getTypeAsString() const; - - // Re-enqueue thyself - void reEnqueue(); - - F32 getRetryTimerDelay() const; - U32 getMaxNumRetries() const; - - bool isObjectValid() const { return mObject.notNull() && (!mObject->isDead()); } - bool isNew() const { return isObjectValid() && mObject->isNew(); } - void updateScore(); - - void markDead(); - bool isDead(); - void startTracking(); - void stopTracking(); - - friend std::ostream& operator<<(std::ostream &s, const Request &q); - - const LLUUID &getID() const { return mObjectID; } - S32 getFace() const { return mFace; } - - bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const - { - return ((match_type == ANY) || (mType == other->mType)) && - (mFace == other->mFace) && - (mObjectID == other->mObjectID); - } - protected: - LLMediaDataClientObject::ptr_t mObject; - private: - Type mType; - // Simple tracking - U32 mNum; - static U32 sNum; + F64 getScore() const { return mScore; } + + // Note: may return empty string! + std::string getCapability() const; + const char *getCapName() const; + const char *getTypeAsString() const; + + // Re-enqueue thyself + void reEnqueue(); + + F32 getRetryTimerDelay() const; + U32 getMaxNumRetries() const; + + bool isObjectValid() const { return mObject.notNull() && (!mObject->isDead()); } + bool isNew() const { return isObjectValid() && mObject->isNew(); } + void updateScore(); + + void markDead(); + bool isDead(); + void startTracking(); + void stopTracking(); + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + + const LLUUID &getID() const { return mObjectID; } + S32 getFace() const { return mFace; } + + bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const + { + return ((match_type == ANY) || (mType == other->mType)) && + (mFace == other->mFace) && + (mObjectID == other->mObjectID); + } + protected: + LLMediaDataClientObject::ptr_t mObject; + private: + Type mType; + // Simple tracking + U32 mNum; + static U32 sNum; U32 mRetryCount; - F64 mScore; - - LLUUID mObjectID; - S32 mFace; + F64 mScore; + + LLUUID mObjectID; + S32 mFace; - // Back pointer to the MDC...not a ref! - LLMediaDataClient *mMDC; - }; - //typedef LLPointer<Request> request_ptr_t; + // Back pointer to the MDC...not a ref! + LLMediaDataClient *mMDC; + }; + //typedef LLPointer<Request> request_ptr_t; class Handler : public LLHttpSDHandler { @@ -215,60 +215,60 @@ protected: }; - class RetryTimer : public LLEventTimer - { - public: - RetryTimer(F32 time, Request::ptr_t); - virtual bool tick() override; - private: - // back-pointer - Request::ptr_t mRequest; - }; + class RetryTimer : public LLEventTimer + { + public: + RetryTimer(F32 time, Request::ptr_t); + virtual bool tick() override; + private: + // back-pointer + Request::ptr_t mRequest; + }; protected: - typedef std::list<Request::ptr_t> request_queue_t; - typedef std::set<Request::ptr_t> request_set_t; + typedef std::list<Request::ptr_t> request_queue_t; + typedef std::set<Request::ptr_t> request_set_t; - // Subclasses must override to return a cap name - virtual const char *getCapabilityName() const = 0; + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const = 0; - // Puts the request into a queue, appropriately handling duplicates, etc. + // Puts the request into a queue, appropriately handling duplicates, etc. virtual void enqueue(Request::ptr_t) = 0; - - virtual void serviceQueue(); + + virtual void serviceQueue(); virtual void serviceHttp(); - virtual request_queue_t *getQueue() { return &mQueue; }; + virtual request_queue_t *getQueue() { return &mQueue; }; - // Gets the next request, removing it from the queue - virtual Request::ptr_t dequeue(); - - virtual bool canServiceRequest(Request::ptr_t request) { return true; }; + // Gets the next request, removing it from the queue + virtual Request::ptr_t dequeue(); - // Returns a request to the head of the queue (should only be used for requests that came from dequeue - virtual void pushBack(Request::ptr_t request); - - void trackRequest(Request::ptr_t request); - void stopTrackingRequest(Request::ptr_t request); + virtual bool canServiceRequest(Request::ptr_t request) { return true; }; + + // Returns a request to the head of the queue (should only be used for requests that came from dequeue + virtual void pushBack(Request::ptr_t request); + + void trackRequest(Request::ptr_t request); + void stopTrackingRequest(Request::ptr_t request); bool isDoneProcessing() const; - - request_queue_t mQueue; - - const F32 mQueueTimerDelay; - const F32 mRetryTimerDelay; - const U32 mMaxNumRetries; - const U32 mMaxSortedQueueSize; - const U32 mMaxRoundRobinQueueSize; - - // Set for keeping track of requests that aren't in either queue. This includes: - // Requests that have been sent and are awaiting a response (pointer held by the Responder) - // Requests that are waiting for their retry timers to fire (pointer held by the retry timer) - request_set_t mUnQueuedRequests; - - void startQueueTimer(); - void stopQueueTimer(); + + request_queue_t mQueue; + + const F32 mQueueTimerDelay; + const F32 mRetryTimerDelay; + const U32 mMaxNumRetries; + const U32 mMaxSortedQueueSize; + const U32 mMaxRoundRobinQueueSize; + + // Set for keeping track of requests that aren't in either queue. This includes: + // Requests that have been sent and are awaiting a response (pointer held by the Responder) + // Requests that are waiting for their retry timers to fire (pointer held by the retry timer) + request_set_t mUnQueuedRequests; + + void startQueueTimer(); + void stopQueueTimer(); LLCore::HttpRequest::ptr_t mHttpRequest; LLCore::HttpHeaders::ptr_t mHttpHeaders; @@ -276,29 +276,29 @@ protected: LLCore::HttpRequest::policy_t mHttpPolicy; private: - - static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); - - friend std::ostream& operator<<(std::ostream &s, const Request &q); - friend std::ostream& operator<<(std::ostream &s, const request_queue_t &q); - - class QueueTimer : public LLEventTimer - { - public: - QueueTimer(F32 time, LLMediaDataClient *mdc); - bool tick() override; - private: - // back-pointer - LLPointer<LLMediaDataClient> mMDC; - }; - - void setIsRunning(bool val) { mQueueTimerIsRunning = val; } - - bool mQueueTimerIsRunning; - -// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); -// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); -// template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); + + static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + friend std::ostream& operator<<(std::ostream &s, const request_queue_t &q); + + class QueueTimer : public LLEventTimer + { + public: + QueueTimer(F32 time, LLMediaDataClient *mdc); + bool tick() override; + private: + // back-pointer + LLPointer<LLMediaDataClient> mMDC; + }; + + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } + + bool mQueueTimerIsRunning; + +// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); +// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); +// template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); }; // MediaDataClient specific for the ObjectMedia cap @@ -308,55 +308,55 @@ protected: LOG_CLASS(LLObjectMediaDataClient); public: LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, - F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, - U32 max_retries = MAX_RETRIES, - U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, - U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) - : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries), - mCurrentQueueIsTheSortedQueue(true) - {} - - void fetchMedia(LLMediaDataClientObject *object); + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries), + mCurrentQueueIsTheSortedQueue(true) + {} + + void fetchMedia(LLMediaDataClientObject *object); void updateMedia(LLMediaDataClientObject *object); - class RequestGet: public Request - { - public: - RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); - /*virtual*/ LLSD getPayload() const; + class RequestGet: public Request + { + public: + RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); + /*virtual*/ LLSD getPayload() const; /*virtual*/ LLCore::HttpHandler::ptr_t createHandler(); - }; + }; - class RequestUpdate: public Request - { - public: - RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); - /*virtual*/ LLSD getPayload() const; + class RequestUpdate: public Request + { + public: + RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); + /*virtual*/ LLSD getPayload() const; /*virtual*/ LLCore::HttpHandler::ptr_t createHandler(); - }; + }; + + // Returns true iff the queue is empty + virtual bool isEmpty() const; - // Returns true iff the queue is empty - virtual bool isEmpty() const; - - // Returns true iff the given object is in the queue - virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); - - // Remove the given object from the queue. Returns true iff the given object is removed. - virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); + // Returns true iff the given object is in the queue + virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); - virtual bool processQueueTimer(); + // Remove the given object from the queue. Returns true iff the given object is removed. + virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); - virtual bool canServiceRequest(Request::ptr_t request); + virtual bool processQueueTimer(); + + virtual bool canServiceRequest(Request::ptr_t request); protected: - // Subclasses must override to return a cap name - virtual const char *getCapabilityName() const; - - virtual request_queue_t *getQueue(); - - // Puts the request into the appropriate queue - virtual void enqueue(Request::ptr_t); - + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; + + virtual request_queue_t *getQueue(); + + // Puts the request into the appropriate queue + virtual void enqueue(Request::ptr_t); + class Handler: public LLMediaDataClient::Handler { LOG_CLASS(Handler); @@ -370,15 +370,15 @@ protected: }; private: - // The Get/Update data client needs a second queue to avoid object updates starving load-ins. - void swapCurrentQueue(); - - request_queue_t mRoundRobinQueue; - bool mCurrentQueueIsTheSortedQueue; - - // Comparator for sorting - static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2); - void sortQueue(); + // The Get/Update data client needs a second queue to avoid object updates starving load-ins. + void swapCurrentQueue(); + + request_queue_t mRoundRobinQueue; + bool mCurrentQueueIsTheSortedQueue; + + // Comparator for sorting + static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2); + void sortQueue(); }; @@ -388,36 +388,36 @@ class LLObjectMediaNavigateClient : public LLMediaDataClient protected: LOG_CLASS(LLObjectMediaNavigateClient); public: - // NOTE: from llmediaservice.h - static const int ERROR_PERMISSION_DENIED_CODE = 8002; - + // NOTE: from llmediaservice.h + static const int ERROR_PERMISSION_DENIED_CODE = 8002; + LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, - F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, - U32 max_retries = MAX_RETRIES, - U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, - U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) - : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) - {} - + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) + {} + void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url); - // Puts the request into the appropriate queue + // Puts the request into the appropriate queue virtual void enqueue(Request::ptr_t); - class RequestNavigate: public Request - { - public: - RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url); - /*virtual*/ LLSD getPayload() const; + class RequestNavigate: public Request + { + public: + RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url); + /*virtual*/ LLSD getPayload() const; /*virtual*/ LLCore::HttpHandler::ptr_t createHandler(); - /*virtual*/ std::string getURL() { return mURL; } - private: - std::string mURL; - }; - + /*virtual*/ std::string getURL() { return mURL; } + private: + std::string mURL; + }; + protected: - // Subclasses must override to return a cap name - virtual const char *getCapabilityName() const; + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; class Handler : public LLMediaDataClient::Handler { diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index b342fa5549..163fb5ffd4 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanelpeople.cpp * @brief Side tray "People" panel * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -52,7 +52,7 @@ #include "llavatarlist.h" #include "llavatarlistitem.h" #include "llavatarnamecache.h" -#include "llcallingcard.h" // for LLAvatarTracker +#include "llcallingcard.h" // for LLAvatarTracker #include "llcallbacklist.h" #include "llerror.h" #include "llfloateravatarpicker.h" @@ -65,8 +65,8 @@ #include "llparticipantlist.h" #include "llsidetraypanelcontainer.h" #include "llrecentpeople.h" -#include "llviewercontrol.h" // for gSavedSettings -#include "llviewermenu.h" // for gMenuHolder +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewermenu.h" // for gMenuHolder #include "llviewerregion.h" #include "llvoiceclient.h" #include "llworld.h" @@ -76,165 +76,165 @@ #include "llagentui.h" #include "llslurl.h" -#define FRIEND_LIST_UPDATE_TIMEOUT 0.5 +#define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 -static const std::string NEARBY_TAB_NAME = "nearby_panel"; -static const std::string FRIENDS_TAB_NAME = "friends_panel"; -static const std::string GROUP_TAB_NAME = "groups_panel"; -static const std::string RECENT_TAB_NAME = "recent_panel"; -static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars +static const std::string NEARBY_TAB_NAME = "nearby_panel"; +static const std::string FRIENDS_TAB_NAME = "friends_panel"; +static const std::string GROUP_TAB_NAME = "groups_panel"; +static const std::string RECENT_TAB_NAME = "recent_panel"; +static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars static const std::string COLLAPSED_BY_USER = "collapsed_by_user"; /** Comparator for comparing avatar items by last interaction date */ class LLAvatarItemRecentComparator : public LLAvatarItemComparator { public: - LLAvatarItemRecentComparator() {}; - virtual ~LLAvatarItemRecentComparator() {}; + LLAvatarItemRecentComparator() {}; + virtual ~LLAvatarItemRecentComparator() {}; protected: - virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const - { - LLRecentPeople& people = LLRecentPeople::instance(); - const LLDate& date1 = people.getDate(avatar_item1->getAvatarId()); - const LLDate& date2 = people.getDate(avatar_item2->getAvatarId()); - - //older comes first - return date1 > date2; - } + virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const + { + LLRecentPeople& people = LLRecentPeople::instance(); + const LLDate& date1 = people.getDate(avatar_item1->getAvatarId()); + const LLDate& date2 = people.getDate(avatar_item2->getAvatarId()); + + //older comes first + return date1 > date2; + } }; /** Compares avatar items by online status, then by name */ class LLAvatarItemStatusComparator : public LLAvatarItemComparator { public: - LLAvatarItemStatusComparator() {}; + LLAvatarItemStatusComparator() {}; protected: - /** - * @return true if item1 < item2, false otherwise - */ - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { - LLAvatarTracker& at = LLAvatarTracker::instance(); - bool online1 = at.isBuddyOnline(item1->getAvatarId()); - bool online2 = at.isBuddyOnline(item2->getAvatarId()); - - if (online1 == online2) - { - std::string name1 = item1->getAvatarName(); - std::string name2 = item2->getAvatarName(); - - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); - - return name1 < name2; - } - - return online1 > online2; - } + /** + * @return true if item1 < item2, false otherwise + */ + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { + LLAvatarTracker& at = LLAvatarTracker::instance(); + bool online1 = at.isBuddyOnline(item1->getAvatarId()); + bool online2 = at.isBuddyOnline(item2->getAvatarId()); + + if (online1 == online2) + { + std::string name1 = item1->getAvatarName(); + std::string name2 = item2->getAvatarName(); + + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); + + return name1 < name2; + } + + return online1 > online2; + } }; /** Compares avatar items by distance between you and them */ class LLAvatarItemDistanceComparator : public LLAvatarItemComparator { public: - typedef std::map < LLUUID, LLVector3d > id_to_pos_map_t; - LLAvatarItemDistanceComparator() {}; + typedef std::map < LLUUID, LLVector3d > id_to_pos_map_t; + LLAvatarItemDistanceComparator() {}; - void updateAvatarsPositions(std::vector<LLVector3d>& positions, uuid_vec_t& uuids) - { - std::vector<LLVector3d>::const_iterator - pos_it = positions.begin(), - pos_end = positions.end(); + void updateAvatarsPositions(std::vector<LLVector3d>& positions, uuid_vec_t& uuids) + { + std::vector<LLVector3d>::const_iterator + pos_it = positions.begin(), + pos_end = positions.end(); - uuid_vec_t::const_iterator - id_it = uuids.begin(), - id_end = uuids.end(); + uuid_vec_t::const_iterator + id_it = uuids.begin(), + id_end = uuids.end(); - LLAvatarItemDistanceComparator::id_to_pos_map_t pos_map; + LLAvatarItemDistanceComparator::id_to_pos_map_t pos_map; - mAvatarsPositions.clear(); + mAvatarsPositions.clear(); - for (;pos_it != pos_end && id_it != id_end; ++pos_it, ++id_it ) - { - mAvatarsPositions[*id_it] = *pos_it; - } - }; + for (;pos_it != pos_end && id_it != id_end; ++pos_it, ++id_it ) + { + mAvatarsPositions[*id_it] = *pos_it; + } + }; protected: - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { - const LLVector3d& me_pos = gAgent.getPositionGlobal(); - const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second; - const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second; - - return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos); - } + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { + const LLVector3d& me_pos = gAgent.getPositionGlobal(); + const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second; + const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second; + + return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos); + } private: - id_to_pos_map_t mAvatarsPositions; + id_to_pos_map_t mAvatarsPositions; }; /** Comparator for comparing nearby avatar items by last spoken time */ class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator { public: - LLAvatarItemRecentSpeakerComparator() {}; - virtual ~LLAvatarItemRecentSpeakerComparator() {}; + LLAvatarItemRecentSpeakerComparator() {}; + virtual ~LLAvatarItemRecentSpeakerComparator() {}; protected: - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { - LLPointer<LLSpeaker> lhs = LLActiveSpeakerMgr::instance().findSpeaker(item1->getAvatarId()); - LLPointer<LLSpeaker> rhs = LLActiveSpeakerMgr::instance().findSpeaker(item2->getAvatarId()); - if ( lhs.notNull() && rhs.notNull() ) - { - // Compare by last speaking time - if( lhs->mLastSpokeTime != rhs->mLastSpokeTime ) - return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime ); - } - else if ( lhs.notNull() ) - { - // True if only item1 speaker info available - return true; - } - else if ( rhs.notNull() ) - { - // False if only item2 speaker info available - return false; - } - // By default compare by name. - return LLAvatarItemNameComparator::doCompare(item1, item2); - } + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { + LLPointer<LLSpeaker> lhs = LLActiveSpeakerMgr::instance().findSpeaker(item1->getAvatarId()); + LLPointer<LLSpeaker> rhs = LLActiveSpeakerMgr::instance().findSpeaker(item2->getAvatarId()); + if ( lhs.notNull() && rhs.notNull() ) + { + // Compare by last speaking time + if( lhs->mLastSpokeTime != rhs->mLastSpokeTime ) + return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime ); + } + else if ( lhs.notNull() ) + { + // True if only item1 speaker info available + return true; + } + else if ( rhs.notNull() ) + { + // False if only item2 speaker info available + return false; + } + // By default compare by name. + return LLAvatarItemNameComparator::doCompare(item1, item2); + } }; class LLAvatarItemRecentArrivalComparator : public LLAvatarItemNameComparator { public: - LLAvatarItemRecentArrivalComparator() {}; - virtual ~LLAvatarItemRecentArrivalComparator() {}; + LLAvatarItemRecentArrivalComparator() {}; + virtual ~LLAvatarItemRecentArrivalComparator() {}; protected: - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { - F32 arr_time1 = LLRecentPeople::instance().getArrivalTimeByID(item1->getAvatarId()); - F32 arr_time2 = LLRecentPeople::instance().getArrivalTimeByID(item2->getAvatarId()); + F32 arr_time1 = LLRecentPeople::instance().getArrivalTimeByID(item1->getAvatarId()); + F32 arr_time2 = LLRecentPeople::instance().getArrivalTimeByID(item2->getAvatarId()); - if (arr_time1 == arr_time2) - { - std::string name1 = item1->getAvatarName(); - std::string name2 = item2->getAvatarName(); + if (arr_time1 == arr_time2) + { + std::string name1 = item1->getAvatarName(); + std::string name2 = item2->getAvatarName(); - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); - return name1 < name2; - } + return name1 < name2; + } - return arr_time1 > arr_time2; - } + return arr_time1 > arr_time2; + } }; static const LLAvatarItemRecentComparator RECENT_COMPARATOR; @@ -248,35 +248,35 @@ static LLPanelInjector<LLPanelPeople> t_people("panel_people"); //============================================================================= /** - * Updates given list either on regular basis or on external events (up to implementation). + * Updates given list either on regular basis or on external events (up to implementation). */ class LLPanelPeople::Updater { public: - typedef boost::function<void()> callback_t; - Updater(callback_t cb) - : mCallback(cb) - { - } - - virtual ~Updater() - { - } - - /** - * Activate/deactivate updater. - * - * This may start/stop regular updates. - */ - virtual void setActive(bool) {} + typedef boost::function<void()> callback_t; + Updater(callback_t cb) + : mCallback(cb) + { + } + + virtual ~Updater() + { + } + + /** + * Activate/deactivate updater. + * + * This may start/stop regular updates. + */ + virtual void setActive(bool) {} protected: - void update() - { - mCallback(); - } + void update() + { + mCallback(); + } - callback_t mCallback; + callback_t mCallback; }; /** @@ -285,233 +285,233 @@ protected: class LLButtonsUpdater : public LLPanelPeople::Updater, public LLFriendObserver { public: - LLButtonsUpdater(callback_t cb) - : LLPanelPeople::Updater(cb) - { - LLAvatarTracker::instance().addObserver(this); - } - - ~LLButtonsUpdater() - { - LLAvatarTracker::instance().removeObserver(this); - } - - /*virtual*/ void changed(U32 mask) - { - (void) mask; - update(); - } + LLButtonsUpdater(callback_t cb) + : LLPanelPeople::Updater(cb) + { + LLAvatarTracker::instance().addObserver(this); + } + + ~LLButtonsUpdater() + { + LLAvatarTracker::instance().removeObserver(this); + } + + /*virtual*/ void changed(U32 mask) + { + (void) mask; + update(); + } }; class LLAvatarListUpdater : public LLPanelPeople::Updater, public LLEventTimer { public: - LLAvatarListUpdater(callback_t cb, F32 period) - : LLEventTimer(period), - LLPanelPeople::Updater(cb) - { - stop(); - } - - bool tick() override // from LLEventTimer - { - return false; - } + LLAvatarListUpdater(callback_t cb, F32 period) + : LLEventTimer(period), + LLPanelPeople::Updater(cb) + { + stop(); + } + + bool tick() override // from LLEventTimer + { + return false; + } }; /** * Updates the friends list. - * - * Updates the list on external events which trigger the changed() method. + * + * Updates the list on external events which trigger the changed() method. */ class LLFriendListUpdater : public LLAvatarListUpdater, public LLFriendObserver { - LOG_CLASS(LLFriendListUpdater); - class LLInventoryFriendCardObserver; - -public: - friend class LLInventoryFriendCardObserver; - LLFriendListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT) - , mIsActive(false) - { - LLAvatarTracker::instance().addObserver(this); - - // For notification when SIP online status changes. - LLVoiceClient::getInstance()->addObserver(this); - mInvObserver = new LLInventoryFriendCardObserver(this); - } - - ~LLFriendListUpdater() - { - // will be deleted by ~LLInventoryModel - //delete mInvObserver; + LOG_CLASS(LLFriendListUpdater); + class LLInventoryFriendCardObserver; + +public: + friend class LLInventoryFriendCardObserver; + LLFriendListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT) + , mIsActive(false) + { + LLAvatarTracker::instance().addObserver(this); + + // For notification when SIP online status changes. + LLVoiceClient::getInstance()->addObserver(this); + mInvObserver = new LLInventoryFriendCardObserver(this); + } + + ~LLFriendListUpdater() + { + // will be deleted by ~LLInventoryModel + //delete mInvObserver; if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->removeObserver(this); } - LLAvatarTracker::instance().removeObserver(this); - } - - void changed(U32 mask) override - { - if (mIsActive) - { - // events can arrive quickly in bulk - we need not process EVERY one of them - - // so we wait a short while to let others pile-in, and process them in aggregate. - start(); - } - - // save-up all the mask-bits which have come-in - mMask |= mask; - } - - - bool tick() override - { - if (!mIsActive) return FALSE; - - if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) - { - update(); - } - - // Stop updates. - stop(); - mMask = 0; - - return false; - } - - void setActive(bool active) override - { - mIsActive = active; - if (active) - { - tick(); - } - } + LLAvatarTracker::instance().removeObserver(this); + } + + void changed(U32 mask) override + { + if (mIsActive) + { + // events can arrive quickly in bulk - we need not process EVERY one of them - + // so we wait a short while to let others pile-in, and process them in aggregate. + start(); + } + + // save-up all the mask-bits which have come-in + mMask |= mask; + } + + + bool tick() override + { + if (!mIsActive) return FALSE; + + if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) + { + update(); + } + + // Stop updates. + stop(); + mMask = 0; + + return false; + } + + void setActive(bool active) override + { + mIsActive = active; + if (active) + { + tick(); + } + } private: - U32 mMask; - LLInventoryFriendCardObserver* mInvObserver; - bool mIsActive; - - /** - * This class is intended for updating Friend List when Inventory Friend Card is added/removed. - * - * The main usage is when Inventory Friends/All content is added while synchronizing with - * friends list on startup is performed. In this case Friend Panel should be updated when - * missing Inventory Friend Card is created. - * *NOTE: updating is fired when Inventory item is added into CallingCards/Friends subfolder. - * Otherwise LLFriendObserver functionality is enough to keep Friends Panel synchronized. - */ - class LLInventoryFriendCardObserver : public LLInventoryObserver - { - LOG_CLASS(LLFriendListUpdater::LLInventoryFriendCardObserver); - - friend class LLFriendListUpdater; - - private: - LLInventoryFriendCardObserver(LLFriendListUpdater* updater) : mUpdater(updater) - { - gInventory.addObserver(this); - } - ~LLInventoryFriendCardObserver() - { - gInventory.removeObserver(this); - } - /*virtual*/ void changed(U32 mask) - { - LL_DEBUGS() << "Inventory changed: " << mask << LL_ENDL; - - static bool synchronize_friends_folders = true; - if (synchronize_friends_folders) - { - // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder, - // fetches their contents if needed and synchronizes it with buddies list. - // If the folders are not found they are created. - LLFriendCardsManager::instance().syncFriendCardsFolders(); - synchronize_friends_folders = false; - } - - // *NOTE: deleting of InventoryItem is performed via moving to Trash. - // That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE - if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED) - { - LL_DEBUGS() << "Calling card added: count: " << gInventory.getChangedIDs().size() - << ", first Inventory ID: "<< (*gInventory.getChangedIDs().begin()) - << LL_ENDL; - - bool friendFound = false; - std::set<LLUUID> changedIDs = gInventory.getChangedIDs(); - for (std::set<LLUUID>::const_iterator it = changedIDs.begin(); it != changedIDs.end(); ++it) - { - if (isDescendentOfInventoryFriends(*it)) - { - friendFound = true; - break; - } - } - - if (friendFound) - { - LL_DEBUGS() << "friend found, panel should be updated" << LL_ENDL; - mUpdater->changed(LLFriendObserver::ADD); - } - } - } - - bool isDescendentOfInventoryFriends(const LLUUID& invItemID) - { - LLViewerInventoryItem * item = gInventory.getItem(invItemID); - if (NULL == item) - return false; - - return LLFriendCardsManager::instance().isItemInAnyFriendsList(item); - } - LLFriendListUpdater* mUpdater; - - static const U32 CALLINGCARD_ADDED = LLInventoryObserver::ADD | LLInventoryObserver::CALLING_CARD; - }; + U32 mMask; + LLInventoryFriendCardObserver* mInvObserver; + bool mIsActive; + + /** + * This class is intended for updating Friend List when Inventory Friend Card is added/removed. + * + * The main usage is when Inventory Friends/All content is added while synchronizing with + * friends list on startup is performed. In this case Friend Panel should be updated when + * missing Inventory Friend Card is created. + * *NOTE: updating is fired when Inventory item is added into CallingCards/Friends subfolder. + * Otherwise LLFriendObserver functionality is enough to keep Friends Panel synchronized. + */ + class LLInventoryFriendCardObserver : public LLInventoryObserver + { + LOG_CLASS(LLFriendListUpdater::LLInventoryFriendCardObserver); + + friend class LLFriendListUpdater; + + private: + LLInventoryFriendCardObserver(LLFriendListUpdater* updater) : mUpdater(updater) + { + gInventory.addObserver(this); + } + ~LLInventoryFriendCardObserver() + { + gInventory.removeObserver(this); + } + /*virtual*/ void changed(U32 mask) + { + LL_DEBUGS() << "Inventory changed: " << mask << LL_ENDL; + + static bool synchronize_friends_folders = true; + if (synchronize_friends_folders) + { + // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder, + // fetches their contents if needed and synchronizes it with buddies list. + // If the folders are not found they are created. + LLFriendCardsManager::instance().syncFriendCardsFolders(); + synchronize_friends_folders = false; + } + + // *NOTE: deleting of InventoryItem is performed via moving to Trash. + // That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE + if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED) + { + LL_DEBUGS() << "Calling card added: count: " << gInventory.getChangedIDs().size() + << ", first Inventory ID: "<< (*gInventory.getChangedIDs().begin()) + << LL_ENDL; + + bool friendFound = false; + std::set<LLUUID> changedIDs = gInventory.getChangedIDs(); + for (std::set<LLUUID>::const_iterator it = changedIDs.begin(); it != changedIDs.end(); ++it) + { + if (isDescendentOfInventoryFriends(*it)) + { + friendFound = true; + break; + } + } + + if (friendFound) + { + LL_DEBUGS() << "friend found, panel should be updated" << LL_ENDL; + mUpdater->changed(LLFriendObserver::ADD); + } + } + } + + bool isDescendentOfInventoryFriends(const LLUUID& invItemID) + { + LLViewerInventoryItem * item = gInventory.getItem(invItemID); + if (NULL == item) + return false; + + return LLFriendCardsManager::instance().isItemInAnyFriendsList(item); + } + LLFriendListUpdater* mUpdater; + + static const U32 CALLINGCARD_ADDED = LLInventoryObserver::ADD | LLInventoryObserver::CALLING_CARD; + }; }; /** * Periodically updates the nearby people list while the Nearby tab is active. - * + * * The period is defined by NEARBY_LIST_UPDATE_INTERVAL constant. */ class LLNearbyListUpdater : public LLAvatarListUpdater { - LOG_CLASS(LLNearbyListUpdater); + LOG_CLASS(LLNearbyListUpdater); public: - LLNearbyListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, NEARBY_LIST_UPDATE_INTERVAL) - { - setActive(false); - } - - void setActive(bool val) override - { - if (val) - { - // update immediately and start regular updates - update(); - start(); - } - else - { - // stop regular updates - stop(); - } - } - - bool tick() override - { - update(); - return false; - } + LLNearbyListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, NEARBY_LIST_UPDATE_INTERVAL) + { + setActive(false); + } + + void setActive(bool val) override + { + if (val) + { + // update immediately and start regular updates + update(); + start(); + } + else + { + // stop regular updates + stop(); + } + } + + bool tick() override + { + update(); + return false; + } private: }; @@ -520,83 +520,83 @@ private: */ class LLRecentListUpdater : public LLAvatarListUpdater, public boost::signals2::trackable { - LOG_CLASS(LLRecentListUpdater); + LOG_CLASS(LLRecentListUpdater); public: - LLRecentListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, 0) - { - LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this)); - } + LLRecentListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, 0) + { + LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this)); + } }; //============================================================================= LLPanelPeople::LLPanelPeople() - : LLPanel(), - mTabContainer(NULL), - mOnlineFriendList(NULL), - mAllFriendList(NULL), - mNearbyList(NULL), - mRecentList(NULL), - mGroupList(NULL), - mMiniMap(NULL) + : LLPanel(), + mTabContainer(NULL), + mOnlineFriendList(NULL), + mAllFriendList(NULL), + mNearbyList(NULL), + mRecentList(NULL), + mGroupList(NULL), + mMiniMap(NULL) { - mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); - mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); - mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); - mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this)); - - mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); - mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); - mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Group.Minus", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Chat", boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Gear", boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1)); - - mCommitCallbackRegistrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); - - mEnableCallbackRegistrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2)); - mEnableCallbackRegistrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2)); - mEnableCallbackRegistrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2)); - - mEnableCallbackRegistrar.add("People.Group.Plus.Validate", boost::bind(&LLPanelPeople::onGroupPlusButtonValidate, this)); - - doPeriodically(boost::bind(&LLPanelPeople::updateNearbyArrivalTime, this), 2.0); + mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); + mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); + mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); + mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this)); + + mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); + mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); + mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); + mCommitCallbackRegistrar.add("People.Group.Minus", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); + mCommitCallbackRegistrar.add("People.Chat", boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + mCommitCallbackRegistrar.add("People.Gear", boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1)); + + mCommitCallbackRegistrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); + + mEnableCallbackRegistrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2)); + mEnableCallbackRegistrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2)); + mEnableCallbackRegistrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2)); + + mEnableCallbackRegistrar.add("People.Group.Plus.Validate", boost::bind(&LLPanelPeople::onGroupPlusButtonValidate, this)); + + doPeriodically(boost::bind(&LLPanelPeople::updateNearbyArrivalTime, this), 2.0); } LLPanelPeople::~LLPanelPeople() { - delete mButtonsUpdater; - delete mNearbyListUpdater; - delete mFriendListUpdater; - delete mRecentListUpdater; - - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + delete mButtonsUpdater; + delete mNearbyListUpdater; + delete mFriendListUpdater; + delete mRecentListUpdater; + + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->removeObserver(this); + } } void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list) { - if(!avatar_list) - { - LL_ERRS() << "Bad parameter" << LL_ENDL; - return; - } - - bool expanded = param.asBoolean(); - - setAccordionCollapsedByUser(ctrl, !expanded); - if(!expanded) - { - avatar_list->resetSelection(); - } + if(!avatar_list) + { + LL_ERRS() << "Bad parameter" << LL_ENDL; + return; + } + + bool expanded = param.asBoolean(); + + setAccordionCollapsedByUser(ctrl, !expanded); + if(!expanded) + { + avatar_list->resetSelection(); + } } @@ -610,574 +610,574 @@ void LLPanelPeople::removePicker() BOOL LLPanelPeople::postBuild() { - S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); - - getChild<LLFilterEditor>("nearby_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - getChild<LLFilterEditor>("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - - if(LLAgentBenefitsMgr::current().getGroupMembershipLimit() < max_premium) - { - getChild<LLTextBox>("groupcount")->setText(getString("GroupCountWithInfo")); - getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); - } - - mTabContainer = getChild<LLTabContainer>("tabs"); - mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); - mSavedFilters.resize(mTabContainer->getTabCount()); - mSavedOriginalFilters.resize(mTabContainer->getTabCount()); - - LLPanel* friends_tab = getChild<LLPanel>(FRIENDS_TAB_NAME); - // updater is active only if panel is visible to user. - friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2)); + S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); + + getChild<LLFilterEditor>("nearby_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild<LLFilterEditor>("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + + if(LLAgentBenefitsMgr::current().getGroupMembershipLimit() < max_premium) + { + getChild<LLTextBox>("groupcount")->setText(getString("GroupCountWithInfo")); + getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); + } + + mTabContainer = getChild<LLTabContainer>("tabs"); + mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); + mSavedFilters.resize(mTabContainer->getTabCount()); + mSavedOriginalFilters.resize(mTabContainer->getTabCount()); + + LLPanel* friends_tab = getChild<LLPanel>(FRIENDS_TAB_NAME); + // updater is active only if panel is visible to user. + friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2)); friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::removePicker, this)); - mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online"); - mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all"); - mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); - mOnlineFriendList->setShowIcons("FriendsListShowIcons"); - mOnlineFriendList->showPermissions("FriendsListShowPermissions"); - mOnlineFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); - mAllFriendList->setNoItemsCommentText(getString("no_friends")); - mAllFriendList->setShowIcons("FriendsListShowIcons"); - mAllFriendList->showPermissions("FriendsListShowPermissions"); - mAllFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); - - LLPanel* nearby_tab = getChild<LLPanel>(NEARBY_TAB_NAME); - nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2)); - mNearbyList = nearby_tab->getChild<LLAvatarList>("avatar_list"); - mNearbyList->setNoItemsCommentText(getString("no_one_near")); - mNearbyList->setNoItemsMsg(getString("no_one_near")); - mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); - mNearbyList->setShowIcons("NearbyListShowIcons"); - mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames")); - mMiniMap = (LLNetMap*)getChildView("Net Map",true); - mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? - getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); - - mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list"); - mRecentList->setNoItemsCommentText(getString("no_recent_people")); - mRecentList->setNoItemsMsg(getString("no_recent_people")); - mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people")); - mRecentList->setShowIcons("RecentListShowIcons"); - - mGroupList = getChild<LLGroupList>("group_list"); - mGroupList->setNoItemsCommentText(getString("no_groups_msg")); - mGroupList->setNoItemsMsg(getString("no_groups_msg")); - mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); - - mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyPeopleContextMenu); - mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); - mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); - mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); - - setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); - setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); - setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false); - - mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - - mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); - mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); - mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); - mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); - - // Set openning IM as default on return action for avatar lists - mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - - mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this)); - mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - - LLMenuButton* groups_gear_btn = getChild<LLMenuButton>("groups_gear_btn"); - - // Use the context menu of the Groups list for the Groups tab gear menu. - LLToggleableMenu* groups_gear_menu = mGroupList->getContextMenu(); - if (groups_gear_menu) - { - groups_gear_btn->setMenu(groups_gear_menu, LLMenuButton::MP_BOTTOM_LEFT); - } - else - { - LL_WARNS() << "People->Groups list menu not found" << LL_ENDL; - } - - LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>("tab_all"); - accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList)); - - accordion_tab = getChild<LLAccordionCtrlTab>("tab_online"); - accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList)); - - // Must go after setting commit callback and initializing all pointers to children. - mTabContainer->selectTabByName(NEARBY_TAB_NAME); - - LLVoiceClient::getInstance()->addObserver(this); - - // call this method in case some list is empty and buttons can be in inconsistent state - updateButtons(); - - mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); - mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); - - return TRUE; + mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online"); + mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all"); + mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); + mOnlineFriendList->setShowIcons("FriendsListShowIcons"); + mOnlineFriendList->showPermissions("FriendsListShowPermissions"); + mOnlineFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); + mAllFriendList->setNoItemsCommentText(getString("no_friends")); + mAllFriendList->setShowIcons("FriendsListShowIcons"); + mAllFriendList->showPermissions("FriendsListShowPermissions"); + mAllFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); + + LLPanel* nearby_tab = getChild<LLPanel>(NEARBY_TAB_NAME); + nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2)); + mNearbyList = nearby_tab->getChild<LLAvatarList>("avatar_list"); + mNearbyList->setNoItemsCommentText(getString("no_one_near")); + mNearbyList->setNoItemsMsg(getString("no_one_near")); + mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); + mNearbyList->setShowIcons("NearbyListShowIcons"); + mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames")); + mMiniMap = (LLNetMap*)getChildView("Net Map",true); + mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? + getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); + + mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list"); + mRecentList->setNoItemsCommentText(getString("no_recent_people")); + mRecentList->setNoItemsMsg(getString("no_recent_people")); + mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people")); + mRecentList->setShowIcons("RecentListShowIcons"); + + mGroupList = getChild<LLGroupList>("group_list"); + mGroupList->setNoItemsCommentText(getString("no_groups_msg")); + mGroupList->setNoItemsMsg(getString("no_groups_msg")); + mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); + + mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyPeopleContextMenu); + mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + + setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); + setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); + setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false); + + mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + + mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); + mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); + mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); + mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); + + // Set openning IM as default on return action for avatar lists + mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + + mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this)); + mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + + LLMenuButton* groups_gear_btn = getChild<LLMenuButton>("groups_gear_btn"); + + // Use the context menu of the Groups list for the Groups tab gear menu. + LLToggleableMenu* groups_gear_menu = mGroupList->getContextMenu(); + if (groups_gear_menu) + { + groups_gear_btn->setMenu(groups_gear_menu, LLMenuButton::MP_BOTTOM_LEFT); + } + else + { + LL_WARNS() << "People->Groups list menu not found" << LL_ENDL; + } + + LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>("tab_all"); + accordion_tab->setDropDownStateChangedCallback( + boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList)); + + accordion_tab = getChild<LLAccordionCtrlTab>("tab_online"); + accordion_tab->setDropDownStateChangedCallback( + boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList)); + + // Must go after setting commit callback and initializing all pointers to children. + mTabContainer->selectTabByName(NEARBY_TAB_NAME); + + LLVoiceClient::getInstance()->addObserver(this); + + // call this method in case some list is empty and buttons can be in inconsistent state + updateButtons(); + + mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); + mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); + + return TRUE; } // virtual void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal) { - if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) - { - return; - } - - updateButtons(); + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + updateButtons(); } void LLPanelPeople::updateFriendListHelpText() { - // show special help text for just created account to help finding friends. EXT-4836 - static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_help_text"); - - // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...) - // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448. - bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches(); - no_friends_text->setVisible(!any_friend_exists); - if (no_friends_text->getVisible()) - { - //update help text for empty lists - const std::string& filter = mSavedOriginalFilters[mTabContainer->getCurrentPanelIndex()]; - - std::string message_name = filter.empty() ? "no_friends_msg" : "no_filtered_friends_msg"; - LLStringUtil::format_map_t args; - args["[SEARCH_TERM]"] = LLURI::escape(filter); - no_friends_text->setText(getString(message_name, args)); - } + // show special help text for just created account to help finding friends. EXT-4836 + static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_help_text"); + + // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...) + // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448. + bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches(); + no_friends_text->setVisible(!any_friend_exists); + if (no_friends_text->getVisible()) + { + //update help text for empty lists + const std::string& filter = mSavedOriginalFilters[mTabContainer->getCurrentPanelIndex()]; + + std::string message_name = filter.empty() ? "no_friends_msg" : "no_filtered_friends_msg"; + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter); + no_friends_text->setText(getString(message_name, args)); + } } void LLPanelPeople::updateFriendList() { - if (!mOnlineFriendList || !mAllFriendList) - return; - - // get all buddies we know about - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - LLAvatarTracker::buddy_map_t all_buddies; - av_tracker.copyBuddyList(all_buddies); - - // save them to the online and all friends vectors - uuid_vec_t& online_friendsp = mOnlineFriendList->getIDs(); - uuid_vec_t& all_friendsp = mAllFriendList->getIDs(); - - all_friendsp.clear(); - online_friendsp.clear(); - - uuid_vec_t buddies_uuids; - LLAvatarTracker::buddy_map_t::const_iterator buddies_iter; - - // Fill the avatar list with friends UUIDs - for (buddies_iter = all_buddies.begin(); buddies_iter != all_buddies.end(); ++buddies_iter) - { - buddies_uuids.push_back(buddies_iter->first); - } - - if (buddies_uuids.size() > 0) - { - LL_DEBUGS() << "Friends added to the list: " << buddies_uuids.size() << LL_ENDL; - all_friendsp = buddies_uuids; - } - else - { - LL_DEBUGS() << "No friends found" << LL_ENDL; - } - - LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); - for (; buddy_it != all_buddies.end(); ++buddy_it) - { - LLUUID buddy_id = buddy_it->first; - if (av_tracker.isBuddyOnline(buddy_id)) - online_friendsp.push_back(buddy_id); - } - - /* - * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items. - * But avatarlist can be updated only if it is visible @see LLAvatarList::draw(); - * So we need to do force update of lists to avoid inconsistency of data and view of avatarlist. - */ - mOnlineFriendList->setDirty(true, !mOnlineFriendList->filterHasMatches());// do force update if list do NOT have items - mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches()); - //update trash and other buttons according to a selected item - updateButtons(); - showFriendsAccordionsIfNeeded(); + if (!mOnlineFriendList || !mAllFriendList) + return; + + // get all buddies we know about + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + LLAvatarTracker::buddy_map_t all_buddies; + av_tracker.copyBuddyList(all_buddies); + + // save them to the online and all friends vectors + uuid_vec_t& online_friendsp = mOnlineFriendList->getIDs(); + uuid_vec_t& all_friendsp = mAllFriendList->getIDs(); + + all_friendsp.clear(); + online_friendsp.clear(); + + uuid_vec_t buddies_uuids; + LLAvatarTracker::buddy_map_t::const_iterator buddies_iter; + + // Fill the avatar list with friends UUIDs + for (buddies_iter = all_buddies.begin(); buddies_iter != all_buddies.end(); ++buddies_iter) + { + buddies_uuids.push_back(buddies_iter->first); + } + + if (buddies_uuids.size() > 0) + { + LL_DEBUGS() << "Friends added to the list: " << buddies_uuids.size() << LL_ENDL; + all_friendsp = buddies_uuids; + } + else + { + LL_DEBUGS() << "No friends found" << LL_ENDL; + } + + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + for (; buddy_it != all_buddies.end(); ++buddy_it) + { + LLUUID buddy_id = buddy_it->first; + if (av_tracker.isBuddyOnline(buddy_id)) + online_friendsp.push_back(buddy_id); + } + + /* + * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items. + * But avatarlist can be updated only if it is visible @see LLAvatarList::draw(); + * So we need to do force update of lists to avoid inconsistency of data and view of avatarlist. + */ + mOnlineFriendList->setDirty(true, !mOnlineFriendList->filterHasMatches());// do force update if list do NOT have items + mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches()); + //update trash and other buttons according to a selected item + updateButtons(); + showFriendsAccordionsIfNeeded(); } void LLPanelPeople::updateNearbyList() { - if (!mNearbyList) - return; + if (!mNearbyList) + return; - std::vector<LLVector3d> positions; + std::vector<LLVector3d> positions; - LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); - mNearbyList->setDirty(); + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + mNearbyList->setDirty(); - DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); - LLActiveSpeakerMgr::instance().update(TRUE); + DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); + LLActiveSpeakerMgr::instance().update(TRUE); } void LLPanelPeople::updateRecentList() { - if (!mRecentList) - return; + if (!mRecentList) + return; - LLRecentPeople::instance().get(mRecentList->getIDs()); - mRecentList->setDirty(); + LLRecentPeople::instance().get(mRecentList->getIDs()); + mRecentList->setDirty(); } void LLPanelPeople::updateButtons() { - std::string cur_tab = getActiveTabName(); - bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); - bool group_tab_active = (cur_tab == GROUP_TAB_NAME); - //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); - LLUUID selected_id; - - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - bool item_selected = (selected_uuids.size() == 1); - bool multiple_selected = (selected_uuids.size() >= 1); - - if (group_tab_active) - { - if (item_selected) - { - selected_id = mGroupList->getSelectedUUID(); - } - - LLPanel* groups_panel = mTabContainer->getCurrentPanel(); - groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected - - U32 groups_count = gAgent.mGroups.size(); - S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); - U32 groups_remaining = max_groups > groups_count ? max_groups - groups_count : 0; - groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); - groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_remaining)); - } - else - { - bool is_friend = true; - bool is_self = false; - // Check whether selected avatar is our friend. - if (item_selected) - { - selected_id = selected_uuids.front(); - is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; - is_self = gAgent.getID() == selected_id; - } - - LLPanel* cur_panel = mTabContainer->getCurrentPanel(); - if (cur_panel) - { - if (cur_panel->hasChild("add_friend_btn", TRUE)) - cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); - - if (friends_tab_active) - { - cur_panel->getChildView("friends_del_btn")->setEnabled(multiple_selected); - } - - if (!group_tab_active) - { - cur_panel->getChildView("gear_btn")->setEnabled(multiple_selected); - } - } - } + std::string cur_tab = getActiveTabName(); + bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); + bool group_tab_active = (cur_tab == GROUP_TAB_NAME); + //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); + LLUUID selected_id; + + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + bool item_selected = (selected_uuids.size() == 1); + bool multiple_selected = (selected_uuids.size() >= 1); + + if (group_tab_active) + { + if (item_selected) + { + selected_id = mGroupList->getSelectedUUID(); + } + + LLPanel* groups_panel = mTabContainer->getCurrentPanel(); + groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected + + U32 groups_count = gAgent.mGroups.size(); + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); + U32 groups_remaining = max_groups > groups_count ? max_groups - groups_count : 0; + groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); + groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_remaining)); + } + else + { + bool is_friend = true; + bool is_self = false; + // Check whether selected avatar is our friend. + if (item_selected) + { + selected_id = selected_uuids.front(); + is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; + is_self = gAgent.getID() == selected_id; + } + + LLPanel* cur_panel = mTabContainer->getCurrentPanel(); + if (cur_panel) + { + if (cur_panel->hasChild("add_friend_btn", TRUE)) + cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); + + if (friends_tab_active) + { + cur_panel->getChildView("friends_del_btn")->setEnabled(multiple_selected); + } + + if (!group_tab_active) + { + cur_panel->getChildView("gear_btn")->setEnabled(multiple_selected); + } + } + } } std::string LLPanelPeople::getActiveTabName() const { - return mTabContainer->getCurrentPanel()->getName(); + return mTabContainer->getCurrentPanel()->getName(); } LLUUID LLPanelPeople::getCurrentItemID() const { - std::string cur_tab = getActiveTabName(); + std::string cur_tab = getActiveTabName(); - if (cur_tab == FRIENDS_TAB_NAME) // this tab has two lists - { - LLUUID cur_online_friend; + if (cur_tab == FRIENDS_TAB_NAME) // this tab has two lists + { + LLUUID cur_online_friend; - if ((cur_online_friend = mOnlineFriendList->getSelectedUUID()).notNull()) - return cur_online_friend; + if ((cur_online_friend = mOnlineFriendList->getSelectedUUID()).notNull()) + return cur_online_friend; - return mAllFriendList->getSelectedUUID(); - } + return mAllFriendList->getSelectedUUID(); + } - if (cur_tab == NEARBY_TAB_NAME) - return mNearbyList->getSelectedUUID(); + if (cur_tab == NEARBY_TAB_NAME) + return mNearbyList->getSelectedUUID(); - if (cur_tab == RECENT_TAB_NAME) - return mRecentList->getSelectedUUID(); + if (cur_tab == RECENT_TAB_NAME) + return mRecentList->getSelectedUUID(); - if (cur_tab == GROUP_TAB_NAME) - return mGroupList->getSelectedUUID(); + if (cur_tab == GROUP_TAB_NAME) + return mGroupList->getSelectedUUID(); - if (cur_tab == BLOCKED_TAB_NAME) - return LLUUID::null; // FIXME? + if (cur_tab == BLOCKED_TAB_NAME) + return LLUUID::null; // FIXME? - llassert(0 && "unknown tab selected"); - return LLUUID::null; + llassert(0 && "unknown tab selected"); + return LLUUID::null; } void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const { - std::string cur_tab = getActiveTabName(); - - if (cur_tab == FRIENDS_TAB_NAME) - { - // friends tab has two lists - mOnlineFriendList->getSelectedUUIDs(selected_uuids); - mAllFriendList->getSelectedUUIDs(selected_uuids); - } - else if (cur_tab == NEARBY_TAB_NAME) - mNearbyList->getSelectedUUIDs(selected_uuids); - else if (cur_tab == RECENT_TAB_NAME) - mRecentList->getSelectedUUIDs(selected_uuids); - else if (cur_tab == GROUP_TAB_NAME) - mGroupList->getSelectedUUIDs(selected_uuids); - else if (cur_tab == BLOCKED_TAB_NAME) - selected_uuids.clear(); // FIXME? - else - llassert(0 && "unknown tab selected"); + std::string cur_tab = getActiveTabName(); + + if (cur_tab == FRIENDS_TAB_NAME) + { + // friends tab has two lists + mOnlineFriendList->getSelectedUUIDs(selected_uuids); + mAllFriendList->getSelectedUUIDs(selected_uuids); + } + else if (cur_tab == NEARBY_TAB_NAME) + mNearbyList->getSelectedUUIDs(selected_uuids); + else if (cur_tab == RECENT_TAB_NAME) + mRecentList->getSelectedUUIDs(selected_uuids); + else if (cur_tab == GROUP_TAB_NAME) + mGroupList->getSelectedUUIDs(selected_uuids); + else if (cur_tab == BLOCKED_TAB_NAME) + selected_uuids.clear(); // FIXME? + else + llassert(0 && "unknown tab selected"); } void LLPanelPeople::showGroupMenu(LLMenuGL* menu) { - // Shows the menu at the top of the button bar. - - // Calculate its coordinates. - // (assumes that groups panel is the current tab) - LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild<LLPanel>("bottom_panel"); - LLPanel* parent_panel = mTabContainer->getCurrentPanel(); - menu->arrangeAndClear(); - S32 menu_height = menu->getRect().getHeight(); - S32 menu_x = -2; // *HACK: compensates HPAD in showPopup() - S32 menu_y = bottom_panel->getRect().mTop + menu_height; - - // Actually show the menu. - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(parent_panel, menu, menu_x, menu_y); + // Shows the menu at the top of the button bar. + + // Calculate its coordinates. + // (assumes that groups panel is the current tab) + LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild<LLPanel>("bottom_panel"); + LLPanel* parent_panel = mTabContainer->getCurrentPanel(); + menu->arrangeAndClear(); + S32 menu_height = menu->getRect().getHeight(); + S32 menu_x = -2; // *HACK: compensates HPAD in showPopup() + S32 menu_y = bottom_panel->getRect().mTop + menu_height; + + // Actually show the menu. + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(parent_panel, menu, menu_x, menu_y); } void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save) { - switch (order) - { - case E_SORT_BY_NAME: - list->sortByName(); - break; - case E_SORT_BY_STATUS: - list->setComparator(&STATUS_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_MOST_RECENT: - list->setComparator(&RECENT_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_RECENT_SPEAKERS: - list->setComparator(&RECENT_SPEAKER_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_DISTANCE: - list->setComparator(&DISTANCE_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_RECENT_ARRIVAL: - list->setComparator(&RECENT_ARRIVAL_COMPARATOR); - list->sort(); - break; - default: - LL_WARNS() << "Unrecognized people sort order for " << list->getName() << LL_ENDL; - return; - } - - if (save) - { - std::string setting; - - if (list == mAllFriendList || list == mOnlineFriendList) - setting = "FriendsSortOrder"; - else if (list == mRecentList) - setting = "RecentPeopleSortOrder"; - else if (list == mNearbyList) - setting = "NearbyPeopleSortOrder"; - - if (!setting.empty()) - gSavedSettings.setU32(setting, order); - } + switch (order) + { + case E_SORT_BY_NAME: + list->sortByName(); + break; + case E_SORT_BY_STATUS: + list->setComparator(&STATUS_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_MOST_RECENT: + list->setComparator(&RECENT_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_RECENT_SPEAKERS: + list->setComparator(&RECENT_SPEAKER_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_DISTANCE: + list->setComparator(&DISTANCE_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_RECENT_ARRIVAL: + list->setComparator(&RECENT_ARRIVAL_COMPARATOR); + list->sort(); + break; + default: + LL_WARNS() << "Unrecognized people sort order for " << list->getName() << LL_ENDL; + return; + } + + if (save) + { + std::string setting; + + if (list == mAllFriendList || list == mOnlineFriendList) + setting = "FriendsSortOrder"; + else if (list == mRecentList) + setting = "RecentPeopleSortOrder"; + else if (list == mNearbyList) + setting = "NearbyPeopleSortOrder"; + + if (!setting.empty()) + gSavedSettings.setU32(setting, order); + } } void LLPanelPeople::onFilterEdit(const std::string& search_string) { - const S32 cur_tab_idx = mTabContainer->getCurrentPanelIndex(); - std::string& filter = mSavedOriginalFilters[cur_tab_idx]; - std::string& saved_filter = mSavedFilters[cur_tab_idx]; - - filter = search_string; - LLStringUtil::trimHead(filter); - - // Searches are case-insensitive - std::string search_upper = filter; - LLStringUtil::toUpper(search_upper); - - if (saved_filter == search_upper) - return; - - saved_filter = search_upper; - - // Apply new filter to the current tab. - const std::string cur_tab = getActiveTabName(); - if (cur_tab == NEARBY_TAB_NAME) - { - mNearbyList->setNameFilter(filter); - } - else if (cur_tab == FRIENDS_TAB_NAME) - { - // store accordion tabs opened/closed state before any manipulation with accordion tabs - if (!saved_filter.empty()) + const S32 cur_tab_idx = mTabContainer->getCurrentPanelIndex(); + std::string& filter = mSavedOriginalFilters[cur_tab_idx]; + std::string& saved_filter = mSavedFilters[cur_tab_idx]; + + filter = search_string; + LLStringUtil::trimHead(filter); + + // Searches are case-insensitive + std::string search_upper = filter; + LLStringUtil::toUpper(search_upper); + + if (saved_filter == search_upper) + return; + + saved_filter = search_upper; + + // Apply new filter to the current tab. + const std::string cur_tab = getActiveTabName(); + if (cur_tab == NEARBY_TAB_NAME) + { + mNearbyList->setNameFilter(filter); + } + else if (cur_tab == FRIENDS_TAB_NAME) + { + // store accordion tabs opened/closed state before any manipulation with accordion tabs + if (!saved_filter.empty()) { notifyChildren(LLSD().with("action","store_state")); } - mOnlineFriendList->setNameFilter(filter); - mAllFriendList->setNameFilter(filter); + mOnlineFriendList->setNameFilter(filter); + mAllFriendList->setNameFilter(filter); setAccordionCollapsedByUser("tab_online", false); setAccordionCollapsedByUser("tab_all", false); showFriendsAccordionsIfNeeded(); - // restore accordion tabs state _after_ all manipulations - if(saved_filter.empty()) + // restore accordion tabs state _after_ all manipulations + if(saved_filter.empty()) { notifyChildren(LLSD().with("action","restore_state")); } } - else if (cur_tab == GROUP_TAB_NAME) - { - mGroupList->setNameFilter(filter); - } - else if (cur_tab == RECENT_TAB_NAME) - { - mRecentList->setNameFilter(filter); - } + else if (cur_tab == GROUP_TAB_NAME) + { + mGroupList->setNameFilter(filter); + } + else if (cur_tab == RECENT_TAB_NAME) + { + mRecentList->setNameFilter(filter); + } } void LLPanelPeople::onGroupLimitInfo() { - LLSD args; - - S32 max_basic = LLAgentBenefitsMgr::get("Base").getGroupMembershipLimit(); - S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); - - args["MAX_BASIC"] = max_basic; - args["MAX_PREMIUM"] = max_premium; - - if (LLAgentBenefitsMgr::has("Premium_Plus")) - { - S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium_Plus").getGroupMembershipLimit(); - args["MAX_PREMIUM_PLUS"] = max_premium_plus; - LLNotificationsUtil::add("GroupLimitInfoPlus", args); - } - else - { - LLNotificationsUtil::add("GroupLimitInfo", args); - } + LLSD args; + + S32 max_basic = LLAgentBenefitsMgr::get("Base").getGroupMembershipLimit(); + S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); + + args["MAX_BASIC"] = max_basic; + args["MAX_PREMIUM"] = max_premium; + + if (LLAgentBenefitsMgr::has("Premium_Plus")) + { + S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium_Plus").getGroupMembershipLimit(); + args["MAX_PREMIUM_PLUS"] = max_premium_plus; + LLNotificationsUtil::add("GroupLimitInfoPlus", args); + } + else + { + LLNotificationsUtil::add("GroupLimitInfo", args); + } } void LLPanelPeople::onTabSelected(const LLSD& param) { - std::string tab_name = getChild<LLPanel>(param.asString())->getName(); - updateButtons(); + std::string tab_name = getChild<LLPanel>(param.asString())->getName(); + updateButtons(); - showFriendsAccordionsIfNeeded(); + showFriendsAccordionsIfNeeded(); } void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) { - LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(ctrl); - if(!item) - { - return; - } - - LLUUID clicked_id = item->getAvatarId(); - if(gAgent.getID() == clicked_id) - { - return; - } - + LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(ctrl); + if(!item) + { + return; + } + + LLUUID clicked_id = item->getAvatarId(); + if(gAgent.getID() == clicked_id) + { + return; + } + #if 0 // SJB: Useful for testing, but not currently functional or to spec - LLAvatarActions::showProfile(clicked_id); + LLAvatarActions::showProfile(clicked_id); #else // spec says open IM window - LLAvatarActions::startIM(clicked_id); + LLAvatarActions::startIM(clicked_id); #endif } void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) { - if (getActiveTabName() == NEARBY_TAB_NAME) - { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - mMiniMap->setSelected(selected_uuids); - } else - // Make sure only one of the friends lists (online/all) has selection. - if (getActiveTabName() == FRIENDS_TAB_NAME) - { - if (list == mOnlineFriendList) - mAllFriendList->resetSelection(true); - else if (list == mAllFriendList) - mOnlineFriendList->resetSelection(true); - else - llassert(0 && "commit on unknown friends list"); - } - - updateButtons(); + if (getActiveTabName() == NEARBY_TAB_NAME) + { + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + mMiniMap->setSelected(selected_uuids); + } else + // Make sure only one of the friends lists (online/all) has selection. + if (getActiveTabName() == FRIENDS_TAB_NAME) + { + if (list == mOnlineFriendList) + mAllFriendList->resetSelection(true); + else if (list == mAllFriendList) + mOnlineFriendList->resetSelection(true); + else + llassert(0 && "commit on unknown friends list"); + } + + updateButtons(); } void LLPanelPeople::onAddFriendButtonClicked() { - LLUUID id = getCurrentItemID(); - if (id.notNull()) - { - LLAvatarActions::requestFriendshipDialog(id); - } + LLUUID id = getCurrentItemID(); + if (id.notNull()) + { + LLAvatarActions::requestFriendshipDialog(id); + } } bool LLPanelPeople::isItemsFreeOfFriends(const uuid_vec_t& uuids) { - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - for ( uuid_vec_t::const_iterator - id = uuids.begin(), - id_end = uuids.end(); - id != id_end; ++id ) - { - if (av_tracker.isBuddy (*id)) - { - return false; - } - } - return true; + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + for ( uuid_vec_t::const_iterator + id = uuids.begin(), + id_end = uuids.end(); + id != id_end; ++id ) + { + if (av_tracker.isBuddy (*id)) + { + return false; + } + } + return true; } void LLPanelPeople::onAddFriendWizButtonClicked() @@ -1185,397 +1185,397 @@ void LLPanelPeople::onAddFriendWizButtonClicked() LLPanel* cur_panel = mTabContainer->getCurrentPanel(); LLView * button = cur_panel->findChild<LLButton>("friends_add_btn", TRUE); - // Show add friend wizard. + // Show add friend wizard. LLFloater* root_floater = gFloaterView->getParentFloater(this); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelPeople::onAvatarPicked, _1, _2), FALSE, TRUE, FALSE, root_floater->getName(), button); - if (!picker) - { - return; - } - - // Need to disable 'ok' button when friend occurs in selection - picker->setOkBtnEnableCb(boost::bind(&LLPanelPeople::isItemsFreeOfFriends, this, _1)); - - if (root_floater) - { - root_floater->addDependentFloater(picker); - } + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelPeople::onAvatarPicked, _1, _2), FALSE, TRUE, FALSE, root_floater->getName(), button); + if (!picker) + { + return; + } + + // Need to disable 'ok' button when friend occurs in selection + picker->setOkBtnEnableCb(boost::bind(&LLPanelPeople::isItemsFreeOfFriends, this, _1)); + + if (root_floater) + { + root_floater->addDependentFloater(picker); + } mPicker = picker->getHandle(); } void LLPanelPeople::onDeleteFriendButtonClicked() { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - - if (selected_uuids.size() == 1) - { - LLAvatarActions::removeFriendDialog( selected_uuids.front() ); - } - else if (selected_uuids.size() > 1) - { - LLAvatarActions::removeFriendsDialog( selected_uuids ); - } + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + + if (selected_uuids.size() == 1) + { + LLAvatarActions::removeFriendDialog( selected_uuids.front() ); + } + else if (selected_uuids.size() > 1) + { + LLAvatarActions::removeFriendsDialog( selected_uuids ); + } } void LLPanelPeople::onChatButtonClicked() { - LLUUID group_id = getCurrentItemID(); - if (group_id.notNull()) - LLGroupActions::startIM(group_id); + LLUUID group_id = getCurrentItemID(); + if (group_id.notNull()) + LLGroupActions::startIM(group_id); } void LLPanelPeople::onGearButtonClicked(LLUICtrl* btn) { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - // Spawn at bottom left corner of the button. - if (getActiveTabName() == NEARBY_TAB_NAME) - LLPanelPeopleMenus::gNearbyPeopleContextMenu.show(btn, selected_uuids, 0, 0); - else - LLPanelPeopleMenus::gPeopleContextMenu.show(btn, selected_uuids, 0, 0); + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + // Spawn at bottom left corner of the button. + if (getActiveTabName() == NEARBY_TAB_NAME) + LLPanelPeopleMenus::gNearbyPeopleContextMenu.show(btn, selected_uuids, 0, 0); + else + LLPanelPeopleMenus::gPeopleContextMenu.show(btn, selected_uuids, 0, 0); } void LLPanelPeople::onImButtonClicked() { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - if ( selected_uuids.size() == 1 ) - { - // if selected only one person then start up IM - LLAvatarActions::startIM(selected_uuids.at(0)); - } - else if ( selected_uuids.size() > 1 ) - { - // for multiple selection start up friends conference - LLAvatarActions::startConference(selected_uuids); - } + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + if ( selected_uuids.size() == 1 ) + { + // if selected only one person then start up IM + LLAvatarActions::startIM(selected_uuids.at(0)); + } + else if ( selected_uuids.size() > 1 ) + { + // for multiple selection start up friends conference + LLAvatarActions::startConference(selected_uuids); + } } // static void LLPanelPeople::onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names) { - if (!names.empty() && !ids.empty()) - LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName()); + if (!names.empty() && !ids.empty()) + LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName()); } bool LLPanelPeople::onGroupPlusButtonValidate() { - if (!gAgent.canJoinGroups()) - { - LLNotificationsUtil::add("JoinedTooManyGroups"); - return false; - } + if (!gAgent.canJoinGroups()) + { + LLNotificationsUtil::add("JoinedTooManyGroups"); + return false; + } - return true; + return true; } void LLPanelPeople::onGroupMinusButtonClicked() { - LLUUID group_id = getCurrentItemID(); - if (group_id.notNull()) - LLGroupActions::leave(group_id); + LLUUID group_id = getCurrentItemID(); + if (group_id.notNull()) + LLGroupActions::leave(group_id); } void LLPanelPeople::onGroupPlusMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); + std::string chosen_item = userdata.asString(); - if (chosen_item == "join_group") - LLGroupActions::search(); - else if (chosen_item == "new_group") - LLGroupActions::createGroup(); + if (chosen_item == "join_group") + LLGroupActions::search(); + else if (chosen_item == "new_group") + LLGroupActions::createGroup(); } void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); - - if (chosen_item == "sort_name") - { - setSortOrder(mAllFriendList, E_SORT_BY_NAME); - } - else if (chosen_item == "sort_status") - { - setSortOrder(mAllFriendList, E_SORT_BY_STATUS); - } - else if (chosen_item == "view_icons") - { - mAllFriendList->toggleIcons(); - mOnlineFriendList->toggleIcons(); - } - else if (chosen_item == "view_permissions") - { - bool show_permissions = !gSavedSettings.getBOOL("FriendsListShowPermissions"); - gSavedSettings.setBOOL("FriendsListShowPermissions", show_permissions); - - mAllFriendList->showPermissions(show_permissions); - mOnlineFriendList->showPermissions(show_permissions); - } - else if (chosen_item == "view_usernames") - { - bool hide_usernames = !gSavedSettings.getBOOL("FriendsListHideUsernames"); - gSavedSettings.setBOOL("FriendsListHideUsernames", hide_usernames); - - mAllFriendList->setShowCompleteName(!hide_usernames); - mAllFriendList->handleDisplayNamesOptionChanged(); - mOnlineFriendList->setShowCompleteName(!hide_usernames); - mOnlineFriendList->handleDisplayNamesOptionChanged(); - } - } + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_name") + { + setSortOrder(mAllFriendList, E_SORT_BY_NAME); + } + else if (chosen_item == "sort_status") + { + setSortOrder(mAllFriendList, E_SORT_BY_STATUS); + } + else if (chosen_item == "view_icons") + { + mAllFriendList->toggleIcons(); + mOnlineFriendList->toggleIcons(); + } + else if (chosen_item == "view_permissions") + { + bool show_permissions = !gSavedSettings.getBOOL("FriendsListShowPermissions"); + gSavedSettings.setBOOL("FriendsListShowPermissions", show_permissions); + + mAllFriendList->showPermissions(show_permissions); + mOnlineFriendList->showPermissions(show_permissions); + } + else if (chosen_item == "view_usernames") + { + bool hide_usernames = !gSavedSettings.getBOOL("FriendsListHideUsernames"); + gSavedSettings.setBOOL("FriendsListHideUsernames", hide_usernames); + + mAllFriendList->setShowCompleteName(!hide_usernames); + mAllFriendList->handleDisplayNamesOptionChanged(); + mOnlineFriendList->setShowCompleteName(!hide_usernames); + mOnlineFriendList->handleDisplayNamesOptionChanged(); + } + } void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); + std::string chosen_item = userdata.asString(); - if (chosen_item == "show_icons") - { - mGroupList->toggleIcons(); - } + if (chosen_item == "show_icons") + { + mGroupList->toggleIcons(); + } } void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); - - if (chosen_item == "sort_by_recent_speakers") - { - setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS); - } - else if (chosen_item == "sort_name") - { - setSortOrder(mNearbyList, E_SORT_BY_NAME); - } - else if (chosen_item == "view_icons") - { - mNearbyList->toggleIcons(); - } - else if (chosen_item == "sort_distance") - { - setSortOrder(mNearbyList, E_SORT_BY_DISTANCE); - } - else if (chosen_item == "sort_arrival") - { - setSortOrder(mNearbyList, E_SORT_BY_RECENT_ARRIVAL); - } - else if (chosen_item == "view_usernames") - { - bool hide_usernames = !gSavedSettings.getBOOL("NearbyListHideUsernames"); - gSavedSettings.setBOOL("NearbyListHideUsernames", hide_usernames); - - mNearbyList->setShowCompleteName(!hide_usernames); - mNearbyList->handleDisplayNamesOptionChanged(); - } + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_by_recent_speakers") + { + setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS); + } + else if (chosen_item == "sort_name") + { + setSortOrder(mNearbyList, E_SORT_BY_NAME); + } + else if (chosen_item == "view_icons") + { + mNearbyList->toggleIcons(); + } + else if (chosen_item == "sort_distance") + { + setSortOrder(mNearbyList, E_SORT_BY_DISTANCE); + } + else if (chosen_item == "sort_arrival") + { + setSortOrder(mNearbyList, E_SORT_BY_RECENT_ARRIVAL); + } + else if (chosen_item == "view_usernames") + { + bool hide_usernames = !gSavedSettings.getBOOL("NearbyListHideUsernames"); + gSavedSettings.setBOOL("NearbyListHideUsernames", hide_usernames); + + mNearbyList->setShowCompleteName(!hide_usernames); + mNearbyList->handleDisplayNamesOptionChanged(); + } } bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata) { - std::string item = userdata.asString(); - U32 sort_order = gSavedSettings.getU32("NearbyPeopleSortOrder"); - - if (item == "sort_by_recent_speakers") - return sort_order == E_SORT_BY_RECENT_SPEAKERS; - if (item == "sort_name") - return sort_order == E_SORT_BY_NAME; - if (item == "sort_distance") - return sort_order == E_SORT_BY_DISTANCE; - if (item == "sort_arrival") - return sort_order == E_SORT_BY_RECENT_ARRIVAL; - - return false; + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("NearbyPeopleSortOrder"); + + if (item == "sort_by_recent_speakers") + return sort_order == E_SORT_BY_RECENT_SPEAKERS; + if (item == "sort_name") + return sort_order == E_SORT_BY_NAME; + if (item == "sort_distance") + return sort_order == E_SORT_BY_DISTANCE; + if (item == "sort_arrival") + return sort_order == E_SORT_BY_RECENT_ARRIVAL; + + return false; } void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); - - if (chosen_item == "sort_recent") - { - setSortOrder(mRecentList, E_SORT_BY_MOST_RECENT); - } - else if (chosen_item == "sort_name") - { - setSortOrder(mRecentList, E_SORT_BY_NAME); - } - else if (chosen_item == "view_icons") - { - mRecentList->toggleIcons(); - } + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_recent") + { + setSortOrder(mRecentList, E_SORT_BY_MOST_RECENT); + } + else if (chosen_item == "sort_name") + { + setSortOrder(mRecentList, E_SORT_BY_NAME); + } + else if (chosen_item == "view_icons") + { + mRecentList->toggleIcons(); + } } -bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata) +bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata) { - std::string item = userdata.asString(); - U32 sort_order = gSavedSettings.getU32("FriendsSortOrder"); + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("FriendsSortOrder"); - if (item == "sort_name") - return sort_order == E_SORT_BY_NAME; - if (item == "sort_status") - return sort_order == E_SORT_BY_STATUS; + if (item == "sort_name") + return sort_order == E_SORT_BY_NAME; + if (item == "sort_status") + return sort_order == E_SORT_BY_STATUS; - return false; + return false; } -bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata) +bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata) { - std::string item = userdata.asString(); - U32 sort_order = gSavedSettings.getU32("RecentPeopleSortOrder"); + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("RecentPeopleSortOrder"); - if (item == "sort_recent") - return sort_order == E_SORT_BY_MOST_RECENT; - if (item == "sort_name") - return sort_order == E_SORT_BY_NAME; + if (item == "sort_recent") + return sort_order == E_SORT_BY_MOST_RECENT; + if (item == "sort_name") + return sort_order == E_SORT_BY_NAME; - return false; + return false; } void LLPanelPeople::onMoreButtonClicked() { - // *TODO: not implemented yet + // *TODO: not implemented yet } -void LLPanelPeople::onOpen(const LLSD& key) +void LLPanelPeople::onOpen(const LLSD& key) { - std::string tab_name = key["people_panel_tab_name"]; - if (!tab_name.empty()) - { - mTabContainer->selectTabByName(tab_name); - if(tab_name == BLOCKED_TAB_NAME) - { - LLPanel* blocked_tab = mTabContainer->getCurrentPanel()->findChild<LLPanel>("panel_block_list_sidetray"); - if(blocked_tab) - { - blocked_tab->onOpen(key); - } - } - } + std::string tab_name = key["people_panel_tab_name"]; + if (!tab_name.empty()) + { + mTabContainer->selectTabByName(tab_name); + if(tab_name == BLOCKED_TAB_NAME) + { + LLPanel* blocked_tab = mTabContainer->getCurrentPanel()->findChild<LLPanel>("panel_block_list_sidetray"); + if(blocked_tab) + { + blocked_tab->onOpen(key); + } + } + } } bool LLPanelPeople::notifyChildren(const LLSD& info) { - if (info.has("task-panel-action") && info["task-panel-action"].asString() == "handle-tri-state") - { - LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(getParent()); - if (!container) - { - LL_WARNS() << "Cannot find People panel container" << LL_ENDL; - return true; - } - - if (container->getCurrentPanelIndex() > 0) - { - // if not on the default panel, switch to it - container->onOpen(LLSD().with(LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME, getName())); - } - else - LLFloaterReg::hideInstance("people"); - - return true; // this notification is only supposed to be handled by task panels - } - - return LLPanel::notifyChildren(info); + if (info.has("task-panel-action") && info["task-panel-action"].asString() == "handle-tri-state") + { + LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(getParent()); + if (!container) + { + LL_WARNS() << "Cannot find People panel container" << LL_ENDL; + return true; + } + + if (container->getCurrentPanelIndex() > 0) + { + // if not on the default panel, switch to it + container->onOpen(LLSD().with(LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME, getName())); + } + else + LLFloaterReg::hideInstance("people"); + + return true; // this notification is only supposed to be handled by task panels + } + + return LLPanel::notifyChildren(info); } void LLPanelPeople::showAccordion(const std::string name, bool show) { - if(name.empty()) - { - LL_WARNS() << "No name provided" << LL_ENDL; - return; - } - - LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name); - tab->setVisible(show); - if(show) - { - // don't expand accordion if it was collapsed by user - if(!isAccordionCollapsedByUser(tab)) - { - // expand accordion - tab->changeOpenClose(false); - } - } + if(name.empty()) + { + LL_WARNS() << "No name provided" << LL_ENDL; + return; + } + + LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name); + tab->setVisible(show); + if(show) + { + // don't expand accordion if it was collapsed by user + if(!isAccordionCollapsedByUser(tab)) + { + // expand accordion + tab->changeOpenClose(false); + } + } } void LLPanelPeople::showFriendsAccordionsIfNeeded() { - if(FRIENDS_TAB_NAME == getActiveTabName()) - { - // Expand and show accordions if needed, else - hide them - showAccordion("tab_online", mOnlineFriendList->filterHasMatches()); - showAccordion("tab_all", mAllFriendList->filterHasMatches()); - - // Rearrange accordions - LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion"); - accordion->arrange(); - - // *TODO: new no_matched_tabs_text attribute was implemented in accordion (EXT-7368). - // this code should be refactored to use it - // keep help text in a synchronization with accordions visibility. - updateFriendListHelpText(); - } + if(FRIENDS_TAB_NAME == getActiveTabName()) + { + // Expand and show accordions if needed, else - hide them + showAccordion("tab_online", mOnlineFriendList->filterHasMatches()); + showAccordion("tab_all", mAllFriendList->filterHasMatches()); + + // Rearrange accordions + LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion"); + accordion->arrange(); + + // *TODO: new no_matched_tabs_text attribute was implemented in accordion (EXT-7368). + // this code should be refactored to use it + // keep help text in a synchronization with accordions visibility. + updateFriendListHelpText(); + } } void LLPanelPeople::onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param) { - if(ctrl == mOnlineFriendList) - { - showAccordion("tab_online", param.asInteger()); - } - else if(ctrl == mAllFriendList) - { - showAccordion("tab_all", param.asInteger()); - } + if(ctrl == mOnlineFriendList) + { + showAccordion("tab_online", param.asInteger()); + } + else if(ctrl == mAllFriendList) + { + showAccordion("tab_all", param.asInteger()); + } } void LLPanelPeople::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed) { - if(!acc_tab) - { - LL_WARNS() << "Invalid parameter" << LL_ENDL; - return; - } - - LLSD param = acc_tab->getValue(); - param[COLLAPSED_BY_USER] = collapsed; - acc_tab->setValue(param); + if(!acc_tab) + { + LL_WARNS() << "Invalid parameter" << LL_ENDL; + return; + } + + LLSD param = acc_tab->getValue(); + param[COLLAPSED_BY_USER] = collapsed; + acc_tab->setValue(param); } void LLPanelPeople::setAccordionCollapsedByUser(const std::string& name, bool collapsed) { - setAccordionCollapsedByUser(getChild<LLUICtrl>(name), collapsed); + setAccordionCollapsedByUser(getChild<LLUICtrl>(name), collapsed); } bool LLPanelPeople::isAccordionCollapsedByUser(LLUICtrl* acc_tab) { - if(!acc_tab) - { - LL_WARNS() << "Invalid parameter" << LL_ENDL; - return false; - } - - LLSD param = acc_tab->getValue(); - if(!param.has(COLLAPSED_BY_USER)) - { - return false; - } - return param[COLLAPSED_BY_USER].asBoolean(); + if(!acc_tab) + { + LL_WARNS() << "Invalid parameter" << LL_ENDL; + return false; + } + + LLSD param = acc_tab->getValue(); + if(!param.has(COLLAPSED_BY_USER)) + { + return false; + } + return param[COLLAPSED_BY_USER].asBoolean(); } bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name) { - return isAccordionCollapsedByUser(getChild<LLUICtrl>(name)); + return isAccordionCollapsedByUser(getChild<LLUICtrl>(name)); } bool LLPanelPeople::updateNearbyArrivalTime() { - std::vector<LLVector3d> positions; - std::vector<LLUUID> uuids; - static LLCachedControl<F32> range(gSavedSettings, "NearMeRange"); - LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), range); - LLRecentPeople::instance().updateAvatarsArrivalTime(uuids); - return LLApp::isExiting(); + std::vector<LLVector3d> positions; + std::vector<LLUUID> uuids; + static LLCachedControl<F32> range(gSavedSettings, "NearMeRange"); + LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), range); + LLRecentPeople::instance().updateAvatarsArrivalTime(uuids); + return LLApp::isExiting(); } diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index a6d628e1ad..449654da6a 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsetkeybinddialog.cpp * @brief LLSetKeyBindDialog class implementation. * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2019, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -76,9 +76,9 @@ LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) mContextConeOutAlpha(0.f), mContextConeFadeTime(0.f) { - mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); - mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); - mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } LLSetKeyBindDialog::~LLSetKeyBindDialog() diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 2bc8d04a8e..6799104f9a 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llspeakers.cpp * @brief Management interface for muting and controlling volume of residents currently speaking * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,48 +46,48 @@ extern LLControlGroup gSavedSettings; const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); -LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) : - mStatus(LLSpeaker::STATUS_TEXT_ONLY), - mLastSpokeTime(0.f), - mSpeechVolume(0.f), - mHasSpoken(FALSE), - mHasLeftCurrentCall(FALSE), - mDotColor(LLColor4::white), - mID(id), - mTyping(FALSE), - mSortIndex(0), - mType(type), - mIsModerator(FALSE), - mModeratorMutedVoice(FALSE), - mModeratorMutedText(FALSE) +LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) : + mStatus(LLSpeaker::STATUS_TEXT_ONLY), + mLastSpokeTime(0.f), + mSpeechVolume(0.f), + mHasSpoken(FALSE), + mHasLeftCurrentCall(FALSE), + mDotColor(LLColor4::white), + mID(id), + mTyping(FALSE), + mSortIndex(0), + mType(type), + mIsModerator(FALSE), + mModeratorMutedVoice(FALSE), + mModeratorMutedText(FALSE) { - if (name.empty() && type == SPEAKER_AGENT) - { - lookupName(); - } - else - { - mDisplayName = name; - } + if (name.empty() && type == SPEAKER_AGENT) + { + lookupName(); + } + else + { + mDisplayName = name; + } } void LLSpeaker::lookupName() { - if (mDisplayName.empty()) - { - LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _1, _2)); // todo: can be group??? - } + if (mDisplayName.empty()) + { + LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _1, _2)); // todo: can be group??? + } } void LLSpeaker::onNameCache(const LLUUID& id, const LLAvatarName& av_name) { - mDisplayName = av_name.getUserName(); + mDisplayName = av_name.getUserName(); } bool LLSpeaker::isInVoiceChannel() { - return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED; + return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED; } LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source) @@ -98,9 +98,9 @@ LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source) LLSD LLSpeakerUpdateSpeakerEvent::getValue() { - LLSD ret; - ret["id"] = mSpeakerID; - return ret; + LLSD ret; + ret["id"] = mSpeakerID; + return ret; } LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source) @@ -112,10 +112,10 @@ LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source) LLSD LLSpeakerUpdateModeratorEvent::getValue() { - LLSD ret; - ret["id"] = mSpeakerID; - ret["is_moderator"] = mIsModerator; - return ret; + LLSD ret; + ret["id"] = mSpeakerID; + ret["is_moderator"] = mIsModerator; + return ret; } LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) @@ -125,7 +125,7 @@ LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) LLSD LLSpeakerTextModerationEvent::getValue() { - return std::string("text"); + return std::string("text"); } @@ -136,7 +136,7 @@ LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source) LLSD LLSpeakerVoiceModerationEvent::getValue() { - return std::string("voice"); + return std::string("voice"); } LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id) @@ -147,31 +147,31 @@ LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const L LLSD LLSpeakerListChangeEvent::getValue() { - return mSpeakerID; + return mSpeakerID; } // helper sort class struct LLSortRecentSpeakers { - bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const; + bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const; }; bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const { - // Sort first on status - if (lhs->mStatus != rhs->mStatus) - { - return (lhs->mStatus < rhs->mStatus); - } - - // and then on last speaking time - if(lhs->mLastSpokeTime != rhs->mLastSpokeTime) - { - return (lhs->mLastSpokeTime > rhs->mLastSpokeTime); - } - - // and finally (only if those are both equal), on name. - return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); + // Sort first on status + if (lhs->mStatus != rhs->mStatus) + { + return (lhs->mStatus < rhs->mStatus); + } + + // and then on last speaking time + if(lhs->mLastSpokeTime != rhs->mLastSpokeTime) + { + return (lhs->mLastSpokeTime > rhs->mLastSpokeTime); + } + + // and finally (only if those are both equal), on name. + return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); } LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id) @@ -183,16 +183,16 @@ LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 acti bool LLSpeakerActionTimer::tick() { - if (mActionCallback) - { - return (BOOL)mActionCallback(mSpeakerId); - } - return true; + if (mActionCallback) + { + return (BOOL)mActionCallback(mSpeakerId); + } + return true; } void LLSpeakerActionTimer::unset() { - mActionCallback = 0; + mActionCallback = 0; } LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay) @@ -203,454 +203,454 @@ LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTime LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage() { - removeAllTimers(); + removeAllTimers(); } void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) { - bool not_found = true; - if (mActionTimersMap.size() > 0) - { - not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); - } - - // If there is already a started timer for the passed UUID don't do anything. - if (not_found) - { - // Starting a timer to remove an participant after delay is completed - mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id, - new LLSpeakerActionTimer( - boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1), - mActionDelay, speaker_id))); - } + bool not_found = true; + if (mActionTimersMap.size() > 0) + { + not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); + } + + // If there is already a started timer for the passed UUID don't do anything. + if (not_found) + { + // Starting a timer to remove an participant after delay is completed + mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id, + new LLSpeakerActionTimer( + boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1), + mActionDelay, speaker_id))); + } } void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id) { - if (mActionTimersMap.size() == 0) return; + if (mActionTimersMap.size() == 0) return; - LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); + LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); - if (it_speaker != mActionTimersMap.end()) - { - it_speaker->second->unset(); - mActionTimersMap.erase(it_speaker); - } + if (it_speaker != mActionTimersMap.end()) + { + it_speaker->second->unset(); + mActionTimersMap.erase(it_speaker); + } } void LLSpeakersDelayActionsStorage::removeAllTimers() { - LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin(); - for (; iter != mActionTimersMap.end(); ++iter) - { - delete iter->second; - } - mActionTimersMap.clear(); + LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin(); + for (; iter != mActionTimersMap.end(); ++iter) + { + delete iter->second; + } + mActionTimersMap.clear(); } bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_id) { - unsetActionTimer(speaker_id); + unsetActionTimer(speaker_id); - if (mActionCallback) - { - mActionCallback(speaker_id); - } + if (mActionCallback) + { + mActionCallback(speaker_id); + } - return true; + return true; } bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id) { - return (mActionTimersMap.size() > 0) && (mActionTimersMap.find(speaker_id) != mActionTimersMap.end()); + return (mActionTimersMap.size() > 0) && (mActionTimersMap.find(speaker_id) != mActionTimersMap.end()); } // // LLSpeakerMgr // -LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : - mVoiceChannel(channelp), - mVoiceModerated(false), - mModerateModeHandledFirstTime(false), - mSpeakerListUpdated(false) +LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : + mVoiceChannel(channelp), + mVoiceModerated(false), + mModerateModeHandledFirstTime(false), + mSpeakerListUpdated(false) { mGetListTime.reset(); - static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0); + static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0); - mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); + mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); } LLSpeakerMgr::~LLSpeakerMgr() { - delete mSpeakerDelayRemover; + delete mSpeakerDelayRemover; } LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) { - LLUUID session_id = getSessionID(); - if (id.isNull() || (id == session_id)) - { - return NULL; - } - - LLPointer<LLSpeaker> speakerp; - if (mSpeakers.find(id) == mSpeakers.end()) - { - speakerp = new LLSpeaker(id, name, type); - speakerp->mStatus = status; - mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); - mSpeakersSorted.push_back(speakerp); - LL_DEBUGS("Speakers") << "Added speaker " << id << LL_ENDL; - fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); - } - else - { - speakerp = findSpeaker(id); - if (speakerp.notNull()) - { - // keep highest priority status (lowest value) instead of overriding current value - speakerp->mStatus = llmin(speakerp->mStatus, status); - // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id - // we need to override speakers that we think are objects when we find out they are really - // residents - if (type == LLSpeaker::SPEAKER_AGENT) - { - speakerp->mType = LLSpeaker::SPEAKER_AGENT; - speakerp->lookupName(); - } - } - else - { - LL_WARNS("Speakers") << "Speaker " << id << " not found" << LL_ENDL; - } - } - - mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); - return speakerp; + LLUUID session_id = getSessionID(); + if (id.isNull() || (id == session_id)) + { + return NULL; + } + + LLPointer<LLSpeaker> speakerp; + if (mSpeakers.find(id) == mSpeakers.end()) + { + speakerp = new LLSpeaker(id, name, type); + speakerp->mStatus = status; + mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); + mSpeakersSorted.push_back(speakerp); + LL_DEBUGS("Speakers") << "Added speaker " << id << LL_ENDL; + fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); + } + else + { + speakerp = findSpeaker(id); + if (speakerp.notNull()) + { + // keep highest priority status (lowest value) instead of overriding current value + speakerp->mStatus = llmin(speakerp->mStatus, status); + // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id + // we need to override speakers that we think are objects when we find out they are really + // residents + if (type == LLSpeaker::SPEAKER_AGENT) + { + speakerp->mType = LLSpeaker::SPEAKER_AGENT; + speakerp->lookupName(); + } + } + else + { + LL_WARNS("Speakers") << "Speaker " << id << " not found" << LL_ENDL; + } + } + + mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); + return speakerp; } // *TODO: Once way to request the current voice channel moderation mode is implemented // this method with related code should be removed. /* Initializes "moderate_mode" of voice session on first join. - + This is WORKAROUND because a way to request the current voice channel moderation mode exists but is not implemented in viewer yet. See EXT-6937. */ void LLSpeakerMgr::initVoiceModerateMode() { - if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive())) - { - LLPointer<LLSpeaker> speakerp; - - if (mSpeakers.find(gAgentID) != mSpeakers.end()) - { - speakerp = mSpeakers[gAgentID]; - } - - if (speakerp.notNull()) - { - mVoiceModerated = speakerp->mModeratorMutedVoice; - mModerateModeHandledFirstTime = true; - } - } + if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive())) + { + LLPointer<LLSpeaker> speakerp; + + if (mSpeakers.find(gAgentID) != mSpeakers.end()) + { + speakerp = mSpeakers[gAgentID]; + } + + if (speakerp.notNull()) + { + mVoiceModerated = speakerp->mModeratorMutedVoice; + mModerateModeHandledFirstTime = true; + } + } } void LLSpeakerMgr::update(BOOL resort_ok) { - if (!LLVoiceClient::getInstance()) - { - return; - } - - LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor"); - LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor"); - - if(resort_ok) // only allow list changes when user is not interacting with it - { - updateSpeakerList(); - } - - // update status of all current speakers - BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) - { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; - - if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) - { - speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); - BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); - if (moderator_muted_voice != speakerp->mModeratorMutedVoice) - { - speakerp->mModeratorMutedVoice = moderator_muted_voice; - LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< LL_ENDL; - speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); - } - - if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) - { - speakerp->mStatus = LLSpeaker::STATUS_MUTED; - } - else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) - { - // reset inactivity expiration - if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) - { - speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); - speakerp->mHasSpoken = TRUE; - fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); - } - speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; - // interpolate between active color and full speaking color based on power of speech output - speakerp->mDotColor = speaking_color; - if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) - { - speakerp->mDotColor = overdriven_color; - } - } - else - { - speakerp->mSpeechVolume = 0.f; - speakerp->mDotColor = ACTIVE_COLOR; - - if (speakerp->mHasSpoken) - { - // have spoken once, not currently speaking - speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; - } - else - { - // default state for being in voice channel - speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; - } - } - } - // speaker no longer registered in voice channel, demote to text only - else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL) - { - if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) - { - // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - } - else - { - speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; - speakerp->mSpeechVolume = 0.f; - speakerp->mDotColor = ACTIVE_COLOR; - } - } - } - - if(resort_ok) // only allow list changes when user is not interacting with it - { - // sort by status then time last spoken - std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); - } - - // for recent speakers who are not currently speaking, show "recent" color dot for most recent - // fading to "active" color - - S32 recent_speaker_count = 0; - S32 sort_index = 0; - speaker_list_t::iterator sorted_speaker_it; - for(sorted_speaker_it = mSpeakersSorted.begin(); - sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) - { - LLPointer<LLSpeaker> speakerp = *sorted_speaker_it; - - // color code recent speakers who are not currently speaking - if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) - { - speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); - recent_speaker_count++; - } - - // stuff sort ordinal into speaker so the ui can sort by this value - speakerp->mSortIndex = sort_index++; - } + if (!LLVoiceClient::getInstance()) + { + return; + } + + LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor"); + LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor"); + + if(resort_ok) // only allow list changes when user is not interacting with it + { + updateSpeakerList(); + } + + // update status of all current speakers + BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) + { + LLUUID speaker_id = speaker_it->first; + LLSpeaker* speakerp = speaker_it->second; + + if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) + { + speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); + BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); + if (moderator_muted_voice != speakerp->mModeratorMutedVoice) + { + speakerp->mModeratorMutedVoice = moderator_muted_voice; + LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< LL_ENDL; + speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); + } + + if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) + { + speakerp->mStatus = LLSpeaker::STATUS_MUTED; + } + else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) + { + // reset inactivity expiration + if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) + { + speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); + speakerp->mHasSpoken = TRUE; + fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); + } + speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; + // interpolate between active color and full speaking color based on power of speech output + speakerp->mDotColor = speaking_color; + if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) + { + speakerp->mDotColor = overdriven_color; + } + } + else + { + speakerp->mSpeechVolume = 0.f; + speakerp->mDotColor = ACTIVE_COLOR; + + if (speakerp->mHasSpoken) + { + // have spoken once, not currently speaking + speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; + } + else + { + // default state for being in voice channel + speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; + } + } + } + // speaker no longer registered in voice channel, demote to text only + else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL) + { + if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) + { + // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + } + else + { + speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; + speakerp->mSpeechVolume = 0.f; + speakerp->mDotColor = ACTIVE_COLOR; + } + } + } + + if(resort_ok) // only allow list changes when user is not interacting with it + { + // sort by status then time last spoken + std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); + } + + // for recent speakers who are not currently speaking, show "recent" color dot for most recent + // fading to "active" color + + S32 recent_speaker_count = 0; + S32 sort_index = 0; + speaker_list_t::iterator sorted_speaker_it; + for(sorted_speaker_it = mSpeakersSorted.begin(); + sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) + { + LLPointer<LLSpeaker> speakerp = *sorted_speaker_it; + + // color code recent speakers who are not currently speaking + if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) + { + speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); + recent_speaker_count++; + } + + // stuff sort ordinal into speaker so the ui can sort by this value + speakerp->mSortIndex = sort_index++; + } } void LLSpeakerMgr::updateSpeakerList() { - // Are we bound to the currently active voice channel? - if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) - { - std::set<LLUUID> participants; - LLVoiceClient::getInstance()->getParticipantList(participants); - // If we are, add all voice client participants to our list of known speakers - for (std::set<LLUUID>::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) - { - setSpeaker(*participant_it, - LLVoiceClient::getInstance()->getDisplayName(*participant_it), - LLSpeaker::STATUS_VOICE_ACTIVE, - (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); - } - } - else - { - // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). - LLUUID session_id = getSessionID(); - if (!session_id.isNull() && !mSpeakerListUpdated) - { - // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long. - // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started. - // (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply) - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); - if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) - { - // For groups, we need to hit the group manager. - // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); - - if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) - { - // Add group members when we get the complete list (note: can take a while before we get that list) - LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); + // Are we bound to the currently active voice channel? + if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) + { + std::set<LLUUID> participants; + LLVoiceClient::getInstance()->getParticipantList(participants); + // If we are, add all voice client participants to our list of known speakers + for (std::set<LLUUID>::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) + { + setSpeaker(*participant_it, + LLVoiceClient::getInstance()->getDisplayName(*participant_it), + LLSpeaker::STATUS_VOICE_ACTIVE, + (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); + } + } + else + { + // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). + LLUUID session_id = getSessionID(); + if (!session_id.isNull() && !mSpeakerListUpdated) + { + // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long. + // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started. + // (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply) + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) + { + // For groups, we need to hit the group manager. + // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); + + if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + { + // Add group members when we get the complete list (note: can take a while before we get that list) + LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); const S32 load_group_max_members = gSavedSettings.getS32("ChatLoadGroupMaxMembers"); S32 updated = 0; - while (member_it != gdatap->mMembers.end()) - { - LLGroupMemberData* member = member_it->second; + while (member_it != gdatap->mMembers.end()) + { + LLGroupMemberData* member = member_it->second; LLUUID id = member_it->first; - // Add only members who are online and not already in the list - if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end())) - { - LLPointer<LLSpeaker> speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); - speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); + // Add only members who are online and not already in the list + if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end())) + { + LLPointer<LLSpeaker> speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); updated++; - } - ++member_it; + } + ++member_it; // Limit the number of "manually updated" participants to a reasonable number to avoid severe fps drop // *TODO : solve the perf issue of having several hundreds of widgets in the conversation list if (updated >= load_group_max_members) break; - } + } mSpeakerListUpdated = true; - } - } - else if (mSpeakers.size() == 0) - { - // For all other session type (ad-hoc, P2P), we use the initial participants targets list - for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it) - { - // Add buddies if they are on line, add any other avatar. - if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it)) - { - setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); - } - } - mSpeakerListUpdated = true; - } - else - { - // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server) - mSpeakerListUpdated = true; - } - } - } - // Always add the current agent (it has to be there...). Will do nothing if already there. - setSpeaker(gAgentID, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + } + } + else if (mSpeakers.size() == 0) + { + // For all other session type (ad-hoc, P2P), we use the initial participants targets list + for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it) + { + // Add buddies if they are on line, add any other avatar. + if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it)) + { + setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + } + } + mSpeakerListUpdated = true; + } + else + { + // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server) + mSpeakerListUpdated = true; + } + } + } + // Always add the current agent (it has to be there...). Will do nothing if already there. + setSpeaker(gAgentID, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); } void LLSpeakerMgr::setSpeakerNotInChannel(LLPointer<LLSpeaker> speakerp) { - if (speakerp.notNull()) - { - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - speakerp->mDotColor = INACTIVE_COLOR; - mSpeakerDelayRemover->setActionTimer(speakerp->mID); - } + if (speakerp.notNull()) + { + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + speakerp->mDotColor = INACTIVE_COLOR; + mSpeakerDelayRemover->setActionTimer(speakerp->mID); + } } bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) { - mSpeakers.erase(speaker_id); + mSpeakers.erase(speaker_id); - speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); - - for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) - { - if (speaker_id == (*sorted_speaker_it)->mID) - { - mSpeakersSorted.erase(sorted_speaker_it); - break; - } - } + speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); - LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << LL_ENDL; - fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); + for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) + { + if (speaker_id == (*sorted_speaker_it)->mID) + { + mSpeakersSorted.erase(sorted_speaker_it); + break; + } + } + + LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << LL_ENDL; + fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); - update(TRUE); + update(TRUE); - return false; + return false; } LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) { - //In some conditions map causes crash if it is empty(Windows only), adding check (EK) - if (mSpeakers.size() == 0) - return NULL; - speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); - if (found_it == mSpeakers.end()) - { - return NULL; - } - return found_it->second; + //In some conditions map causes crash if it is empty(Windows only), adding check (EK) + if (mSpeakers.size() == 0) + return NULL; + speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); + if (found_it == mSpeakers.end()) + { + return NULL; + } + return found_it->second; } void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text) { - speaker_list->clear(); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLPointer<LLSpeaker> speakerp = speaker_it->second; - // what about text only muted or inactive? - if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) - { - speaker_list->push_back(speakerp); - } - } + speaker_list->clear(); + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLPointer<LLSpeaker> speakerp = speaker_it->second; + // what about text only muted or inactive? + if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) + { + speaker_list->push_back(speakerp); + } + } } -const LLUUID LLSpeakerMgr::getSessionID() -{ - return mVoiceChannel->getSessionID(); +const LLUUID LLSpeakerMgr::getSessionID() +{ + return mVoiceChannel->getSessionID(); } bool LLSpeakerMgr::isSpeakerToBeRemoved(const LLUUID& speaker_id) { - return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id); + return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id); } void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing) { - LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); - if (speakerp.notNull()) - { - speakerp->mTyping = typing; - } + LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); + if (speakerp.notNull()) + { + speakerp->mTyping = typing; + } } // speaker has chatted via either text or voice void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id) { - LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); - if (speakerp.notNull()) - { - speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); - speakerp->mHasSpoken = TRUE; - fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); - } + LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); + if (speakerp.notNull()) + { + speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); + speakerp->mHasSpoken = TRUE; + fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); + } } BOOL LLSpeakerMgr::isVoiceActive() { - // mVoiceChannel = NULL means current voice channel, whatever it is - return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); + // mVoiceChannel = NULL means current voice channel, whatever it is + return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); } @@ -663,170 +663,170 @@ LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel) void LLIMSpeakerMgr::updateSpeakerList() { - // don't do normal updates which are pulled from voice channel - // rely on user list reported by sim - - // We need to do this to allow PSTN callers into group chats to show in the list. - LLSpeakerMgr::updateSpeakerList(); - - return; + // don't do normal updates which are pulled from voice channel + // rely on user list reported by sim + + // We need to do this to allow PSTN callers into group chats to show in the list. + LLSpeakerMgr::updateSpeakerList(); + + return; } void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers) { - if ( !speakers.isMap() ) return; - - if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) - { - LLSD::map_const_iterator speaker_it; - for(speaker_it = speakers["agent_info"].beginMap(); - speaker_it != speakers["agent_info"].endMap(); - ++speaker_it) - { - LLUUID agent_id(speaker_it->first); - - LLPointer<LLSpeaker> speakerp = setSpeaker( - agent_id, - LLStringUtil::null, - LLSpeaker::STATUS_TEXT_ONLY); - - if ( speaker_it->second.isMap() ) - { - BOOL is_moderator = speakerp->mIsModerator; - speakerp->mIsModerator = speaker_it->second["is_moderator"]; - speakerp->mModeratorMutedText = - speaker_it->second["mutes"]["text"]; - // Fire event only if moderator changed - if ( is_moderator != speakerp->mIsModerator ) - { - LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; - fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); - } - } - } - } - else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) - { - //older, more decprecated way. Need here for - //using older version of servers - LLSD::array_const_iterator speaker_it; - for(speaker_it = speakers["agents"].beginArray(); - speaker_it != speakers["agents"].endArray(); - ++speaker_it) - { - const LLUUID agent_id = (*speaker_it).asUUID(); - - LLPointer<LLSpeaker> speakerp = setSpeaker( - agent_id, - LLStringUtil::null, - LLSpeaker::STATUS_TEXT_ONLY); - } - } + if ( !speakers.isMap() ) return; + + if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) + { + LLSD::map_const_iterator speaker_it; + for(speaker_it = speakers["agent_info"].beginMap(); + speaker_it != speakers["agent_info"].endMap(); + ++speaker_it) + { + LLUUID agent_id(speaker_it->first); + + LLPointer<LLSpeaker> speakerp = setSpeaker( + agent_id, + LLStringUtil::null, + LLSpeaker::STATUS_TEXT_ONLY); + + if ( speaker_it->second.isMap() ) + { + BOOL is_moderator = speakerp->mIsModerator; + speakerp->mIsModerator = speaker_it->second["is_moderator"]; + speakerp->mModeratorMutedText = + speaker_it->second["mutes"]["text"]; + // Fire event only if moderator changed + if ( is_moderator != speakerp->mIsModerator ) + { + LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; + fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); + } + } + } + } + else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) + { + //older, more decprecated way. Need here for + //using older version of servers + LLSD::array_const_iterator speaker_it; + for(speaker_it = speakers["agents"].beginArray(); + speaker_it != speakers["agents"].endArray(); + ++speaker_it) + { + const LLUUID agent_id = (*speaker_it).asUUID(); + + LLPointer<LLSpeaker> speakerp = setSpeaker( + agent_id, + LLStringUtil::null, + LLSpeaker::STATUS_TEXT_ONLY); + } + } } void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) { - if ( !update.isMap() ) return; - - if ( update.has("agent_updates") && update["agent_updates"].isMap() ) - { - LLSD::map_const_iterator update_it; - for( - update_it = update["agent_updates"].beginMap(); - update_it != update["agent_updates"].endMap(); - ++update_it) - { - LLUUID agent_id(update_it->first); - LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); - - LLSD agent_data = update_it->second; - - if (agent_data.isMap() && agent_data.has("transition")) - { - if (agent_data["transition"].asString() == "LEAVE") - { - setSpeakerNotInChannel(speakerp); - } - else if (agent_data["transition"].asString() == "ENTER") - { - // add or update speaker - speakerp = setSpeaker(agent_id); - } - else - { - LL_WARNS() << "bad membership list update from 'agent_updates' for agent " << agent_id << ", transition " << ll_print_sd(agent_data["transition"]) << LL_ENDL; - } - } - - if (speakerp.isNull()) continue; - - // should have a valid speaker from this point on - if (agent_data.isMap() && agent_data.has("info")) - { - LLSD agent_info = agent_data["info"]; - - if (agent_info.has("is_moderator")) - { - BOOL is_moderator = speakerp->mIsModerator; - speakerp->mIsModerator = agent_info["is_moderator"]; - // Fire event only if moderator changed - if ( is_moderator != speakerp->mIsModerator ) - { - LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; - fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); - } - } - - if (agent_info.has("mutes")) - { - speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; - } - } - } - } - else if ( update.has("updates") && update["updates"].isMap() ) - { - LLSD::map_const_iterator update_it; - for ( - update_it = update["updates"].beginMap(); - update_it != update["updates"].endMap(); - ++update_it) - { - LLUUID agent_id(update_it->first); - LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); - - std::string agent_transition = update_it->second.asString(); - if (agent_transition == "LEAVE") - { - setSpeakerNotInChannel(speakerp); - } - else if ( agent_transition == "ENTER") - { - // add or update speaker - speakerp = setSpeaker(agent_id); - } - else - { - LL_WARNS() << "bad membership list update from 'updates' for agent " << agent_id << ", transition " << agent_transition << LL_ENDL; - } - } - } + if ( !update.isMap() ) return; + + if ( update.has("agent_updates") && update["agent_updates"].isMap() ) + { + LLSD::map_const_iterator update_it; + for( + update_it = update["agent_updates"].beginMap(); + update_it != update["agent_updates"].endMap(); + ++update_it) + { + LLUUID agent_id(update_it->first); + LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); + + LLSD agent_data = update_it->second; + + if (agent_data.isMap() && agent_data.has("transition")) + { + if (agent_data["transition"].asString() == "LEAVE") + { + setSpeakerNotInChannel(speakerp); + } + else if (agent_data["transition"].asString() == "ENTER") + { + // add or update speaker + speakerp = setSpeaker(agent_id); + } + else + { + LL_WARNS() << "bad membership list update from 'agent_updates' for agent " << agent_id << ", transition " << ll_print_sd(agent_data["transition"]) << LL_ENDL; + } + } + + if (speakerp.isNull()) continue; + + // should have a valid speaker from this point on + if (agent_data.isMap() && agent_data.has("info")) + { + LLSD agent_info = agent_data["info"]; + + if (agent_info.has("is_moderator")) + { + BOOL is_moderator = speakerp->mIsModerator; + speakerp->mIsModerator = agent_info["is_moderator"]; + // Fire event only if moderator changed + if ( is_moderator != speakerp->mIsModerator ) + { + LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; + fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); + } + } + + if (agent_info.has("mutes")) + { + speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; + } + } + } + } + else if ( update.has("updates") && update["updates"].isMap() ) + { + LLSD::map_const_iterator update_it; + for ( + update_it = update["updates"].beginMap(); + update_it != update["updates"].endMap(); + ++update_it) + { + LLUUID agent_id(update_it->first); + LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); + + std::string agent_transition = update_it->second.asString(); + if (agent_transition == "LEAVE") + { + setSpeakerNotInChannel(speakerp); + } + else if ( agent_transition == "ENTER") + { + // add or update speaker + speakerp = setSpeaker(agent_id); + } + else + { + LL_WARNS() << "bad membership list update from 'updates' for agent " << agent_id << ", transition " << agent_transition << LL_ENDL; + } + } + } } void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { - LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); - if (!speakerp) return; - - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "mute update"; - data["session-id"] = getSessionID(); - data["params"] = LLSD::emptyMap(); - data["params"]["agent_id"] = speaker_id; - data["params"]["mute_info"] = LLSD::emptyMap(); - //current value represents ability to type, so invert - data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; + LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); + if (!speakerp) return; + + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "mute update"; + data["session-id"] = getSessionID(); + data["params"] = LLSD::emptyMap(); + data["params"]["agent_id"] = speaker_id; + data["params"]["mute_info"] = LLSD::emptyMap(); + //current value represents ability to type, so invert + data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); @@ -834,24 +834,24 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute) { - LLPointer<LLSpeaker> speakerp = findSpeaker(avatar_id); - if (!speakerp) return; + LLPointer<LLSpeaker> speakerp = findSpeaker(avatar_id); + if (!speakerp) return; - // *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for - // text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) - bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED; + // *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for + // text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) + bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED; - // do not send voice moderation changes for avatars not in voice channel - if (!is_in_voice) return; + // do not send voice moderation changes for avatars not in voice channel + if (!is_in_voice) return; - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "mute update"; - data["session-id"] = getSessionID(); - data["params"] = LLSD::emptyMap(); - data["params"]["agent_id"] = avatar_id; - data["params"]["mute_info"] = LLSD::emptyMap(); - data["params"]["mute_info"]["voice"] = !unmute; + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "mute update"; + data["session-id"] = getSessionID(); + data["params"] = LLSD::emptyMap(); + data["params"]["agent_id"] = avatar_id; + data["params"]["mute_info"] = LLSD::emptyMap(); + data["params"]["mute_info"]["voice"] = !unmute; LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); @@ -901,39 +901,39 @@ void LLIMSpeakerMgr::moderationActionCoro(std::string url, LLSD action) void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone ) { - if (mVoiceModerated == !unmute_everyone) - { - // session already in requested state. Just force participants which do not match it. - forceVoiceModeratedMode(mVoiceModerated); - } - else - { - // otherwise set moderated mode for a whole session. - moderateVoiceSession(getSessionID(), !unmute_everyone); - } + if (mVoiceModerated == !unmute_everyone) + { + // session already in requested state. Just force participants which do not match it. + forceVoiceModeratedMode(mVoiceModerated); + } + else + { + // otherwise set moderated mode for a whole session. + moderateVoiceSession(getSessionID(), !unmute_everyone); + } } void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update) { - if (session_update.has("moderated_mode") && - session_update["moderated_mode"].has("voice")) - { - mVoiceModerated = session_update["moderated_mode"]["voice"]; - } + if (session_update.has("moderated_mode") && + session_update["moderated_mode"].has("voice")) + { + mVoiceModerated = session_update["moderated_mode"]["voice"]; + } } void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice) { - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "session update"; - data["session-id"] = session_id; - data["params"] = LLSD::emptyMap(); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "session update"; + data["session-id"] = session_id; + data["params"] = LLSD::emptyMap(); - data["params"]["update_info"] = LLSD::emptyMap(); + data["params"]["update_info"] = LLSD::emptyMap(); - data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap(); - data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; + data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap(); + data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); @@ -941,17 +941,17 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted) { - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; - - // participant does not match requested state - if (should_be_muted != (bool)speakerp->mModeratorMutedVoice) - { - moderateVoiceParticipant(speaker_id, !should_be_muted); - } - } + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLUUID speaker_id = speaker_it->first; + LLSpeaker* speakerp = speaker_it->second; + + // participant does not match requested state + if (should_be_muted != (bool)speakerp->mModeratorMutedVoice) + { + moderateVoiceParticipant(speaker_id, !should_be_muted); + } + } } // @@ -964,31 +964,31 @@ LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL) void LLActiveSpeakerMgr::updateSpeakerList() { - // point to whatever the current voice channel is - mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); - - // always populate from active voice channel - if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false - { - LL_DEBUGS("Speakers") << "Removed all speakers" << LL_ENDL; - fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); - mSpeakers.clear(); - mSpeakersSorted.clear(); - mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); - mSpeakerDelayRemover->removeAllTimers(); - } - LLSpeakerMgr::updateSpeakerList(); - - // clean up text only speakers - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLSpeaker* speakerp = speaker_it->second; - if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) - { - // automatically flag text only speakers for removal - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - } - } + // point to whatever the current voice channel is + mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + + // always populate from active voice channel + if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false + { + LL_DEBUGS("Speakers") << "Removed all speakers" << LL_ENDL; + fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); + mSpeakers.clear(); + mSpeakersSorted.clear(); + mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + mSpeakerDelayRemover->removeAllTimers(); + } + LLSpeakerMgr::updateSpeakerList(); + + // clean up text only speakers + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLSpeaker* speakerp = speaker_it->second; + if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) + { + // automatically flag text only speakers for removal + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + } + } } @@ -1008,35 +1008,35 @@ LLLocalSpeakerMgr::~LLLocalSpeakerMgr () void LLLocalSpeakerMgr::updateSpeakerList() { - // pull speakers from voice channel - LLSpeakerMgr::updateSpeakerList(); - - if (gDisconnected)//the world is cleared. - { - return ; - } - - // pick up non-voice speakers in chat range - uuid_vec_t avatar_ids; - std::vector<LLVector3d> positions; - LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); - for(U32 i=0; i<avatar_ids.size(); i++) - { - setSpeaker(avatar_ids[i]); - } - - // check if text only speakers have moved out of chat range - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLUUID speaker_id = speaker_it->first; - LLPointer<LLSpeaker> speakerp = speaker_it->second; - if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) - { - LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); - if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS) - { - setSpeakerNotInChannel(speakerp); - } - } - } + // pull speakers from voice channel + LLSpeakerMgr::updateSpeakerList(); + + if (gDisconnected)//the world is cleared. + { + return ; + } + + // pick up non-voice speakers in chat range + uuid_vec_t avatar_ids; + std::vector<LLVector3d> positions; + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); + for(U32 i=0; i<avatar_ids.size(); i++) + { + setSpeaker(avatar_ids[i]); + } + + // check if text only speakers have moved out of chat range + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLUUID speaker_id = speaker_it->first; + LLPointer<LLSpeaker> speakerp = speaker_it->second; + if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) + { + LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); + if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS) + { + setSpeakerNotInChannel(speakerp); + } + } + } } diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 0242da1605..234de42953 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -1,25 +1,25 @@ -/** +/** * @file llspeakers.h * @brief Management interface for muting and controlling volume of residents currently speaking * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,94 +40,94 @@ class LLAvatarName; class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable { public: - typedef enum e_speaker_type - { - SPEAKER_AGENT, - SPEAKER_OBJECT, - SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group) - } ESpeakerType; - - typedef enum e_speaker_status - { - STATUS_SPEAKING, - STATUS_HAS_SPOKEN, - STATUS_VOICE_ACTIVE, - STATUS_TEXT_ONLY, - STATUS_NOT_IN_CHANNEL, - STATUS_MUTED - } ESpeakerStatus; - - - LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); - ~LLSpeaker() {}; - void lookupName(); - - void onNameCache(const LLUUID& id, const LLAvatarName& full_name); - - bool isInVoiceChannel(); - - ESpeakerStatus mStatus; // current activity status in speech group - F32 mLastSpokeTime; // timestamp when this speaker last spoke - F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?) - std::string mDisplayName; // cache user name for this speaker - BOOL mHasSpoken; // has this speaker said anything this session? - BOOL mHasLeftCurrentCall; // has this speaker left the current voice call? - LLColor4 mDotColor; - LLUUID mID; - BOOL mTyping; - S32 mSortIndex; - ESpeakerType mType; - BOOL mIsModerator; - BOOL mModeratorMutedVoice; - BOOL mModeratorMutedText; + typedef enum e_speaker_type + { + SPEAKER_AGENT, + SPEAKER_OBJECT, + SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group) + } ESpeakerType; + + typedef enum e_speaker_status + { + STATUS_SPEAKING, + STATUS_HAS_SPOKEN, + STATUS_VOICE_ACTIVE, + STATUS_TEXT_ONLY, + STATUS_NOT_IN_CHANNEL, + STATUS_MUTED + } ESpeakerStatus; + + + LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); + ~LLSpeaker() {}; + void lookupName(); + + void onNameCache(const LLUUID& id, const LLAvatarName& full_name); + + bool isInVoiceChannel(); + + ESpeakerStatus mStatus; // current activity status in speech group + F32 mLastSpokeTime; // timestamp when this speaker last spoke + F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?) + std::string mDisplayName; // cache user name for this speaker + BOOL mHasSpoken; // has this speaker said anything this session? + BOOL mHasLeftCurrentCall; // has this speaker left the current voice call? + LLColor4 mDotColor; + LLUUID mID; + BOOL mTyping; + S32 mSortIndex; + ESpeakerType mType; + BOOL mIsModerator; + BOOL mModeratorMutedVoice; + BOOL mModeratorMutedText; }; class LLSpeakerUpdateSpeakerEvent : public LLOldEvents::LLEvent { public: - LLSpeakerUpdateSpeakerEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerUpdateSpeakerEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); private: - const LLUUID& mSpeakerID; + const LLUUID& mSpeakerID; }; class LLSpeakerUpdateModeratorEvent : public LLOldEvents::LLEvent { public: - LLSpeakerUpdateModeratorEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerUpdateModeratorEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); private: - const LLUUID& mSpeakerID; - BOOL mIsModerator; + const LLUUID& mSpeakerID; + BOOL mIsModerator; }; class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent { public: - LLSpeakerTextModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerTextModerationEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); }; class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent { public: - LLSpeakerVoiceModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerVoiceModerationEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); }; class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent { public: - LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); - /*virtual*/ LLSD getValue(); + LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); + /*virtual*/ LLSD getValue(); private: - const LLUUID& mSpeakerID; + const LLUUID& mSpeakerID; }; /** * class LLSpeakerActionTimer - * + * * Implements a timer that calls stored callback action for stored speaker after passed period. * * Action is called until callback returns "true". @@ -138,39 +138,39 @@ private: class LLSpeakerActionTimer : public LLEventTimer { public: - typedef boost::function<bool(const LLUUID&)> action_callback_t; - typedef std::map<LLUUID, LLSpeakerActionTimer*> action_timers_map_t; - typedef action_timers_map_t::value_type action_value_t; - typedef action_timers_map_t::const_iterator action_timer_const_iter_t; - typedef action_timers_map_t::iterator action_timer_iter_t; - - /** - * Constructor. - * - * @param action_cb - callback which will be called each time after passed action period. - * @param action_period - time in seconds timer should tick. - * @param speaker_id - LLUUID of speaker which will be passed into action callback. - */ - LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); - virtual ~LLSpeakerActionTimer() {}; - - /** - * Implements timer "tick". - * - * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). - */ - bool tick() override; - - /** - * Clears the callback. - * - * Use this instead of deleteing this object. - * The next call to tick() will return true and that will destroy this object. - */ - void unset(); + typedef boost::function<bool(const LLUUID&)> action_callback_t; + typedef std::map<LLUUID, LLSpeakerActionTimer*> action_timers_map_t; + typedef action_timers_map_t::value_type action_value_t; + typedef action_timers_map_t::const_iterator action_timer_const_iter_t; + typedef action_timers_map_t::iterator action_timer_iter_t; + + /** + * Constructor. + * + * @param action_cb - callback which will be called each time after passed action period. + * @param action_period - time in seconds timer should tick. + * @param speaker_id - LLUUID of speaker which will be passed into action callback. + */ + LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); + virtual ~LLSpeakerActionTimer() {}; + + /** + * Implements timer "tick". + * + * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). + */ + bool tick() override; + + /** + * Clears the callback. + * + * Use this instead of deleteing this object. + * The next call to tick() will return true and that will destroy this object. + */ + void unset(); private: - action_callback_t mActionCallback; - LLUUID mSpeakerId; + action_callback_t mActionCallback; + LLUUID mSpeakerId; }; /** @@ -180,153 +180,153 @@ private: class LLSpeakersDelayActionsStorage { public: - LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay); - ~LLSpeakersDelayActionsStorage(); + LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay); + ~LLSpeakersDelayActionsStorage(); - /** - * Sets new LLSpeakerActionTimer with passed speaker UUID. - */ - void setActionTimer(const LLUUID& speaker_id); + /** + * Sets new LLSpeakerActionTimer with passed speaker UUID. + */ + void setActionTimer(const LLUUID& speaker_id); - /** - * Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and optionally deletes it. - * - * @see onTimerActionCallback() - */ - void unsetActionTimer(const LLUUID& speaker_id); + /** + * Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and optionally deletes it. + * + * @see onTimerActionCallback() + */ + void unsetActionTimer(const LLUUID& speaker_id); - void removeAllTimers(); + void removeAllTimers(); - bool isTimerStarted(const LLUUID& speaker_id); + bool isTimerStarted(const LLUUID& speaker_id); private: - /** - * Callback of the each instance of LLSpeakerActionTimer. - * - * Unsets an appropriate timer instance and calls action callback for specified speacker_id. - * - * @see unsetActionTimer() - */ - bool onTimerActionCallback(const LLUUID& speaker_id); - - LLSpeakerActionTimer::action_timers_map_t mActionTimersMap; - LLSpeakerActionTimer::action_callback_t mActionCallback; - - /** - * Delay to call action callback for speakers after timer was set. - */ - F32 mActionDelay; + /** + * Callback of the each instance of LLSpeakerActionTimer. + * + * Unsets an appropriate timer instance and calls action callback for specified speacker_id. + * + * @see unsetActionTimer() + */ + bool onTimerActionCallback(const LLUUID& speaker_id); + + LLSpeakerActionTimer::action_timers_map_t mActionTimersMap; + LLSpeakerActionTimer::action_callback_t mActionCallback; + + /** + * Delay to call action callback for speakers after timer was set. + */ + F32 mActionDelay; }; class LLSpeakerMgr : public LLOldEvents::LLObservable { - LOG_CLASS(LLSpeakerMgr); + LOG_CLASS(LLSpeakerMgr); public: - LLSpeakerMgr(LLVoiceChannel* channelp); - virtual ~LLSpeakerMgr(); - - LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id); - void update(BOOL resort_ok); - void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); - void speakerChatted(const LLUUID& speaker_id); - LLPointer<LLSpeaker> setSpeaker(const LLUUID& id, - const std::string& name = LLStringUtil::null, - LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY, - LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); - - BOOL isVoiceActive(); - - typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t; - void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); - LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } - const LLUUID getSessionID(); - bool isSpeakerToBeRemoved(const LLUUID& speaker_id); - - /** - * Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant. - * - * Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937 - */ - void initVoiceModerateMode(); + LLSpeakerMgr(LLVoiceChannel* channelp); + virtual ~LLSpeakerMgr(); + + LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id); + void update(BOOL resort_ok); + void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); + void speakerChatted(const LLUUID& speaker_id); + LLPointer<LLSpeaker> setSpeaker(const LLUUID& id, + const std::string& name = LLStringUtil::null, + LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY, + LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); + + BOOL isVoiceActive(); + + typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t; + void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); + LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } + const LLUUID getSessionID(); + bool isSpeakerToBeRemoved(const LLUUID& speaker_id); + + /** + * Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant. + * + * Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937 + */ + void initVoiceModerateMode(); protected: - virtual void updateSpeakerList(); - void setSpeakerNotInChannel(LLPointer<LLSpeaker> speackerp); - bool removeSpeaker(const LLUUID& speaker_id); + virtual void updateSpeakerList(); + void setSpeakerNotInChannel(LLPointer<LLSpeaker> speackerp); + bool removeSpeaker(const LLUUID& speaker_id); - typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t; - speaker_map_t mSpeakers; - bool mSpeakerListUpdated; + typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t; + speaker_map_t mSpeakers; + bool mSpeakerListUpdated; LLTimer mGetListTime; - speaker_list_t mSpeakersSorted; - LLFrameTimer mSpeechTimer; - LLVoiceChannel* mVoiceChannel; + speaker_list_t mSpeakersSorted; + LLFrameTimer mSpeechTimer; + LLVoiceChannel* mVoiceChannel; - /** - * time out speakers when they are not part of current session - */ - LLSpeakersDelayActionsStorage* mSpeakerDelayRemover; + /** + * time out speakers when they are not part of current session + */ + LLSpeakersDelayActionsStorage* mSpeakerDelayRemover; - // *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel - // moderation mode is implemented: See EXT-6937 - bool mVoiceModerated; + // *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel + // moderation mode is implemented: See EXT-6937 + bool mVoiceModerated; - // *TODO: To be removed when a way to request the current voice channel - // moderation mode is implemented: See EXT-6937 - bool mModerateModeHandledFirstTime; + // *TODO: To be removed when a way to request the current voice channel + // moderation mode is implemented: See EXT-6937 + bool mModerateModeHandledFirstTime; }; class LLIMSpeakerMgr : public LLSpeakerMgr { - LOG_CLASS(LLIMSpeakerMgr); + LOG_CLASS(LLIMSpeakerMgr); public: - LLIMSpeakerMgr(LLVoiceChannel* channel); - - void updateSpeakers(const LLSD& update); - void setSpeakers(const LLSD& speakers); - - void toggleAllowTextChat(const LLUUID& speaker_id); - - /** - * Mutes/Unmutes avatar for current group voice chat. - * - * It only marks avatar as muted for session and does not use local Agent's Block list. - * It does not mute Agent itself. - * - * @param[in] avatar_id UUID of avatar to be processed - * @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted. - * - * @see moderateVoiceAllParticipants() - */ - void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); - - /** - * Mutes/Unmutes all avatars for current group voice chat. - * - * It only marks avatars as muted for session and does not use local Agent's Block list. - * It calls forceVoiceModeratedMode() in case of session is already in requested state. - * - * @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted. - * - * @see moderateVoiceParticipant() - */ - void moderateVoiceAllParticipants(bool unmute_everyone); - - void processSessionUpdate(const LLSD& session_update); + LLIMSpeakerMgr(LLVoiceChannel* channel); + + void updateSpeakers(const LLSD& update); + void setSpeakers(const LLSD& speakers); + + void toggleAllowTextChat(const LLUUID& speaker_id); + + /** + * Mutes/Unmutes avatar for current group voice chat. + * + * It only marks avatar as muted for session and does not use local Agent's Block list. + * It does not mute Agent itself. + * + * @param[in] avatar_id UUID of avatar to be processed + * @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted. + * + * @see moderateVoiceAllParticipants() + */ + void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); + + /** + * Mutes/Unmutes all avatars for current group voice chat. + * + * It only marks avatars as muted for session and does not use local Agent's Block list. + * It calls forceVoiceModeratedMode() in case of session is already in requested state. + * + * @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted. + * + * @see moderateVoiceParticipant() + */ + void moderateVoiceAllParticipants(bool unmute_everyone); + + void processSessionUpdate(const LLSD& session_update); protected: - virtual void updateSpeakerList(); + virtual void updateSpeakerList(); - void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); + void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); - /** - * Process all participants to mute/unmute them according to passed voice session state. - */ - void forceVoiceModeratedMode(bool should_be_muted); + /** + * Process all participants to mute/unmute them according to passed voice session state. + */ + void forceVoiceModeratedMode(bool should_be_muted); void moderationActionCoro(std::string url, LLSD action); @@ -334,20 +334,20 @@ protected: class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr> { - LLSINGLETON(LLActiveSpeakerMgr); - LOG_CLASS(LLActiveSpeakerMgr); + LLSINGLETON(LLActiveSpeakerMgr); + LOG_CLASS(LLActiveSpeakerMgr); protected: - virtual void updateSpeakerList() override; + virtual void updateSpeakerList() override; }; class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr> { - LLSINGLETON(LLLocalSpeakerMgr); - ~LLLocalSpeakerMgr (); - LOG_CLASS(LLLocalSpeakerMgr); + LLSINGLETON(LLLocalSpeakerMgr); + ~LLLocalSpeakerMgr (); + LOG_CLASS(LLLocalSpeakerMgr); protected: - virtual void updateSpeakerList() override; + virtual void updateSpeakerList() override; }; #endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a8ba75ab5f..426b71ba67 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstartup.cpp * @brief startup routines. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,9 +31,9 @@ #include "llcallstack.h" #if LL_WINDOWS -# include <process.h> // _spawnl() +# include <process.h> // _spawnl() #else -# include <sys/stat.h> // mkdir() +# include <sys/stat.h> // mkdir() #endif #include <memory> // std::unique_ptr @@ -84,7 +84,7 @@ #include "llversioninfo.h" #include "llviewercontrol.h" #include "llviewerhelp.h" -#include "llxorcipher.h" // saved password, MAC address +#include "llxorcipher.h" // saved password, MAC address #include "llwindow.h" #include "message.h" #include "v3math.h" @@ -121,7 +121,7 @@ #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" -#include "llloginhandler.h" // gLoginHandler, SLURL support +#include "llloginhandler.h" // gLoginHandler, SLURL support #include "lllogininstance.h" // Host the login module. #include "llpanellogin.h" #include "llmutelist.h" @@ -138,7 +138,7 @@ #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" -#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance +#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance #include "llsurface.h" #include "lltexturecache.h" #include "lltexturefetch.h" @@ -237,7 +237,7 @@ extern S32 gStartImageHeight; // static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; -static std::string sInitialOutfitGender; // "male" or "female" +static std::string sInitialOutfitGender; // "male" or "female" static bool gUseCircuitCallbackCalled = false; @@ -291,12 +291,12 @@ void transition_back_to_login_panel(const std::string& emsg); void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) { - LLNameBox::refreshAll(id, full_name, is_group); - LLNameEditor::refreshAll(id, full_name, is_group); - - // TODO: Actually be intelligent about the refresh. - // For now, just brute force refresh the dialogs. - dialog_refresh_all(); + LLNameBox::refreshAll(id, full_name, is_group); + LLNameEditor::refreshAll(id, full_name, is_group); + + // TODO: Actually be intelligent about the refresh. + // For now, just brute force refresh the dialogs. + dialog_refresh_all(); } // @@ -321,10 +321,10 @@ void pump_idle_startup_network(void) // void update_texture_fetch() { - LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread - LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - gTextureList.updateImages(0.10f); + LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + gTextureList.updateImages(0.10f); if (LLImageGLThread::sEnabledTextures) { @@ -335,8 +335,8 @@ void update_texture_fetch() void set_flags_and_update_appearance() { - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); LLInventoryModelBackgroundFetch::instance().start(); } @@ -345,310 +345,310 @@ void set_flags_and_update_appearance() // true when all initialization done. bool idle_startup() { - if (gViewerWindow == NULL) - { - // We expect window to be initialized - LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; - return false; // No world yet - } - - const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); - static LLTimer timeout; - - static LLTimer login_time; - - // until this is encapsulated, this little hack for the - // auth/transform loop will do. - static F32 progress = 0.10f; - - static std::string auth_desc; - static std::string auth_message; - - static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server - - // last location by default - static S32 agent_location_id = START_LOCATION_ID_LAST; - - static bool show_connect_box = true; - - //static bool stipend_since_login = false; - - // HACK: These are things from the main loop that usually aren't done - // until initialization is complete, but need to be done here for things - // to work. - gIdleCallbacks.callFunctions(); - gViewerWindow->updateUI(); - - LLMortician::updateClass(); - - const std::string delims (" "); - std::string system; - int begIdx, endIdx; - std::string osString = LLOSInfo::instance().getOSStringSimple(); - - begIdx = osString.find_first_not_of (delims); - endIdx = osString.find_first_of (delims, begIdx); - system = osString.substr (begIdx, endIdx - begIdx); - system += "Locale"; - - LLStringUtil::setLocale (LLTrans::getString(system)); - - //note: Removing this line will cause incorrect button size in the login screen. -- bao. - gTextureList.updateImages(0.01f) ; - - if ( STATE_FIRST == LLStartUp::getStartupState() ) - { - static bool first_call = true; - if (first_call) - { - // Other phases get handled when startup state changes, - // need to capture the initial state as well. - LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); - first_call = false; - } - - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - - ///////////////////////////////////////////////// - // - // Initialize stuff that doesn't need data from simulators - // - std::string lastGPU = gSavedSettings.getString("LastGPUString"); - std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); - - if (LLFeatureManager::getInstance()->isSafe()) - { - LLNotificationsUtil::add("DisplaySetToSafe"); - } - else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && - (gSavedSettings.getS32("LastFeatureVersion") != 0)) - { - LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); - } - else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) - { - LLSD subs; - subs["LAST_GPU"] = lastGPU; - subs["THIS_GPU"] = thisGPU; - LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); - } - else if (!gViewerWindow->getInitAlert().empty()) - { - LLNotificationsUtil::add(gViewerWindow->getInitAlert()); - } - - //------------------------------------------------- - // Init the SOCKS 5 proxy if the user has configured - // one. We need to do this early in case the user - // is using SOCKS for HTTP so we get the login - // screen and HTTP tables via SOCKS. - //------------------------------------------------- - LLStartUp::startLLProxy(); - - gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); - gSavedSettings.setString("LastGPUString", thisGPU); - - - std::string xml_file = LLUI::locateSkin("xui_version.xml"); - LLXMLNodePtr root; - bool xml_ok = false; - if (LLXMLNode::parseFile(xml_file, root, NULL)) - { - if( (root->hasName("xui_version") ) ) - { - std::string value = root->getValue(); - F32 version = 0.0f; - LLStringUtil::convertToF32(value, version); - if (version >= 1.0f) - { - xml_ok = true; - } - } - } - if (!xml_ok) - { - // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. - // If that's so, then we'll get a fatal error on attempting to load it, - // which will display a nontranslatable error message that says so. - // Otherwise, we'll display a reasonable error message that IS translatable. - LLAppViewer::instance()->earlyExit("BadInstallation"); - } - // - // Statistics stuff - // - - // Load autopilot and stats stuff - gAgentPilot.load(); - - //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); - - // Load the throttle settings - gViewerThrottle.load(); - - // - // Initialize messaging system - // - LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; - - std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); - - LLFILE* found_template = NULL; - found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ - - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message_template.msg - // file will be located in: - // build-vc**/newview/<config>/app_settings - if (!found_template) - { - message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } - #elif LL_DARWIN - // On Mac dev builds, message_template.msg lives in: - // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings - if (!found_template) - { - message_template_path = - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, - "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } - #endif - - if (found_template) - { - fclose(found_template); - - U32 port = gSavedSettings.getU32("UserConnectionPort"); - - if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) - (gSavedSettings.getBOOL("ConnectionPortEnabled"))) - { - port = gSavedSettings.getU32("ConnectionPort"); - } - - // TODO parameterize - const F32 circuit_heartbeat_interval = 5; - const F32 circuit_timeout = 100; - - const LLUseCircuitCodeResponder* responder = NULL; - bool failure_is_fatal = true; - - if(!start_messaging_system( - message_template_path, - port, - LLVersionInfo::instance().getMajor(), - LLVersionInfo::instance().getMinor(), - LLVersionInfo::instance().getPatch(), - FALSE, - std::string(), - responder, - failure_is_fatal, - circuit_heartbeat_interval, - circuit_timeout)) - { - std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); - LL_WARNS("AppInit") << diagnostic << LL_ENDL; - LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); - } - - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message.xml file will - // be located in indra/build-vc**/newview/<config>/app_settings. - std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); - - if (!LLFile::isfile(message_path.c_str())) - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); - } - else - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - } - #else - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - #endif - - } - else - { - LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); - } - - if(gMessageSystem && gMessageSystem->isOK()) - { - // Initialize all of the callbacks in case of bad message - // system data - LLMessageSystem* msg = gMessageSystem; - msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, - invalid_message_callback, - NULL); - msg->setExceptionFunc(MX_PACKET_TOO_SHORT, - invalid_message_callback, - NULL); - - // running off end of a packet is now valid in the case - // when a reader has a newer message template than - // the sender - /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, - invalid_message_callback, - NULL);*/ - msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, - invalid_message_callback, - NULL); - - if (gSavedSettings.getBOOL("LogMessages")) - { - LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; - msg->startLogging(); - } - - // start the xfer system. by default, choke the downloads - // a lot... - const S32 VIEWER_MAX_XFER = 3; - start_xfer_manager(); - gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); - F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); - if (xfer_throttle_bps > 1.f) - { - gXferManager->setUseAckThrottling(TRUE); - gXferManager->setAckThrottleBPS(xfer_throttle_bps); - } - gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); - - - F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); - msg->mPacketRing.setDropPercentage(dropPercent); - - F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); - F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); - if (inBandwidth != 0.f) - { - LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; - msg->mPacketRing.setUseInThrottle(TRUE); - msg->mPacketRing.setInBandwidth(inBandwidth); - } - if (outBandwidth != 0.f) - { - LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; - msg->mPacketRing.setUseOutThrottle(TRUE); - msg->mPacketRing.setOutBandwidth(outBandwidth); - } - } - - LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; - - //------------------------------------------------- - // Init audio, which may be needed for prefs dialog - // or audio cues in connection UI. - //------------------------------------------------- - - if (FALSE == gSavedSettings.getBOOL("NoAudio")) - { - delete gAudiop; - gAudiop = NULL; + if (gViewerWindow == NULL) + { + // We expect window to be initialized + LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; + return false; // No world yet + } + + const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); + static LLTimer timeout; + + static LLTimer login_time; + + // until this is encapsulated, this little hack for the + // auth/transform loop will do. + static F32 progress = 0.10f; + + static std::string auth_desc; + static std::string auth_message; + + static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server + + // last location by default + static S32 agent_location_id = START_LOCATION_ID_LAST; + + static bool show_connect_box = true; + + //static bool stipend_since_login = false; + + // HACK: These are things from the main loop that usually aren't done + // until initialization is complete, but need to be done here for things + // to work. + gIdleCallbacks.callFunctions(); + gViewerWindow->updateUI(); + + LLMortician::updateClass(); + + const std::string delims (" "); + std::string system; + int begIdx, endIdx; + std::string osString = LLOSInfo::instance().getOSStringSimple(); + + begIdx = osString.find_first_not_of (delims); + endIdx = osString.find_first_of (delims, begIdx); + system = osString.substr (begIdx, endIdx - begIdx); + system += "Locale"; + + LLStringUtil::setLocale (LLTrans::getString(system)); + + //note: Removing this line will cause incorrect button size in the login screen. -- bao. + gTextureList.updateImages(0.01f) ; + + if ( STATE_FIRST == LLStartUp::getStartupState() ) + { + static bool first_call = true; + if (first_call) + { + // Other phases get handled when startup state changes, + // need to capture the initial state as well. + LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); + first_call = false; + } + + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + ///////////////////////////////////////////////// + // + // Initialize stuff that doesn't need data from simulators + // + std::string lastGPU = gSavedSettings.getString("LastGPUString"); + std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); + + if (LLFeatureManager::getInstance()->isSafe()) + { + LLNotificationsUtil::add("DisplaySetToSafe"); + } + else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && + (gSavedSettings.getS32("LastFeatureVersion") != 0)) + { + LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); + } + else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) + { + LLSD subs; + subs["LAST_GPU"] = lastGPU; + subs["THIS_GPU"] = thisGPU; + LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); + } + else if (!gViewerWindow->getInitAlert().empty()) + { + LLNotificationsUtil::add(gViewerWindow->getInitAlert()); + } + + //------------------------------------------------- + // Init the SOCKS 5 proxy if the user has configured + // one. We need to do this early in case the user + // is using SOCKS for HTTP so we get the login + // screen and HTTP tables via SOCKS. + //------------------------------------------------- + LLStartUp::startLLProxy(); + + gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); + gSavedSettings.setString("LastGPUString", thisGPU); + + + std::string xml_file = LLUI::locateSkin("xui_version.xml"); + LLXMLNodePtr root; + bool xml_ok = false; + if (LLXMLNode::parseFile(xml_file, root, NULL)) + { + if( (root->hasName("xui_version") ) ) + { + std::string value = root->getValue(); + F32 version = 0.0f; + LLStringUtil::convertToF32(value, version); + if (version >= 1.0f) + { + xml_ok = true; + } + } + } + if (!xml_ok) + { + // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. + // If that's so, then we'll get a fatal error on attempting to load it, + // which will display a nontranslatable error message that says so. + // Otherwise, we'll display a reasonable error message that IS translatable. + LLAppViewer::instance()->earlyExit("BadInstallation"); + } + // + // Statistics stuff + // + + // Load autopilot and stats stuff + gAgentPilot.load(); + + //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); + + // Load the throttle settings + gViewerThrottle.load(); + + // + // Initialize messaging system + // + LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; + + std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); + + LLFILE* found_template = NULL; + found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message_template.msg + // file will be located in: + // build-vc**/newview/<config>/app_settings + if (!found_template) + { + message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #elif LL_DARWIN + // On Mac dev builds, message_template.msg lives in: + // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings + if (!found_template) + { + message_template_path = + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, + "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #endif + + if (found_template) + { + fclose(found_template); + + U32 port = gSavedSettings.getU32("UserConnectionPort"); + + if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) + (gSavedSettings.getBOOL("ConnectionPortEnabled"))) + { + port = gSavedSettings.getU32("ConnectionPort"); + } + + // TODO parameterize + const F32 circuit_heartbeat_interval = 5; + const F32 circuit_timeout = 100; + + const LLUseCircuitCodeResponder* responder = NULL; + bool failure_is_fatal = true; + + if(!start_messaging_system( + message_template_path, + port, + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + FALSE, + std::string(), + responder, + failure_is_fatal, + circuit_heartbeat_interval, + circuit_timeout)) + { + std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); + } + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message.xml file will + // be located in indra/build-vc**/newview/<config>/app_settings. + std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); + + if (!LLFile::isfile(message_path.c_str())) + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); + } + else + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + } + #else + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + #endif + + } + else + { + LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); + } + + if(gMessageSystem && gMessageSystem->isOK()) + { + // Initialize all of the callbacks in case of bad message + // system data + LLMessageSystem* msg = gMessageSystem; + msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, + invalid_message_callback, + NULL); + msg->setExceptionFunc(MX_PACKET_TOO_SHORT, + invalid_message_callback, + NULL); + + // running off end of a packet is now valid in the case + // when a reader has a newer message template than + // the sender + /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, + invalid_message_callback, + NULL);*/ + msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, + invalid_message_callback, + NULL); + + if (gSavedSettings.getBOOL("LogMessages")) + { + LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; + msg->startLogging(); + } + + // start the xfer system. by default, choke the downloads + // a lot... + const S32 VIEWER_MAX_XFER = 3; + start_xfer_manager(); + gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); + F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); + if (xfer_throttle_bps > 1.f) + { + gXferManager->setUseAckThrottling(TRUE); + gXferManager->setAckThrottleBPS(xfer_throttle_bps); + } + gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); + + + F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); + msg->mPacketRing.setDropPercentage(dropPercent); + + F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); + F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); + if (inBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; + msg->mPacketRing.setUseInThrottle(TRUE); + msg->mPacketRing.setInBandwidth(inBandwidth); + } + if (outBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; + msg->mPacketRing.setUseOutThrottle(TRUE); + msg->mPacketRing.setOutBandwidth(outBandwidth); + } + } + + LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; + + //------------------------------------------------- + // Init audio, which may be needed for prefs dialog + // or audio cues in connection UI. + //------------------------------------------------- + + if (FALSE == gSavedSettings.getBOOL("NoAudio")) + { + delete gAudiop; + gAudiop = NULL; #ifdef LL_FMODSTUDIO #if !LL_WINDOWS @@ -661,262 +661,262 @@ bool idle_startup() #ifdef LL_OPENAL #if !LL_WINDOWS - if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) + if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) #endif // !LL_WINDOWS - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); - } + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); + } #endif - - if (gAudiop) - { + + if (gAudiop) + { #if LL_WINDOWS - // FMOD Ex on Windows needs the window handle to stop playing audio - // when window is minimized. JC - void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); + // FMOD Ex on Windows needs the window handle to stop playing audio + // when window is minimized. JC + void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); #else - void* window_handle = NULL; + void* window_handle = NULL; #endif - if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) - { - if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) - { - LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); - } - - // if the audio engine hasn't set up its own preferred handler for streaming audio - // then set up the generic streaming audio implementation which uses media plugins - if (NULL == gAudiop->getStreamingAudioImpl()) - { - LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); - } - - gAudiop->setMuted(TRUE); - } - else - { - LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; - delete gAudiop; - gAudiop = NULL; - } - } - } - - LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; - - if (LLTimer::knownBadTimer()) - { - LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; - } - - // - // Log on to system - // - if (gUserCredential.isNull()) - { - gUserCredential = gLoginHandler.initializeLoginInfo(); - } - // Previous initializeLoginInfo may have generated user credentials. Re-check them. - if (gUserCredential.isNull()) - { - show_connect_box = TRUE; - } - else if (gSavedSettings.getBOOL("AutoLogin")) - { - // Log into last account - gRememberPassword = true; - gRememberUser = true; - gSavedSettings.setBOOL("RememberPassword", TRUE); - gSavedSettings.setBOOL("RememberUser", TRUE); - show_connect_box = false; - } - else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) - { - // Console provided login&password - gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); - gRememberUser = gSavedSettings.getBOOL("RememberUser"); - show_connect_box = false; - } - else - { - gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); - gRememberUser = gSavedSettings.getBOOL("RememberUser"); - show_connect_box = TRUE; - } - - //setup map of datetime strings to codes and slt & local time offset from utc - // *TODO: Does this need to be here? - LLStringOps::setupDatetimeInfo(false); - - // Go to the next startup state - LLStartUp::setStartupState( STATE_BROWSER_INIT ); - return FALSE; - } - - - if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingBrowser"); - set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); - // LLViewerMedia::initBrowser(); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - return FALSE; - } - - - if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " - << show_connect_box << LL_ENDL; - - // if we've gone backwards in the login state machine, to this state where we show the UI - // AND the debug setting to exit in this case is true, then go ahead and bail quickly - if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) - { - LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; - // no requirement for notification here - just exit - LLAppViewer::instance()->earlyExitNoNotify(); - } - - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - - // Login screen needs menus for preferences, but we can enter - // this startup phase more than once. - if (gLoginMenuBarView == NULL) - { - LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; - initialize_spellcheck_menu(); - init_menus(); - } - show_release_notes_if_required(); - - if (show_connect_box) - { - LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; - // Load all the name information out of the login view - // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't - // show the login view until login_show() is called below. - if (gUserCredential.isNull()) - { - LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; - gUserCredential = gLoginHandler.initializeLoginInfo(); - } - // Make sure the process dialog doesn't hide things - gViewerWindow->setShowProgress(FALSE); - // Show the login dialog - login_show(); - // connect dialog is already shown, so fill in the names - LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); - LLPanelLogin::giveFocus(); - - // MAINT-3231 Show first run dialog only for Desura viewer - if (gSavedSettings.getString("sourceid") == "1208_desura") - { - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) - { - LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; - show_first_run_dialog(); - } - else - { - LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; - } - } - display_startup(); - LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input - } - else - { - LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; - // skip directly to message template verification - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - } - - gViewerWindow->setNormalControlsVisible( FALSE ); - gLoginMenuBarView->setVisible( TRUE ); - gLoginMenuBarView->setEnabled( TRUE ); - show_debug_menus(); - - // Hide the splash screen - LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; - LLSplashScreen::hide(); - // Push our window frontmost - gViewerWindow->getWindow()->show(); - - // DEV-16927. The following code removes errant keystrokes that happen while the window is being - // first made visible. + if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) + { + if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) + { + LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); + } + + // if the audio engine hasn't set up its own preferred handler for streaming audio + // then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + + gAudiop->setMuted(TRUE); + } + else + { + LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; + delete gAudiop; + gAudiop = NULL; + } + } + } + + LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; + + if (LLTimer::knownBadTimer()) + { + LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; + } + + // + // Log on to system + // + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + // Previous initializeLoginInfo may have generated user credentials. Re-check them. + if (gUserCredential.isNull()) + { + show_connect_box = TRUE; + } + else if (gSavedSettings.getBOOL("AutoLogin")) + { + // Log into last account + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); + show_connect_box = false; + } + else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) + { + // Console provided login&password + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); + show_connect_box = false; + } + else + { + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); + show_connect_box = TRUE; + } + + //setup map of datetime strings to codes and slt & local time offset from utc + // *TODO: Does this need to be here? + LLStringOps::setupDatetimeInfo(false); + + // Go to the next startup state + LLStartUp::setStartupState( STATE_BROWSER_INIT ); + return FALSE; + } + + + if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingBrowser"); + set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + // LLViewerMedia::initBrowser(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + return FALSE; + } + + + if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " + << show_connect_box << LL_ENDL; + + // if we've gone backwards in the login state machine, to this state where we show the UI + // AND the debug setting to exit in this case is true, then go ahead and bail quickly + if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) + { + LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; + // no requirement for notification here - just exit + LLAppViewer::instance()->earlyExitNoNotify(); + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + + // Login screen needs menus for preferences, but we can enter + // this startup phase more than once. + if (gLoginMenuBarView == NULL) + { + LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; + initialize_spellcheck_menu(); + init_menus(); + } + show_release_notes_if_required(); + + if (show_connect_box) + { + LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; + // Load all the name information out of the login view + // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't + // show the login view until login_show() is called below. + if (gUserCredential.isNull()) + { + LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + // Make sure the process dialog doesn't hide things + gViewerWindow->setShowProgress(FALSE); + // Show the login dialog + login_show(); + // connect dialog is already shown, so fill in the names + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); + LLPanelLogin::giveFocus(); + + // MAINT-3231 Show first run dialog only for Desura viewer + if (gSavedSettings.getString("sourceid") == "1208_desura") + { + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; + show_first_run_dialog(); + } + else + { + LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; + } + } + display_startup(); + LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input + } + else + { + LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; + // skip directly to message template verification + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + } + + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + show_debug_menus(); + + // Hide the splash screen + LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; + LLSplashScreen::hide(); + // Push our window frontmost + gViewerWindow->getWindow()->show(); + + // DEV-16927. The following code removes errant keystrokes that happen while the window is being + // first made visible. #ifdef _WIN32 LL_DEBUGS("AppInit") << "Processing PeekMessage" << LL_ENDL; - MSG msg; - while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) + MSG msg; + while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) { } LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL; #endif display_startup(); timeout.reset(); - return FALSE; - } - - if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) - { - // when we get to this state, we've already been past the login UI - // (possiblely automatically) - flag this so we can test in the - // STATE_LOGIN_SHOW state if we've gone backwards - mLoginStatePastUI = true; - - // Don't do anything. Wait for the login view to call the login_callback, - // which will push us to the next state. - - // display() function will be the one to run display_startup() - // Sleep so we don't spin the CPU - ms_sleep(1); - return FALSE; - } - - if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) - { - // Post login screen, we should see if any settings have changed that may - // require us to either start/stop or change the socks proxy. As various communications - // past this point may require the proxy to be up. - if (!LLStartUp::startLLProxy()) - { - // Proxy start up failed, we should now bail the state machine - // startLLProxy() will have reported an error to the user - // already, so we just go back to the login screen. The user - // could then change the preferences to fix the issue. - - LLStartUp::setStartupState(STATE_LOGIN_SHOW); - return FALSE; - } - - // reset the values that could have come in from a slurl - // DEV-42215: Make sure they're not empty -- gUserCredential - // might already have been set from gSavedSettings, and it's too bad - // to overwrite valid values with empty strings. - - if (show_connect_box) - { - // TODO if not use viewer auth - // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); - // end TODO - - // HACK: Try to make not jump on login - gKeyboard->resetKeys(); - } - - // when we get to this state, we've already been past the login UI - // (possiblely automatically) - flag this so we can test in the - // STATE_LOGIN_SHOW state if we've gone backwards - mLoginStatePastUI = true; - - // save the credentials - std::string userid = "unknown"; + return FALSE; + } + + if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) + { + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // Don't do anything. Wait for the login view to call the login_callback, + // which will push us to the next state. + + // display() function will be the one to run display_startup() + // Sleep so we don't spin the CPU + ms_sleep(1); + return FALSE; + } + + if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) + { + // Post login screen, we should see if any settings have changed that may + // require us to either start/stop or change the socks proxy. As various communications + // past this point may require the proxy to be up. + if (!LLStartUp::startLLProxy()) + { + // Proxy start up failed, we should now bail the state machine + // startLLProxy() will have reported an error to the user + // already, so we just go back to the login screen. The user + // could then change the preferences to fix the issue. + + LLStartUp::setStartupState(STATE_LOGIN_SHOW); + return FALSE; + } + + // reset the values that could have come in from a slurl + // DEV-42215: Make sure they're not empty -- gUserCredential + // might already have been set from gSavedSettings, and it's too bad + // to overwrite valid values with empty strings. + + if (show_connect_box) + { + // TODO if not use viewer auth + // Load all the name information out of the login view + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); + // end TODO + + // HACK: Try to make not jump on login + gKeyboard->resetKeys(); + } + + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // save the credentials + std::string userid = "unknown"; if (gUserCredential.notNull()) { userid = gUserCredential->userID(); @@ -928,24 +928,24 @@ bool idle_startup() gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); } } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); - gSavedSettings.setBOOL("RememberUser", gRememberUser); - LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; - gDebugInfo["LoginName"] = userid; - - // create necessary directories - // *FIX: these mkdir's should error check - gDirUtilp->setLindenUserDir(userid); - LLFile::mkdir(gDirUtilp->getLindenUserDir()); - - // As soon as directories are ready initialize notification storages - if (!LLPersistentNotificationStorage::instanceExists()) - { - // check existance since this part of code can be reached - // twice due to login failures - LLPersistentNotificationStorage::initParamSingleton(); - LLDoNotDisturbNotificationStorage::initParamSingleton(); - } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); + LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; + gDebugInfo["LoginName"] = userid; + + // create necessary directories + // *FIX: these mkdir's should error check + gDirUtilp->setLindenUserDir(userid); + LLFile::mkdir(gDirUtilp->getLindenUserDir()); + + // As soon as directories are ready initialize notification storages + if (!LLPersistentNotificationStorage::instanceExists()) + { + // check existance since this part of code can be reached + // twice due to login failures + LLPersistentNotificationStorage::initParamSingleton(); + LLDoNotDisturbNotificationStorage::initParamSingleton(); + } else { // reinitialize paths in case user switched grids or accounts @@ -953,152 +953,152 @@ bool idle_startup() LLDoNotDisturbNotificationStorage::getInstance()->reset(); } - // Set PerAccountSettingsFile to the default value. - std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); - gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); - gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; - - // Note: can't store warnings files per account because some come up before login - - // Overwrite default user settings with user settings - LLAppViewer::instance()->loadSettingsFromDirectory("Account"); - - // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). - LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); - if (logInstantMessagesControl.notNull()) - { - gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); - } - - // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation - // and startup time is close enough if we don't have a real value. - if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) - { - gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); - } - - //Default the path if one isn't set. - // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was - // provided in pre 2.0 viewer. See EXT-6661 - if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) - { - gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); - gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); - } - else - { - gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - } - gDirUtilp->setPerAccountChatLogsDir(userid); - - LLFile::mkdir(gDirUtilp->getChatLogsDir()); - LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); - - if (show_connect_box) - { - LLSLURL slurl; - //LLPanelLogin::closePanel(); - } - - - // Load URL History File - LLURLHistory::loadFile("url_history.xml"); - // Load location history - LLLocationHistory::getInstance()->load(); - - // Load Avatars icons cache - LLAvatarIconIDCache::getInstance()->load(); - - LLRenderMuteList::getInstance()->loadFromFile(); - - //------------------------------------------------- - // Handle startup progress screen - //------------------------------------------------- - - // on startup the user can request to go to their home, - // their last location, or some URL "-url //sim/x/y[/z]" - // All accounts have both a home and a last location, and we don't support - // more locations than that. Choose the appropriate one. JC - switch (LLStartUp::getStartSLURL().getType()) - { - case LLSLURL::LOCATION: - agent_location_id = START_LOCATION_ID_URL; - break; - case LLSLURL::LAST_LOCATION: - agent_location_id = START_LOCATION_ID_LAST; - break; - default: - agent_location_id = START_LOCATION_ID_HOME; - break; - } - - gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - - // Display the startup progress bar. - gViewerWindow->initTextures(agent_location_id); - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); - - gViewerWindow->revealIntroPanel(); - - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); - - return FALSE; - } - - if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) - { - gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); - - // Update progress status and the display loop. - auth_desc = LLTrans::getString("LoginInProgress"); - set_startup_status(progress, auth_desc, auth_message); - progress += 0.02f; - display_startup(); - - // Setting initial values... - LLLoginInstance* login = LLLoginInstance::getInstance(); - login->setNotificationsInterface(LLNotifications::getInstance()); - - login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); - login->setLastExecEvent(gLastExecEvent); - login->setLastExecDuration(gLastExecDuration); - - // This call to LLLoginInstance::connect() starts the - // authentication process. - login->connect(gUserCredential); - - LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); - return FALSE; - } - - if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) - { - // If we get here we have gotten past the potential stall - // in curl, so take "may appear frozen" out of progress bar. JC - auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); - set_startup_status(progress, auth_desc, auth_message); - - LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); - return FALSE; - } - - if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) - { - // Generic failure message - std::ostringstream emsg; - emsg << LLTrans::getString("LoginFailedHeader") << "\n"; - if(LLLoginInstance::getInstance()->authFailure()) - { - LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " - << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; - LLSD response = LLLoginInstance::getInstance()->getResponse(); - // Still have error conditions that may need some - // sort of handling - dig up specific message - std::string reason_response = response["reason"]; - std::string message_response = response["message"]; - std::string message_id = response["message_id"]; - std::string message; // actual string to show the user + // Set PerAccountSettingsFile to the default value. + std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); + gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); + gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; + + // Note: can't store warnings files per account because some come up before login + + // Overwrite default user settings with user settings + LLAppViewer::instance()->loadSettingsFromDirectory("Account"); + + // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). + LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); + if (logInstantMessagesControl.notNull()) + { + gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); + } + + // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation + // and startup time is close enough if we don't have a real value. + if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) + { + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + } + + //Default the path if one isn't set. + // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was + // provided in pre 2.0 viewer. See EXT-6661 + if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) + { + gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); + gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); + } + else + { + gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + } + gDirUtilp->setPerAccountChatLogsDir(userid); + + LLFile::mkdir(gDirUtilp->getChatLogsDir()); + LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); + + if (show_connect_box) + { + LLSLURL slurl; + //LLPanelLogin::closePanel(); + } + + + // Load URL History File + LLURLHistory::loadFile("url_history.xml"); + // Load location history + LLLocationHistory::getInstance()->load(); + + // Load Avatars icons cache + LLAvatarIconIDCache::getInstance()->load(); + + LLRenderMuteList::getInstance()->loadFromFile(); + + //------------------------------------------------- + // Handle startup progress screen + //------------------------------------------------- + + // on startup the user can request to go to their home, + // their last location, or some URL "-url //sim/x/y[/z]" + // All accounts have both a home and a last location, and we don't support + // more locations than that. Choose the appropriate one. JC + switch (LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + agent_location_id = START_LOCATION_ID_URL; + break; + case LLSLURL::LAST_LOCATION: + agent_location_id = START_LOCATION_ID_LAST; + break; + default: + agent_location_id = START_LOCATION_ID_HOME; + break; + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + // Display the startup progress bar. + gViewerWindow->initTextures(agent_location_id); + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); + + gViewerWindow->revealIntroPanel(); + + LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); + + return FALSE; + } + + if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) + { + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); + + // Update progress status and the display loop. + auth_desc = LLTrans::getString("LoginInProgress"); + set_startup_status(progress, auth_desc, auth_message); + progress += 0.02f; + display_startup(); + + // Setting initial values... + LLLoginInstance* login = LLLoginInstance::getInstance(); + login->setNotificationsInterface(LLNotifications::getInstance()); + + login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); + login->setLastExecEvent(gLastExecEvent); + login->setLastExecDuration(gLastExecDuration); + + // This call to LLLoginInstance::connect() starts the + // authentication process. + login->connect(gUserCredential); + + LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); + return FALSE; + } + + if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) + { + // If we get here we have gotten past the potential stall + // in curl, so take "may appear frozen" out of progress bar. JC + auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); + set_startup_status(progress, auth_desc, auth_message); + + LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); + return FALSE; + } + + if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) + { + // Generic failure message + std::ostringstream emsg; + emsg << LLTrans::getString("LoginFailedHeader") << "\n"; + if(LLLoginInstance::getInstance()->authFailure()) + { + LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " + << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; + LLSD response = LLLoginInstance::getInstance()->getResponse(); + // Still have error conditions that may need some + // sort of handling - dig up specific message + std::string reason_response = response["reason"]; + std::string message_response = response["message"]; + std::string message_id = response["message_id"]; + std::string message; // actual string to show the user bool localized_by_id = false; if(!message_id.empty()) @@ -1131,63 +1131,63 @@ bool idle_startup() } if(!localized_by_id && !message_response.empty()) - { - // *HACK: "no_inventory_host" sent as the message itself. - // Remove this clause when server is sending message_id as well. - message = LLAgent::sTeleportErrorMessages[ message_response ]; - } - - if (message.empty()) - { - // Fallback to server-supplied string; necessary since server - // may add strings that this viewer is not yet aware of - message = message_response; - } - - emsg << message; - - - if(reason_response == "key") - { - // Couldn't login because user/password is wrong - // Clear the credential - gUserCredential->clearAuthenticator(); - } - - if(reason_response == "update" - || reason_response == "optional") - { - // In the case of a needed update, quit. - // Its either downloading or declined. - // If optional was skipped this case shouldn't - // be reached. - - LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; - LLLoginInstance::getInstance()->disconnect(); - LLAppViewer::instance()->forceQuit(); - } - else - { - if (reason_response != "tos" && reason_response != "mfa_challenge") - { - // Don't pop up a notification in the TOS or MFA cases because - // the specialized floater has already scolded the user. - std::string error_code; - if(response.has("errorcode")) - { - error_code = response["errorcode"].asString(); - } - if ((reason_response == "CURLError") && - (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && - response.has("certificate")) - { - // This was a certificate error, so grab the certificate - // and throw up the appropriate dialog. - LLPointer<LLCertificate> certificate; - try - { - certificate = gSecAPIHandler->getCertificate(response["certificate"]); - } + { + // *HACK: "no_inventory_host" sent as the message itself. + // Remove this clause when server is sending message_id as well. + message = LLAgent::sTeleportErrorMessages[ message_response ]; + } + + if (message.empty()) + { + // Fallback to server-supplied string; necessary since server + // may add strings that this viewer is not yet aware of + message = message_response; + } + + emsg << message; + + + if(reason_response == "key") + { + // Couldn't login because user/password is wrong + // Clear the credential + gUserCredential->clearAuthenticator(); + } + + if(reason_response == "update" + || reason_response == "optional") + { + // In the case of a needed update, quit. + // Its either downloading or declined. + // If optional was skipped this case shouldn't + // be reached. + + LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; + LLLoginInstance::getInstance()->disconnect(); + LLAppViewer::instance()->forceQuit(); + } + else + { + if (reason_response != "tos" && reason_response != "mfa_challenge") + { + // Don't pop up a notification in the TOS or MFA cases because + // the specialized floater has already scolded the user. + std::string error_code; + if(response.has("errorcode")) + { + error_code = response["errorcode"].asString(); + } + if ((reason_response == "CURLError") && + (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && + response.has("certificate")) + { + // This was a certificate error, so grab the certificate + // and throw up the appropriate dialog. + LLPointer<LLCertificate> certificate; + try + { + certificate = gSecAPIHandler->getCertificate(response["certificate"]); + } catch (LLCertException &cert_exception) { LL_WARNS("LLStartup", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL; @@ -1201,1231 +1201,1231 @@ bool idle_startup() gSavedSettings.setBOOL("AutoLogin", FALSE); show_connect_box = true; } - if(certificate) - { - LLSD args = transform_cert_args(certificate); - - if(error_code == "SSL_CACERT") - { - // if we are handling an untrusted CA, throw up the dialog - // with the 'trust this CA' button. - LLNotificationsUtil::add("TrustCertificateError", args, response, - trust_cert_done); - - show_connect_box = true; - } - else - { - // the certificate exception returns a unique string for each type of exception. - // we grab this string via the LLUserAuth object, and use that to grab the localized - // string. - args["REASON"] = LLTrans::getString(message_response); - - LLNotificationsUtil::add("GeneralCertificateError", args, response, - general_cert_done); - - reset_login(); - gSavedSettings.setBOOL("AutoLogin", FALSE); - show_connect_box = true; - - } - - } - } + if(certificate) + { + LLSD args = transform_cert_args(certificate); + + if(error_code == "SSL_CACERT") + { + // if we are handling an untrusted CA, throw up the dialog + // with the 'trust this CA' button. + LLNotificationsUtil::add("TrustCertificateError", args, response, + trust_cert_done); + + show_connect_box = true; + } + else + { + // the certificate exception returns a unique string for each type of exception. + // we grab this string via the LLUserAuth object, and use that to grab the localized + // string. + args["REASON"] = LLTrans::getString(message_response); + + LLNotificationsUtil::add("GeneralCertificateError", args, response, + general_cert_done); + + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + show_connect_box = true; + + } + + } + } else if (reason_response == "BadType") { LLNotificationsUtil::add("LoginFailedToParse", LLSD(), LLSD(), login_alert_done); } - else if (!message.empty()) - { - // This wasn't a certificate error, so throw up the normal - // notificatioin message. - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); - } - } - transition_back_to_login_panel(emsg.str()); - show_connect_box = true; - } - } - else if(LLLoginInstance::getInstance()->authSuccess()) - { - if(process_login_success_response()) - { - // Pass the user information to the voice chat server interface. - LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); - // create the default proximal channel - LLVoiceChannel::initClass(); - LLStartUp::setStartupState( STATE_WORLD_INIT); - LLTrace::get_frame_recording().reset(); - } - else - { - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); - transition_back_to_login_panel(emsg.str()); - show_connect_box = true; - return FALSE; - } - } - return FALSE; - } - - //--------------------------------------------------------------------- - // World Init - //--------------------------------------------------------------------- - if (STATE_WORLD_INIT == LLStartUp::getStartupState()) - { - set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); - display_startup(); - // We should have an agent id by this point. - llassert(!(gAgentID == LLUUID::null)); - - // Finish agent initialization. (Requires gSavedSettings, builds camera) - gAgent.init(); - display_startup(); - gAgentCamera.init(); - display_startup(); - display_startup(); - - // Since we connected, save off the settings so the user doesn't have to - // type the name/password again if we crash. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - LLUIColorTable::instance().saveUserSettings(); - - display_startup(); - - // - // Initialize classes w/graphics stuff. - // - LLViewerStatsRecorder::instance(); // Since textures work in threads - LLSurface::initClasses(); - display_startup(); - - display_startup(); - - LLDrawable::initClass(); - display_startup(); - - // init the shader managers - LLPostProcess::initClass(); - display_startup(); + else if (!message.empty()) + { + // This wasn't a certificate error, so throw up the normal + // notificatioin message. + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + } + } + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + } + } + else if(LLLoginInstance::getInstance()->authSuccess()) + { + if(process_login_success_response()) + { + // Pass the user information to the voice chat server interface. + LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); + // create the default proximal channel + LLVoiceChannel::initClass(); + LLStartUp::setStartupState( STATE_WORLD_INIT); + LLTrace::get_frame_recording().reset(); + } + else + { + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + return FALSE; + } + } + return FALSE; + } + + //--------------------------------------------------------------------- + // World Init + //--------------------------------------------------------------------- + if (STATE_WORLD_INIT == LLStartUp::getStartupState()) + { + set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + display_startup(); + // We should have an agent id by this point. + llassert(!(gAgentID == LLUUID::null)); + + // Finish agent initialization. (Requires gSavedSettings, builds camera) + gAgent.init(); + display_startup(); + gAgentCamera.init(); + display_startup(); + display_startup(); + + // Since we connected, save off the settings so the user doesn't have to + // type the name/password again if we crash. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + LLUIColorTable::instance().saveUserSettings(); + + display_startup(); + + // + // Initialize classes w/graphics stuff. + // + LLViewerStatsRecorder::instance(); // Since textures work in threads + LLSurface::initClasses(); + display_startup(); + + display_startup(); + + LLDrawable::initClass(); + display_startup(); + + // init the shader managers + LLPostProcess::initClass(); + display_startup(); + + LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); + display_startup(); + + LLViewerObject::initVOClasses(); + display_startup(); + + // Initialize all our tools. Must be done after saved settings loaded. + // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. + LLToolMgr::getInstance()->initTools(); + display_startup(); + + // Pre-load floaters, like the world map, that are slow to spawn + // due to XML complexity. + gViewerWindow->initWorldUI(); + + display_startup(); + + // This is where we used to initialize gWorldp. Original comment said: + // World initialization must be done after above window init + + // User might have overridden far clip + LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); + display_startup(); + // Before we create the first region, we need to set the agent's mOriginGlobal + // This is necessary because creating objects before this is set will result in a + // bad mPositionAgent cache. + + gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); + display_startup(); + + LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); + display_startup(); + + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " + << gFirstSimSeedCap << LL_ENDL; + regionp->setSeedCapability(gFirstSimSeedCap); + LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; + display_startup(); + // Set agent's initial region to be the one we just created. + gAgent.setRegion(regionp); + display_startup(); + // Set agent's initial position, which will be read by LLVOAvatar when the avatar + // object is created. I think this must be done after setting the region. JC + gAgent.setPositionAgent(agent_start_position_region); + + display_startup(); + LLStartUp::initExperiences(); + + display_startup(); + + // If logging should be enebled, turns it on and loads history from disk + // Note: does not happen on init of singleton because preferences can use + // this instance without logging in + LLConversationLog::getInstance()->initLoggingState(); + + LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); + + return FALSE; + } + + + //--------------------------------------------------------------------- + // Load QuickTime/GStreamer and other multimedia engines, can be slow. + // Do it while we're waiting on the network for our seed capability. JC + //--------------------------------------------------------------------- + if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) + { + LLStartUp::multimediaInit(); + LLStartUp::setStartupState( STATE_FONT_INIT ); + display_startup(); + return FALSE; + } + + // Loading fonts takes several seconds + if (STATE_FONT_INIT == LLStartUp::getStartupState()) + { + LLStartUp::fontInit(); + LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); + display_startup(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Wait for Seed Cap Grant + //--------------------------------------------------------------------- + if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + if (regionp->capabilitiesReceived()) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + else if (regionp->capabilitiesError()) + { + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else + { + U32 num_retries = regionp->getNumSeedCapRetries(); + if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) + { + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else if (num_retries > 0) + { + LLStringUtil::format_map_t args; + args["[NUMBER]"] = llformat("%d", num_retries + 1); + set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); + } + else + { + set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); + } + } + display_startup(); + return FALSE; + } + + + //--------------------------------------------------------------------- + // Seed Capability Granted + // no newMessage calls should happen before this point + //--------------------------------------------------------------------- + if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) + { + display_startup(); + + // These textures are not warrantied to be cached, so needs + // to hapen with caps granted + gTextureList.doPrefetchImages(); + + // will init images, should be done with caps, but before gSky.init() + LLEnvironment::getInstance()->initSingleton(); + + display_startup(); + update_texture_fetch(); + display_startup(); + + if ( gViewerWindow != NULL) + { // This isn't the first logon attempt, so show the UI + gViewerWindow->setNormalControlsVisible( TRUE ); + } + gLoginMenuBarView->setVisible( FALSE ); + gLoginMenuBarView->setEnabled( FALSE ); + display_startup(); + + // direct logging to the debug console's line buffer + LLError::logToFixedBuffer(gDebugView->mDebugConsolep); + display_startup(); + + // set initial visibility of debug console + gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); + display_startup(); + + // + // Set message handlers + // + LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; + + // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted + register_viewer_callbacks(gMessageSystem); + display_startup(); + + // Debugging info parameters + gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms + display_startup(); + + #ifndef LL_RELEASE_FOR_DOWNLOAD + gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg + gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode + #endif + display_startup(); + + gXferManager->registerCallbacks(gMessageSystem); + display_startup(); + + LLStartUp::initNameCache(); + display_startup(); + + // update the voice settings *after* gCacheName initialization + // so that we can construct voice UI that relies on the name cache + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->updateSettings(); + } + display_startup(); + + // create a container's instance for start a controlling conversation windows + // by the voice's events + LLFloaterIMContainer::getInstance(); + if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) + { + LLViewerParcelAskPlay::getInstance()->loadSettings(); + } + + gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); + + // *Note: this is where gWorldMap used to be initialized. + + // register null callbacks for audio until the audio system is initialized + gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); + gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); + display_startup(); + + //reset statistics + LLViewerStats::instance().resetStats(); + + display_startup(); + // + // Set up region and surface defaults + // + + + // Sets up the parameters for the first simulator + + LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; + gFrameTime = totalTime(); + F32Seconds last_time = gFrameTimeSeconds; + gFrameTimeSeconds = (gFrameTime - gStartTime); + + gFrameIntervalSeconds = gFrameTimeSeconds - last_time; + if (gFrameIntervalSeconds < 0.f) + { + gFrameIntervalSeconds = 0.f; + } + + // Make sure agent knows correct aspect ratio + // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below + LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); + LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); + // Initialize FOV + LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); + display_startup(); + + // Move agent to starting location. The position handed to us by + // the space server is in global coordinates, but the agent frame + // is in region local coordinates. Therefore, we need to adjust + // the coordinates handed to us to fit in the local region. + + gAgent.setPositionAgent(agent_start_position_region); + gAgent.resetAxes(gAgentStartLookAt); + gAgentCamera.stopCameraAnimation(); + gAgentCamera.resetCamera(); + display_startup(); + + // Initialize global class data needed for surfaces (i.e. textures) + LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; + // Initialize all of the viewer object classes for the first time (doing things like texture fetches. + LLGLState::checkStates(); + + gSky.init(); + + LLGLState::checkStates(); + + display_startup(); + + LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; + // For all images pre-loaded into viewer cache, init + // priorities and fetching using decodeAllImages. + // Most of the fetching and decoding likely to be done + // by update_texture_fetch() later, while viewer waits. + // + // Need to do this AFTER we init the sky + const S32 DECODE_TIME_SEC = 2; + for (int i = 0; i < DECODE_TIME_SEC; i++) + { + F32 frac = (F32)i / (F32)DECODE_TIME_SEC; + set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); + display_startup(); + gTextureList.decodeAllImages(1.f); + } + LLStartUp::setStartupState( STATE_WORLD_WAIT ); + + display_startup(); + + // JC - Do this as late as possible to increase likelihood Purify + // will run. + LLMessageSystem* msg = gMessageSystem; + if (!msg->mOurCircuitCode) + { + LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; + } + + gUseCircuitCallbackCalled = false; + + msg->enableCircuit(gFirstSim, TRUE); + // now, use the circuit info to tell simulator about us! + LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; + msg->newMessageFast(_PREHASH_UseCircuitCode); + msg->nextBlockFast(_PREHASH_CircuitCode); + msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); + msg->sendReliable( + gFirstSim, + gSavedSettings.getS32("UseCircuitCodeMaxRetries"), + FALSE, + (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), + use_circuit_callback, + NULL); + + timeout.reset(); + display_startup(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // World Wait + //--------------------------------------------------------------------- + if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; + set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); + if(gGotUseCircuitCodeAck) + { + LLStartUp::setStartupState( STATE_AGENT_SEND ); + } + pump_idle_startup_network(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Send + //--------------------------------------------------------------------- + if (STATE_AGENT_SEND == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; + set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); + display_startup(); + // register with the message system so it knows we're + // expecting this message + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast( + _PREHASH_AgentMovementComplete, + process_agent_movement_complete); + LLViewerRegion* regionp = gAgent.getRegion(); + if(regionp) + { + send_complete_agent_movement(regionp->getHost()); + gAssetStorage->setUpstream(regionp->getHost()); + gCacheName->setUpstream(regionp->getHost()); + } + display_startup(); + + // Create login effect + // But not on first login, because you can't see your avatar then + if (!gAgent.isFirstLogin()) + { + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + } + + LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT + + timeout.reset(); + display_startup(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Wait + //--------------------------------------------------------------------- + if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) + { + { + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) + { + if (gAgentMovementCompleted) + { + // Sometimes we have more than one message in the + // queue. break out of this loop and continue + // processing. If we don't, then this could skip one + // or more login steps. + break; + } + else + { + LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " + << gMessageSystem->getMessageName() << LL_ENDL; + } + display_startup(); + } + lmc.processAcks(); + } + + display_startup(); + + if (gAgentMovementCompleted) + { + LLStartUp::setStartupState( STATE_INVENTORY_SEND ); + } + display_startup(); + + if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) + { + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + return FALSE; + } + + //--------------------------------------------------------------------- + // Inventory Send + //--------------------------------------------------------------------- + if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory send") + display_startup(); + + // request mute list + LL_INFOS() << "Requesting Mute List" << LL_ENDL; + LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + + // Get L$ and ownership credit information + LL_INFOS() << "Requesting Money Balance" << LL_ENDL; + LLStatusBar::sendMoneyBalanceRequest(); + + display_startup(); + + // Inform simulator of our language preference + LLAgentLanguage::update(); + + display_startup(); + // unpack thin inventory + LLSD response = LLLoginInstance::getInstance()->getResponse(); + //bool dump_buffer = false; + + LLSD inv_lib_root = response["inventory-lib-root"]; + if(inv_lib_root.isDefined()) + { + // should only be one + LLSD id = inv_lib_root[0]["folder_id"]; + if(id.isDefined()) + { + gInventory.setLibraryRootFolderID(id.asUUID()); + } + } + display_startup(); + + LLSD inv_lib_owner = response["inventory-lib-owner"]; + if(inv_lib_owner.isDefined()) + { + // should only be one + LLSD id = inv_lib_owner[0]["agent_id"]; + if(id.isDefined()) + { + gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); + } + } + display_startup(); + LLStartUp::setStartupState(STATE_INVENTORY_SKEL); + display_startup(); + return FALSE; + } + + if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory load skeleton") + + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + LLSD inv_skel_lib = response["inventory-skel-lib"]; + if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + { + LL_PROFILE_ZONE_NAMED("load library inv") + if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + } + } + display_startup(); + + LLSD inv_skeleton = response["inventory-skeleton"]; + if (inv_skeleton.isDefined()) + { + LL_PROFILE_ZONE_NAMED("load personal inv") + if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; + } + } + display_startup(); + LLStartUp::setStartupState(STATE_INVENTORY_SEND2); + display_startup(); + return FALSE; + } + + if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory send2") + + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + LLSD inv_basic = response["inventory-basic"]; + if(inv_basic.isDefined()) + { + LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; + } + + LLSD buddy_list = response["buddy-list"]; + if(buddy_list.isDefined()) + { + LLAvatarTracker::buddy_map_t list; + LLUUID agent_id; + S32 has_rights = 0, given_rights = 0; + for(LLSD::array_const_iterator it = buddy_list.beginArray(), + end = buddy_list.endArray(); it != end; ++it) + { + LLSD buddy_id = (*it)["buddy_id"]; + if(buddy_id.isDefined()) + { + agent_id = buddy_id.asUUID(); + } + + LLSD buddy_rights_has = (*it)["buddy_rights_has"]; + if(buddy_rights_has.isDefined()) + { + has_rights = buddy_rights_has.asInteger(); + } + + LLSD buddy_rights_given = (*it)["buddy_rights_given"]; + if(buddy_rights_given.isDefined()) + { + given_rights = buddy_rights_given.asInteger(); + } + + list[agent_id] = new LLRelationship(given_rights, has_rights, false); + } + LLAvatarTracker::instance().addBuddyList(list); + display_startup(); + } + + bool show_hud = false; + LLSD tutorial_setting = response["tutorial_setting"]; + if(tutorial_setting.isDefined()) + { + for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), + end = tutorial_setting.endArray(); it != end; ++it) + { + LLSD tutorial_url = (*it)["tutorial_url"]; + if(tutorial_url.isDefined()) + { + // Tutorial floater will append language code + gSavedSettings.setString("TutorialURL", tutorial_url.asString()); + } + + // For Viewer 2.0 we are not using the web-based tutorial + // If we reverse that decision, put this code back and use + // login.cgi to send a different URL with content that matches + // the Viewer 2.0 UI. + //LLSD use_tutorial = (*it)["use_tutorial"]; + //if(use_tutorial.asString() == "true") + //{ + // show_hud = true; + //} + } + } + display_startup(); + + // Either we want to show tutorial because this is the first login + // to a Linden Help Island or the user quit with the tutorial + // visible. JC + if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) + { + LLFloaterReg::showInstance("hud", LLSD(), FALSE); + } + display_startup(); + + LLSD event_notifications = response["event_notifications"]; + if(event_notifications.isDefined()) + { + gEventNotifier.load(event_notifications); + } + display_startup(); + + LLSD classified_categories = response["classified_categories"]; + if(classified_categories.isDefined()) + { + LLClassifiedInfo::loadCategories(classified_categories); + } + display_startup(); + + // This method MUST be called before gInventory.findCategoryUUIDForType because of + // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. + gInventory.buildParentChildMap(); + + // If buildParentChildMap succeeded, inventory will now be in + // a usable state and gInventory.isInventoryUsable() will be + // true. + + // if inventory is unusable, show warning. + if (!gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("InventoryUnusable"); + } + + LLInventoryModelBackgroundFetch::instance().start(); + gInventory.createCommonSystemCategories(); + LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); + display_startup(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // STATE_INVENTORY_CALLBACKS + //--------------------------------------------------------------------- + if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) + { + if (!LLInventoryModel::isSysFoldersReady()) + { + display_startup(); + return FALSE; + } + LLInventoryModelBackgroundFetch::instance().start(); + LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); + if (cof + && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // Special case, dupplicate request prevention. + // Cof folder will be requested via FetchCOF + // in appearance manager, prevent recursive fetch + cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); + } + + + // It's debatable whether this flag is a good idea - sets all + // bits, and in general it isn't true that inventory + // initialization generates all types of changes. Maybe add an + // INITIALIZE mask bit instead? + gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); + gInventory.notifyObservers(); + + display_startup(); + + // set up callbacks + LL_INFOS() << "Registering Callbacks" << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + LL_INFOS() << " Inventory" << LL_ENDL; + LLInventoryModel::registerCallbacks(msg); + LL_INFOS() << " AvatarTracker" << LL_ENDL; + LLAvatarTracker::instance().registerCallbacks(msg); + LL_INFOS() << " Landmark" << LL_ENDL; + LLLandmark::registerCallbacks(msg); + display_startup(); + + // request all group information + LL_INFOS() << "Requesting Agent Data" << LL_ENDL; + gAgent.sendAgentDataUpdateRequest(); + display_startup(); + // Create the inventory views + LL_INFOS() << "Creating Inventory Views" << LL_ENDL; + LLFloaterReg::getInstance("inventory"); + display_startup(); + LLStartUp::setStartupState( STATE_MISC ); + display_startup(); + + return FALSE; + } + - LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); - display_startup(); - - LLViewerObject::initVOClasses(); - display_startup(); - - // Initialize all our tools. Must be done after saved settings loaded. - // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. - LLToolMgr::getInstance()->initTools(); - display_startup(); - - // Pre-load floaters, like the world map, that are slow to spawn - // due to XML complexity. - gViewerWindow->initWorldUI(); - - display_startup(); - - // This is where we used to initialize gWorldp. Original comment said: - // World initialization must be done after above window init - - // User might have overridden far clip - LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); - display_startup(); - // Before we create the first region, we need to set the agent's mOriginGlobal - // This is necessary because creating objects before this is set will result in a - // bad mPositionAgent cache. - - gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); - display_startup(); - - LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); - display_startup(); - - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); - LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; - - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " - << gFirstSimSeedCap << LL_ENDL; - regionp->setSeedCapability(gFirstSimSeedCap); - LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; - display_startup(); - // Set agent's initial region to be the one we just created. - gAgent.setRegion(regionp); - display_startup(); - // Set agent's initial position, which will be read by LLVOAvatar when the avatar - // object is created. I think this must be done after setting the region. JC - gAgent.setPositionAgent(agent_start_position_region); - - display_startup(); - LLStartUp::initExperiences(); - - display_startup(); - - // If logging should be enebled, turns it on and loads history from disk - // Note: does not happen on init of singleton because preferences can use - // this instance without logging in - LLConversationLog::getInstance()->initLoggingState(); - - LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); - - return FALSE; - } - - - //--------------------------------------------------------------------- - // Load QuickTime/GStreamer and other multimedia engines, can be slow. - // Do it while we're waiting on the network for our seed capability. JC - //--------------------------------------------------------------------- - if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) - { - LLStartUp::multimediaInit(); - LLStartUp::setStartupState( STATE_FONT_INIT ); - display_startup(); - return FALSE; - } - - // Loading fonts takes several seconds - if (STATE_FONT_INIT == LLStartUp::getStartupState()) - { - LLStartUp::fontInit(); - LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); - display_startup(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Wait for Seed Cap Grant - //--------------------------------------------------------------------- - if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); - if (regionp->capabilitiesReceived()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - else if (regionp->capabilitiesError()) + //--------------------------------------------------------------------- + // Misc + //--------------------------------------------------------------------- + if (STATE_MISC == LLStartUp::getStartupState()) + { + // We have a region, and just did a big inventory download. + // We can estimate the user's connection speed, and set their + // max bandwidth accordingly. JC + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { - LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) + // This is actually a pessimistic computation, because TCP may not have enough + // time to ramp up on the (small) default inventory file to truly measure max + // bandwidth. JC + F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); + const F32 FAST_RATE_BPS = 600.f * 1024.f; + const F32 FASTER_RATE_BPS = 750.f * 1024.f; + F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); + if (rate_bps > FASTER_RATE_BPS + && rate_bps > max_bandwidth) { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FASTER_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); } - else + else if (rate_bps > FAST_RATE_BPS + && rate_bps > max_bandwidth) { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FAST_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); } - reset_login(); - } - else - { - U32 num_retries = regionp->getNumSeedCapRetries(); - if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) + + if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) { - LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); + gSavedSettings.setBOOL("HelpFloaterOpen", TRUE); } - else if (num_retries > 0) - { - LLStringUtil::format_map_t args; - args["[NUMBER]"] = llformat("%d", num_retries + 1); - set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); - } - else - { - set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); - } - } - display_startup(); - return FALSE; - } - - - //--------------------------------------------------------------------- - // Seed Capability Granted - // no newMessage calls should happen before this point - //--------------------------------------------------------------------- - if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) - { - display_startup(); - // These textures are not warrantied to be cached, so needs - // to hapen with caps granted - gTextureList.doPrefetchImages(); - - // will init images, should be done with caps, but before gSky.init() - LLEnvironment::getInstance()->initSingleton(); + // Set the show start location to true, now that the user has logged + // on with this install. + gSavedSettings.setBOOL("ShowStartLocation", TRUE); + } display_startup(); - update_texture_fetch(); - display_startup(); - - if ( gViewerWindow != NULL) - { // This isn't the first logon attempt, so show the UI - gViewerWindow->setNormalControlsVisible( TRUE ); - } - gLoginMenuBarView->setVisible( FALSE ); - gLoginMenuBarView->setEnabled( FALSE ); - display_startup(); - - // direct logging to the debug console's line buffer - LLError::logToFixedBuffer(gDebugView->mDebugConsolep); - display_startup(); - - // set initial visibility of debug console - gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); - display_startup(); - - // - // Set message handlers - // - LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; - - // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted - register_viewer_callbacks(gMessageSystem); - display_startup(); - - // Debugging info parameters - gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms - display_startup(); - - #ifndef LL_RELEASE_FOR_DOWNLOAD - gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg - gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode - #endif - display_startup(); - - gXferManager->registerCallbacks(gMessageSystem); - display_startup(); - - LLStartUp::initNameCache(); - display_startup(); - - // update the voice settings *after* gCacheName initialization - // so that we can construct voice UI that relies on the name cache - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->updateSettings(); - } - display_startup(); - - // create a container's instance for start a controlling conversation windows - // by the voice's events - LLFloaterIMContainer::getInstance(); - if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) - { - LLViewerParcelAskPlay::getInstance()->loadSettings(); - } - - gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); - - // *Note: this is where gWorldMap used to be initialized. - - // register null callbacks for audio until the audio system is initialized - gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); - display_startup(); - - //reset statistics - LLViewerStats::instance().resetStats(); - - display_startup(); - // - // Set up region and surface defaults - // - - - // Sets up the parameters for the first simulator - - LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; - gFrameTime = totalTime(); - F32Seconds last_time = gFrameTimeSeconds; - gFrameTimeSeconds = (gFrameTime - gStartTime); - - gFrameIntervalSeconds = gFrameTimeSeconds - last_time; - if (gFrameIntervalSeconds < 0.f) - { - gFrameIntervalSeconds = 0.f; - } - - // Make sure agent knows correct aspect ratio - // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below - LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); - LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); - // Initialize FOV - LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); - display_startup(); - - // Move agent to starting location. The position handed to us by - // the space server is in global coordinates, but the agent frame - // is in region local coordinates. Therefore, we need to adjust - // the coordinates handed to us to fit in the local region. - - gAgent.setPositionAgent(agent_start_position_region); - gAgent.resetAxes(gAgentStartLookAt); - gAgentCamera.stopCameraAnimation(); - gAgentCamera.resetCamera(); - display_startup(); - - // Initialize global class data needed for surfaces (i.e. textures) - LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; - // Initialize all of the viewer object classes for the first time (doing things like texture fetches. - LLGLState::checkStates(); - - gSky.init(); - - LLGLState::checkStates(); - - display_startup(); - - LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; - // For all images pre-loaded into viewer cache, init - // priorities and fetching using decodeAllImages. - // Most of the fetching and decoding likely to be done - // by update_texture_fetch() later, while viewer waits. - // - // Need to do this AFTER we init the sky - const S32 DECODE_TIME_SEC = 2; - for (int i = 0; i < DECODE_TIME_SEC; i++) - { - F32 frac = (F32)i / (F32)DECODE_TIME_SEC; - set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); - display_startup(); - gTextureList.decodeAllImages(1.f); - } - LLStartUp::setStartupState( STATE_WORLD_WAIT ); - - display_startup(); - - // JC - Do this as late as possible to increase likelihood Purify - // will run. - LLMessageSystem* msg = gMessageSystem; - if (!msg->mOurCircuitCode) - { - LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; - } - - gUseCircuitCallbackCalled = false; - - msg->enableCircuit(gFirstSim, TRUE); - // now, use the circuit info to tell simulator about us! - LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable( - gFirstSim, - gSavedSettings.getS32("UseCircuitCodeMaxRetries"), - FALSE, - (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), - use_circuit_callback, - NULL); - - timeout.reset(); - display_startup(); - - return FALSE; - } - - //--------------------------------------------------------------------- - // World Wait - //--------------------------------------------------------------------- - if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; - set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); - if(gGotUseCircuitCodeAck) - { - LLStartUp::setStartupState( STATE_AGENT_SEND ); - } - pump_idle_startup_network(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Agent Send - //--------------------------------------------------------------------- - if (STATE_AGENT_SEND == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; - set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); - display_startup(); - // register with the message system so it knows we're - // expecting this message - LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFuncFast( - _PREHASH_AgentMovementComplete, - process_agent_movement_complete); - LLViewerRegion* regionp = gAgent.getRegion(); - if(regionp) - { - send_complete_agent_movement(regionp->getHost()); - gAssetStorage->setUpstream(regionp->getHost()); - gCacheName->setUpstream(regionp->getHost()); - } - display_startup(); - - // Create login effect - // But not on first login, because you can't see your avatar then - if (!gAgent.isFirstLogin()) - { - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - } - - LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT - - timeout.reset(); - display_startup(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Agent Wait - //--------------------------------------------------------------------- - if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) - { - { - LockMessageChecker lmc(gMessageSystem); - while (lmc.checkAllMessages(gFrameCount, gServicePump)) - { - if (gAgentMovementCompleted) - { - // Sometimes we have more than one message in the - // queue. break out of this loop and continue - // processing. If we don't, then this could skip one - // or more login steps. - break; - } - else - { - LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " - << gMessageSystem->getMessageName() << LL_ENDL; - } - display_startup(); - } - lmc.processAcks(); - } - - display_startup(); - - if (gAgentMovementCompleted) - { - LLStartUp::setStartupState( STATE_INVENTORY_SEND ); - } - display_startup(); - - if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) - { - LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); - } - return FALSE; - } - - //--------------------------------------------------------------------- - // Inventory Send - //--------------------------------------------------------------------- - if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) - { - LL_PROFILE_ZONE_NAMED("State inventory send") - display_startup(); - // request mute list - LL_INFOS() << "Requesting Mute List" << LL_ENDL; - LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + // Load stored local environment if needed. + LLEnvironment::instance().loadFromSettings(); - // Get L$ and ownership credit information - LL_INFOS() << "Requesting Money Balance" << LL_ENDL; - LLStatusBar::sendMoneyBalanceRequest(); + // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) + //check_merchant_status(); display_startup(); - // Inform simulator of our language preference - LLAgentLanguage::update(); - - display_startup(); - // unpack thin inventory - LLSD response = LLLoginInstance::getInstance()->getResponse(); - //bool dump_buffer = false; - - LLSD inv_lib_root = response["inventory-lib-root"]; - if(inv_lib_root.isDefined()) - { - // should only be one - LLSD id = inv_lib_root[0]["folder_id"]; - if(id.isDefined()) - { - gInventory.setLibraryRootFolderID(id.asUUID()); - } - } - display_startup(); - - LLSD inv_lib_owner = response["inventory-lib-owner"]; - if(inv_lib_owner.isDefined()) - { - // should only be one - LLSD id = inv_lib_owner[0]["agent_id"]; - if(id.isDefined()) - { - gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); - } - } - display_startup(); - LLStartUp::setStartupState(STATE_INVENTORY_SKEL); - display_startup(); - return FALSE; - } + if (gSavedSettings.getBOOL("HelpFloaterOpen")) + { + // show default topic + LLViewerHelp::instance().showTopic(""); + } - if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) - { - LL_PROFILE_ZONE_NAMED("State inventory load skeleton") + display_startup(); - LLSD response = LLLoginInstance::getInstance()->getResponse(); + // We're successfully logged in. + gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); - LLSD inv_skel_lib = response["inventory-skel-lib"]; - if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + LLFloaterReg::showInitialVisibleInstances(); + + LLFloaterGridStatus::getInstance()->startGridStatusTimer(); + + display_startup(); + + display_startup(); + // JC: Initializing audio requests many sounds for download. + init_audio(); + display_startup(); + + // JC: Initialize "active" gestures. This may also trigger + // many gesture downloads, if this is the user's first + // time on this machine or -purge has been run. + LLSD gesture_options + = LLLoginInstance::getInstance()->getResponse("gestures"); + if (gesture_options.isDefined()) { - LL_PROFILE_ZONE_NAMED("load library inv") - if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() + << LL_ENDL; + uuid_vec_t item_ids; + for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), + end = gesture_options.endArray(); resp_it != end; ++resp_it) { - LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + // If the id is not specifed in the LLSD, + // the LLSD operator[]() will return a null LLUUID. + LLUUID item_id = (*resp_it)["item_id"]; + LLUUID asset_id = (*resp_it)["asset_id"]; + + if (item_id.notNull() && asset_id.notNull()) + { + // Could schedule and delay these for later. + const BOOL no_inform_server = FALSE; + const BOOL no_deactivate_similar = FALSE; + LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, + no_inform_server, + no_deactivate_similar); + // We need to fetch the inventory items for these gestures + // so we have the names to populate the UI. + item_ids.push_back(item_id); + } } + // no need to add gesture to inventory observer, it's already made in constructor + LLGestureMgr::instance().setFetchIDs(item_ids); + LLGestureMgr::instance().startFetch(); } + gDisplaySwapBuffers = TRUE; display_startup(); - LLSD inv_skeleton = response["inventory-skeleton"]; - if (inv_skeleton.isDefined()) + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); + msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); + + LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; + + LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; + gRenderStartTime.reset(); + gForegroundTime.reset(); + + // HACK: Inform simulator of window size. + // Do this here so it's less likely to race with RegisterNewAgent. + // TODO: Put this into RegisterNewAgent + // JC - 7/20/2002 + gViewerWindow->sendShapeToSim(); + + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + + // The reason we show the alert is because we want to + // reduce confusion for when you log in and your provided + // location is not your expected location. So, if this is + // your first login, then you do not have an expectation, + // thus, do not show this alert. + if (!gAgent.isFirstLogin()) { - LL_PROFILE_ZONE_NAMED("load personal inv") - if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; + LLSLURL start_slurl = LLStartUp::getStartSLURL(); + LL_DEBUGS("AppInit") << "start slurl "<<start_slurl.asString()<<LL_ENDL; + + if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || + ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || + ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) { - LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; + if (start_slurl.getType() == LLSLURL::LAST_LOCATION + && gAgentStartLocation == "last" + && gSavedSettings.getBOOL("RestoreCameraPosOnLogin")) + { + // restore old camera pos + gAgentCamera.setFocusOnAvatar(FALSE, FALSE); + gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null); + BOOL limit_hit = FALSE; + gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit); + if (limit_hit) + { + gAgentCamera.setFocusOnAvatar(TRUE, FALSE); + } + gAgentCamera.stopCameraAnimation(); + } + } + else + { + std::string msg; + switch(start_slurl.getType()) + { + case LLSLURL::LOCATION: + { + + msg = "AvatarMovedDesired"; + break; + } + case LLSLURL::HOME_LOCATION: + { + msg = "AvatarMovedHome"; + break; + } + default: + { + msg = "AvatarMovedLast"; + } + } + LLNotificationsUtil::add(msg); } } + display_startup(); - LLStartUp::setStartupState(STATE_INVENTORY_SEND2); + //DEV-17797. get null folder. Any items found here moved to Lost and Found + LLInventoryModelBackgroundFetch::instance().findLostItems(); display_startup(); + + LLStartUp::setStartupState( STATE_PRECACHE ); + timeout.reset(); return FALSE; } - if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState()) + if (STATE_PRECACHE == LLStartUp::getStartupState()) { - LL_PROFILE_ZONE_NAMED("State inventory send2") + display_startup(); + F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; + + // We now have an inventory skeleton, so if this is a user's first + // login, we can start setting up their clothing and avatar + // appearance. This helps to avoid the generic "Ruth" avatar in + // the orientation island tutorial experience. JC + if (gAgent.isFirstLogin() + && !sInitialOutfit.empty() // registration set up an outfit + && !sInitialOutfitGender.empty() // and a gender + && isAgentAvatarValid() // can't wear clothes without object + && !gAgent.isOutfitChosen()) // nothing already loading + { + // Start loading the wearables, textures, gestures + LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); + } + // If not first login, we need to fetch COF contents and + // compute appearance from that. + if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) + { + gAgentWearables.notifyLoadingStarted(); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); + callAfterCOFFetch(set_flags_and_update_appearance); + } - LLSD response = LLLoginInstance::getInstance()->getResponse(); - - LLSD inv_basic = response["inventory-basic"]; - if(inv_basic.isDefined()) - { - LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; - } - - LLSD buddy_list = response["buddy-list"]; - if(buddy_list.isDefined()) - { - LLAvatarTracker::buddy_map_t list; - LLUUID agent_id; - S32 has_rights = 0, given_rights = 0; - for(LLSD::array_const_iterator it = buddy_list.beginArray(), - end = buddy_list.endArray(); it != end; ++it) - { - LLSD buddy_id = (*it)["buddy_id"]; - if(buddy_id.isDefined()) - { - agent_id = buddy_id.asUUID(); - } - - LLSD buddy_rights_has = (*it)["buddy_rights_has"]; - if(buddy_rights_has.isDefined()) - { - has_rights = buddy_rights_has.asInteger(); - } - - LLSD buddy_rights_given = (*it)["buddy_rights_given"]; - if(buddy_rights_given.isDefined()) - { - given_rights = buddy_rights_given.asInteger(); - } - - list[agent_id] = new LLRelationship(given_rights, has_rights, false); - } - LLAvatarTracker::instance().addBuddyList(list); - display_startup(); - } - - bool show_hud = false; - LLSD tutorial_setting = response["tutorial_setting"]; - if(tutorial_setting.isDefined()) - { - for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), - end = tutorial_setting.endArray(); it != end; ++it) - { - LLSD tutorial_url = (*it)["tutorial_url"]; - if(tutorial_url.isDefined()) - { - // Tutorial floater will append language code - gSavedSettings.setString("TutorialURL", tutorial_url.asString()); - } - - // For Viewer 2.0 we are not using the web-based tutorial - // If we reverse that decision, put this code back and use - // login.cgi to send a different URL with content that matches - // the Viewer 2.0 UI. - //LLSD use_tutorial = (*it)["use_tutorial"]; - //if(use_tutorial.asString() == "true") - //{ - // show_hud = true; - //} - } - } - display_startup(); - - // Either we want to show tutorial because this is the first login - // to a Linden Help Island or the user quit with the tutorial - // visible. JC - if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) - { - LLFloaterReg::showInstance("hud", LLSD(), FALSE); - } - display_startup(); - - LLSD event_notifications = response["event_notifications"]; - if(event_notifications.isDefined()) - { - gEventNotifier.load(event_notifications); - } - display_startup(); - - LLSD classified_categories = response["classified_categories"]; - if(classified_categories.isDefined()) - { - LLClassifiedInfo::loadCategories(classified_categories); - } - display_startup(); - - // This method MUST be called before gInventory.findCategoryUUIDForType because of - // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. - gInventory.buildParentChildMap(); - - // If buildParentChildMap succeeded, inventory will now be in - // a usable state and gInventory.isInventoryUsable() will be - // true. - - // if inventory is unusable, show warning. - if (!gInventory.isInventoryUsable()) - { - LLNotificationsUtil::add("InventoryUnusable"); - } - - LLInventoryModelBackgroundFetch::instance().start(); - gInventory.createCommonSystemCategories(); - LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); display_startup(); - return FALSE; + // wait precache-delay and for agent's avatar or a lot longer. + if ((timeout_frac > 1.f) && isAgentAvatarValid()) + { + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else if (timeout_frac > 10.f) + { + // If we exceed the wait above while isAgentAvatarValid is + // not true yet, we will change startup state and + // eventually (once avatar does get created) wind up at + // the gender chooser. This should occur only in very + // unusual circumstances, so set the timeout fairly high + // to minimize mistaken hits here. + LL_WARNS() << "Wait for valid avatar state exceeded " + << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else + { + update_texture_fetch(); + set_startup_status(0.60f + 0.30f * timeout_frac, + LLTrans::getString("LoginPrecaching"), + gAgent.mMOTD.c_str()); + display_startup(); + } + + return TRUE; } - //--------------------------------------------------------------------- - // STATE_INVENTORY_CALLBACKS - //--------------------------------------------------------------------- - if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) + if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) { - if (!LLInventoryModel::isSysFoldersReady()) + static LLFrameTimer wearables_timer; + + const F32 wearables_time = wearables_timer.getElapsedTimeF32(); + static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); + + if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { - display_startup(); - return FALSE; + // No point in waiting for clothing, we don't even know + // what outfit we want. Pop up a gender chooser dialog to + // ask and proceed to draw the world. JC + // + // *NOTE: We might hit this case even if we have an + // initial outfit, but if the load hasn't started + // already then something is wrong so fall back + // to generic outfits. JC + LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), + callback_choose_gender); + LLStartUp::setStartupState( STATE_CLEANUP ); } - LLInventoryModelBackgroundFetch::instance().start(); - LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); - if (cof - && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + + display_startup(); + + if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) { - // Special case, dupplicate request prevention. - // Cof folder will be requested via FetchCOF - // in appearance manager, prevent recursive fetch - cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); + if (gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("ClothingLoading"); + } + record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); + LLStartUp::setStartupState( STATE_CLEANUP ); + } + else if (gAgent.isFirstLogin() + && isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + // wait for avatar to be completely loaded + if (isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + } + else + { + // OK to just get the wearables + if ( gAgentWearables.areWearablesLoaded() ) + { + // We have our clothing, proceed. + LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } + //fall through this frame to STATE_CLEANUP + } + if (STATE_CLEANUP == LLStartUp::getStartupState()) + { + set_startup_status(1.0, "", ""); + display_startup(); - // It's debatable whether this flag is a good idea - sets all - // bits, and in general it isn't true that inventory - // initialization generates all types of changes. Maybe add an - // INITIALIZE mask bit instead? - gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); - gInventory.notifyObservers(); - - display_startup(); - - // set up callbacks - LL_INFOS() << "Registering Callbacks" << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - LL_INFOS() << " Inventory" << LL_ENDL; - LLInventoryModel::registerCallbacks(msg); - LL_INFOS() << " AvatarTracker" << LL_ENDL; - LLAvatarTracker::instance().registerCallbacks(msg); - LL_INFOS() << " Landmark" << LL_ENDL; - LLLandmark::registerCallbacks(msg); - display_startup(); - - // request all group information - LL_INFOS() << "Requesting Agent Data" << LL_ENDL; - gAgent.sendAgentDataUpdateRequest(); - display_startup(); - // Create the inventory views - LL_INFOS() << "Creating Inventory Views" << LL_ENDL; - LLFloaterReg::getInstance("inventory"); - display_startup(); - LLStartUp::setStartupState( STATE_MISC ); - display_startup(); - - return FALSE; - } - - - //--------------------------------------------------------------------- - // Misc - //--------------------------------------------------------------------- - if (STATE_MISC == LLStartUp::getStartupState()) - { - // We have a region, and just did a big inventory download. - // We can estimate the user's connection speed, and set their - // max bandwidth accordingly. JC - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) - { - // This is actually a pessimistic computation, because TCP may not have enough - // time to ramp up on the (small) default inventory file to truly measure max - // bandwidth. JC - F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); - const F32 FAST_RATE_BPS = 600.f * 1024.f; - const F32 FASTER_RATE_BPS = 750.f * 1024.f; - F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); - if (rate_bps > FASTER_RATE_BPS - && rate_bps > max_bandwidth) - { - LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " - << FASTER_RATE_BPS/1024.f - << " kbps" << LL_ENDL; - gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); - } - else if (rate_bps > FAST_RATE_BPS - && rate_bps > max_bandwidth) - { - LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " - << FAST_RATE_BPS/1024.f - << " kbps" << LL_ENDL; - gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); - } - - if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) - { - gSavedSettings.setBOOL("HelpFloaterOpen", TRUE); - } - - // Set the show start location to true, now that the user has logged - // on with this install. - gSavedSettings.setBOOL("ShowStartLocation", TRUE); - } - - display_startup(); + if (!mBenefitsSuccessfullyInit) + { + LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); + } - // Load stored local environment if needed. - LLEnvironment::instance().loadFromSettings(); + // Let the map know about the inventory. + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if(floater_world_map) + { + floater_world_map->observeInventory(&gInventory); + floater_world_map->observeFriends(); + } + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->resetBusyCount(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; + //gViewerWindow->revealIntroPanel(); + gViewerWindow->setStartupComplete(); + gViewerWindow->setProgressCancelButtonVisible(FALSE); + display_startup(); - // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) - //check_merchant_status(); + // We're not away from keyboard, even though login might have taken + // a while. JC + gAgent.clearAFK(); - display_startup(); - - if (gSavedSettings.getBOOL("HelpFloaterOpen")) - { - // show default topic - LLViewerHelp::instance().showTopic(""); - } - - display_startup(); - - // We're successfully logged in. - gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); - - LLFloaterReg::showInitialVisibleInstances(); - - LLFloaterGridStatus::getInstance()->startGridStatusTimer(); - - display_startup(); - - display_startup(); - // JC: Initializing audio requests many sounds for download. - init_audio(); - display_startup(); - - // JC: Initialize "active" gestures. This may also trigger - // many gesture downloads, if this is the user's first - // time on this machine or -purge has been run. - LLSD gesture_options - = LLLoginInstance::getInstance()->getResponse("gestures"); - if (gesture_options.isDefined()) - { - LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() - << LL_ENDL; - uuid_vec_t item_ids; - for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), - end = gesture_options.endArray(); resp_it != end; ++resp_it) - { - // If the id is not specifed in the LLSD, - // the LLSD operator[]() will return a null LLUUID. - LLUUID item_id = (*resp_it)["item_id"]; - LLUUID asset_id = (*resp_it)["asset_id"]; - - if (item_id.notNull() && asset_id.notNull()) - { - // Could schedule and delay these for later. - const BOOL no_inform_server = FALSE; - const BOOL no_deactivate_similar = FALSE; - LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, - no_inform_server, - no_deactivate_similar); - // We need to fetch the inventory items for these gestures - // so we have the names to populate the UI. - item_ids.push_back(item_id); - } - } - // no need to add gesture to inventory observer, it's already made in constructor - LLGestureMgr::instance().setFetchIDs(item_ids); - LLGestureMgr::instance().startFetch(); - } - gDisplaySwapBuffers = TRUE; - display_startup(); - - LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); - msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); - msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); - msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); - - LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; - - LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; - gRenderStartTime.reset(); - gForegroundTime.reset(); - - // HACK: Inform simulator of window size. - // Do this here so it's less likely to race with RegisterNewAgent. - // TODO: Put this into RegisterNewAgent - // JC - 7/20/2002 - gViewerWindow->sendShapeToSim(); - - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); - - // The reason we show the alert is because we want to - // reduce confusion for when you log in and your provided - // location is not your expected location. So, if this is - // your first login, then you do not have an expectation, - // thus, do not show this alert. - if (!gAgent.isFirstLogin()) - { - LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; - LLSLURL start_slurl = LLStartUp::getStartSLURL(); - LL_DEBUGS("AppInit") << "start slurl "<<start_slurl.asString()<<LL_ENDL; - - if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || - ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || - ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) - { - if (start_slurl.getType() == LLSLURL::LAST_LOCATION - && gAgentStartLocation == "last" - && gSavedSettings.getBOOL("RestoreCameraPosOnLogin")) - { - // restore old camera pos - gAgentCamera.setFocusOnAvatar(FALSE, FALSE); - gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null); - BOOL limit_hit = FALSE; - gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit); - if (limit_hit) - { - gAgentCamera.setFocusOnAvatar(TRUE, FALSE); - } - gAgentCamera.stopCameraAnimation(); - } - } - else - { - std::string msg; - switch(start_slurl.getType()) - { - case LLSLURL::LOCATION: - { - - msg = "AvatarMovedDesired"; - break; - } - case LLSLURL::HOME_LOCATION: - { - msg = "AvatarMovedHome"; - break; - } - default: - { - msg = "AvatarMovedLast"; - } - } - LLNotificationsUtil::add(msg); - } - } - - display_startup(); - //DEV-17797. get null folder. Any items found here moved to Lost and Found - LLInventoryModelBackgroundFetch::instance().findLostItems(); - display_startup(); - - LLStartUp::setStartupState( STATE_PRECACHE ); - timeout.reset(); - return FALSE; - } - - if (STATE_PRECACHE == LLStartUp::getStartupState()) - { - display_startup(); - F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; - - // We now have an inventory skeleton, so if this is a user's first - // login, we can start setting up their clothing and avatar - // appearance. This helps to avoid the generic "Ruth" avatar in - // the orientation island tutorial experience. JC - if (gAgent.isFirstLogin() - && !sInitialOutfit.empty() // registration set up an outfit - && !sInitialOutfitGender.empty() // and a gender - && isAgentAvatarValid() // can't wear clothes without object - && !gAgent.isOutfitChosen()) // nothing already loading - { - // Start loading the wearables, textures, gestures - LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); - } - // If not first login, we need to fetch COF contents and - // compute appearance from that. - if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) - { - gAgentWearables.notifyLoadingStarted(); - gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); - callAfterCOFFetch(set_flags_and_update_appearance); - } - - display_startup(); - - // wait precache-delay and for agent's avatar or a lot longer. - if ((timeout_frac > 1.f) && isAgentAvatarValid()) - { - LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); - } - else if (timeout_frac > 10.f) - { - // If we exceed the wait above while isAgentAvatarValid is - // not true yet, we will change startup state and - // eventually (once avatar does get created) wind up at - // the gender chooser. This should occur only in very - // unusual circumstances, so set the timeout fairly high - // to minimize mistaken hits here. - LL_WARNS() << "Wait for valid avatar state exceeded " - << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; - LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); - } - else - { - update_texture_fetch(); - set_startup_status(0.60f + 0.30f * timeout_frac, - LLTrans::getString("LoginPrecaching"), - gAgent.mMOTD.c_str()); - display_startup(); - } - - return TRUE; - } - - if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) - { - static LLFrameTimer wearables_timer; - - const F32 wearables_time = wearables_timer.getElapsedTimeF32(); - static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); - - if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) - { - // No point in waiting for clothing, we don't even know - // what outfit we want. Pop up a gender chooser dialog to - // ask and proceed to draw the world. JC - // - // *NOTE: We might hit this case even if we have an - // initial outfit, but if the load hasn't started - // already then something is wrong so fall back - // to generic outfits. JC - LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), - callback_choose_gender); - LLStartUp::setStartupState( STATE_CLEANUP ); - } - - display_startup(); - - if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) - { - if (gInventory.isInventoryUsable()) - { - LLNotificationsUtil::add("ClothingLoading"); - } - record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); - LLStartUp::setStartupState( STATE_CLEANUP ); - } - else if (gAgent.isFirstLogin() - && isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - // wait for avatar to be completely loaded - if (isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } - } - else - { - // OK to just get the wearables - if ( gAgentWearables.areWearablesLoaded() ) - { - // We have our clothing, proceed. - LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } - } - //fall through this frame to STATE_CLEANUP - } - - if (STATE_CLEANUP == LLStartUp::getStartupState()) - { - set_startup_status(1.0, "", ""); - display_startup(); - - if (!mBenefitsSuccessfullyInit) - { - LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); - } - - // Let the map know about the inventory. - LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); - if(floater_world_map) - { - floater_world_map->observeInventory(&gInventory); - floater_world_map->observeFriends(); - } - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->resetBusyCount(); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; - //gViewerWindow->revealIntroPanel(); - gViewerWindow->setStartupComplete(); - gViewerWindow->setProgressCancelButtonVisible(FALSE); - display_startup(); - - // We're not away from keyboard, even though login might have taken - // a while. JC - gAgent.clearAFK(); - - // Have the agent start watching the friends list so we can update proxies - gAgent.observeFriends(); - - // Start automatic replay if the flag is set. - if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) - { - LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; - gAgentPilot.startPlayback(); - } - - show_debug_menus(); // Debug menu visiblity and First Use trigger - - // If we've got a startup URL, dispatch it - //LLStartUp::dispatchURL(); - - // Retrieve information about the land data - // (just accessing this the first time will fetch it, - // then the data is cached for the viewer's lifetime) - LLProductInfoRequestManager::instance(); - - // *FIX:Mani - What do I do here? - // Need we really clear the Auth response data? - // Clean up the userauth stuff. - // LLUserAuth::getInstance()->reset(); - - LLStartUp::setStartupState( STATE_STARTED ); - display_startup(); - - // Unmute audio if desired and setup volumes. - // This is a not-uncommon crash site, so surround it with - // LL_INFOS() output to aid diagnosis. - LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; - audio_update_volume(); - LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; - - // reset keyboard focus to sane state of pointing at world - gFocusMgr.setKeyboardFocus(NULL); - - LLAppViewer::instance()->handleLoginComplete(); - - LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); - - display_startup(); - - llassert(LLPathfindingManager::getInstance() != NULL); - LLPathfindingManager::getInstance()->initSystem(); - - gAgentAvatarp->sendHoverHeight(); - - // look for parcels we own - send_places_query(LLUUID::null, - LLUUID::null, - "", - DFQ_AGENT_OWNED, - LLParcel::C_ANY, - ""); - - LLUIUsage::instance().clear(); + // Have the agent start watching the friends list so we can update proxies + gAgent.observeFriends(); + + // Start automatic replay if the flag is set. + if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) + { + LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; + gAgentPilot.startPlayback(); + } + + show_debug_menus(); // Debug menu visiblity and First Use trigger + + // If we've got a startup URL, dispatch it + //LLStartUp::dispatchURL(); + + // Retrieve information about the land data + // (just accessing this the first time will fetch it, + // then the data is cached for the viewer's lifetime) + LLProductInfoRequestManager::instance(); + + // *FIX:Mani - What do I do here? + // Need we really clear the Auth response data? + // Clean up the userauth stuff. + // LLUserAuth::getInstance()->reset(); + + LLStartUp::setStartupState( STATE_STARTED ); + display_startup(); + + // Unmute audio if desired and setup volumes. + // This is a not-uncommon crash site, so surround it with + // LL_INFOS() output to aid diagnosis. + LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; + audio_update_volume(); + LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; + + // reset keyboard focus to sane state of pointing at world + gFocusMgr.setKeyboardFocus(NULL); + + LLAppViewer::instance()->handleLoginComplete(); + + LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); + + display_startup(); + + llassert(LLPathfindingManager::getInstance() != NULL); + LLPathfindingManager::getInstance()->initSystem(); + + gAgentAvatarp->sendHoverHeight(); + + // look for parcels we own + send_places_query(LLUUID::null, + LLUUID::null, + "", + DFQ_AGENT_OWNED, + LLParcel::C_ANY, + ""); + + LLUIUsage::instance().clear(); LLPerfStats::StatsRecorder::setAutotuneInit(); LLLUAmanager::runScriptOnLogin(); - return TRUE; - } + return TRUE; + } - return TRUE; + return TRUE; } // @@ -2434,50 +2434,50 @@ bool idle_startup() void login_show() { - LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; - - // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region - if (gToolBarView) - { - gToolBarView->setVisible(FALSE); - } - - LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); + LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; + + // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region + if (gToolBarView) + { + gToolBarView->setVisible(FALSE); + } + + LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); } // Callback for when login screen is closed. Option 0 = connect, option 1 = quit. void login_callback(S32 option, void *userdata) { - const S32 CONNECT_OPTION = 0; - const S32 QUIT_OPTION = 1; - - if (CONNECT_OPTION == option) - { - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - return; - } - else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION - { - if (!gSavedSettings.getBOOL("RememberPassword")) - { - // turn off the setting and write out to disk - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); - LLUIColorTable::instance().saveUserSettings(); - } - - // Next iteration through main loop should shut down the app cleanly. - LLAppViewer::instance()->userQuit(); - - if (LLAppViewer::instance()->quitRequested()) - { - LLPanelLogin::closePanel(); - } - return; - } - else - { - LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; - } + const S32 CONNECT_OPTION = 0; + const S32 QUIT_OPTION = 1; + + if (CONNECT_OPTION == option) + { + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + return; + } + else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION + { + if (!gSavedSettings.getBOOL("RememberPassword")) + { + // turn off the setting and write out to disk + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); + } + + // Next iteration through main loop should shut down the app cleanly. + LLAppViewer::instance()->userQuit(); + + if (LLAppViewer::instance()->quitRequested()) + { + LLPanelLogin::closePanel(); + } + return; + } + else + { + LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; + } } void release_notes_coro(const std::string url) @@ -2559,35 +2559,35 @@ void show_release_notes_if_required() void show_first_run_dialog() { - LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); + LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); } bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; - LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); - } - - LLPanelLogin::giveFocus(); - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; + LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); + } + + LLPanelLogin::giveFocus(); + return false; } void set_startup_status(const F32 frac, const std::string& string, const std::string& msg) { - gViewerWindow->setProgressPercent(frac*100); - gViewerWindow->setProgressString(string); + gViewerWindow->setProgressPercent(frac*100); + gViewerWindow->setProgressString(string); - gViewerWindow->setProgressMessage(msg); + gViewerWindow->setProgressMessage(msg); } bool login_alert_status(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // Buttons switch( option ) { @@ -2598,222 +2598,222 @@ bool login_alert_status(const LLSD& notification, const LLSD& response) // break; case 2: // Teleport // Restart the login process, starting at our home locaton - LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; default: LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL; } - LLPanelLogin::giveFocus(); - return false; + LLPanelLogin::giveFocus(); + return false; } void use_circuit_callback(void**, S32 result) { - // bail if we're quitting. - if(LLApp::isExiting()) return; - if( !gUseCircuitCallbackCalled ) - { - gUseCircuitCallbackCalled = true; - if (result) - { - // Make sure user knows something bad happened. JC - LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); - } - else - { - gGotUseCircuitCodeAck = true; - } - } + // bail if we're quitting. + if(LLApp::isExiting()) return; + if( !gUseCircuitCallbackCalled ) + { + gUseCircuitCallbackCalled = true; + if (result) + { + // Make sure user knows something bad happened. JC + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else + { + gGotUseCircuitCodeAck = true; + } + } } void register_viewer_callbacks(LLMessageSystem* msg) { - msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); - msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); - msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); - msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); - msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); - msg->setHandlerFunc("SimStats", process_sim_stats); - msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); - msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); - msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); - - msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); - msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); - msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); - msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); - msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); - msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); - - msg->setHandlerFunc("CrossedRegion", process_crossed_region); - msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); - - msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); - msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); - msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); - msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); - - msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); - msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); - msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); - msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); - msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); - msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); - msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); - msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); - msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); - - msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); - msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); - msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); - msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); - msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); - - msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); - msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); - msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); - msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); - msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, - &LLLiveLSLEditor::processScriptRunningReply); - - msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); - - msg->setHandlerFunc("LogoutReply", process_logout_reply); - - //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, - // &LLAgent::processAddModifyAbility); - //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, - // &LLAgent::processRemoveModifyAbility); - msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, - &LLAgent::processAgentDataUpdate); - msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, - &LLAgent::processAgentGroupDataUpdate); - msg->setHandlerFunc("AgentDropGroup", - &LLAgent::processAgentDropGroup); - // land ownership messages - msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, - LLViewerParcelMgr::processParcelOverlay); - msg->setHandlerFuncFast(_PREHASH_ParcelProperties, - LLViewerParcelMgr::processParcelProperties); - msg->setHandlerFunc("ParcelAccessListReply", - LLViewerParcelMgr::processParcelAccessListReply); - msg->setHandlerFunc("ParcelDwellReply", - LLViewerParcelMgr::processParcelDwellReply); - - msg->setHandlerFunc("AvatarPropertiesReply", - &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); - msg->setHandlerFunc("AvatarInterestsReply", - &LLAvatarPropertiesProcessor::processAvatarInterestsReply); - msg->setHandlerFunc("AvatarGroupsReply", - &LLAvatarPropertiesProcessor::processAvatarGroupsReply); - // ratings deprecated - //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, - // LLPanelAvatar::processAvatarStatisticsReply); - msg->setHandlerFunc("AvatarNotesReply", - &LLAvatarPropertiesProcessor::processAvatarNotesReply); - msg->setHandlerFunc("AvatarPicksReply", - &LLAvatarPropertiesProcessor::processAvatarPicksReply); - msg->setHandlerFunc("AvatarClassifiedReply", - &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); - - msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, - LLGroupMgr::processCreateGroupReply); - msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, - LLGroupMgr::processJoinGroupReply); - msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, - LLGroupMgr::processEjectGroupMemberReply); - msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, - LLGroupMgr::processLeaveGroupReply); - msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, - LLGroupMgr::processGroupPropertiesReply); - - // ratings deprecated - // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, - // LLFloaterRate::processReputationIndividualReply); - - msg->setHandlerFunc("ScriptControlChange", - LLAgent::processScriptControlChange ); - - msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); - - msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); - - msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, - LLPanelGroupLandMoney::processGroupAccountSummaryReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, - LLPanelGroupLandMoney::processGroupAccountDetailsReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, - LLPanelGroupLandMoney::processGroupAccountTransactionsReply); - - msg->setHandlerFuncFast(_PREHASH_UserInfoReply, - process_user_info_reply); - - msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); - - msg->setHandlerFunc("TeleportStart", process_teleport_start ); - msg->setHandlerFunc("TeleportProgress", process_teleport_progress); - msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); - msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); - - msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); - - msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, - LLGroupMgr::processGroupMembersReply); - msg->setHandlerFunc("GroupRoleDataReply", - LLGroupMgr::processGroupRoleDataReply); - msg->setHandlerFunc("GroupRoleMembersReply", - LLGroupMgr::processGroupRoleMembersReply); - msg->setHandlerFunc("GroupTitlesReply", - LLGroupMgr::processGroupTitlesReply); - // Special handler as this message is sometimes used for group land. - msg->setHandlerFunc("PlacesReply", process_places_reply); - msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); - - msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); - - msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); - msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); - msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); - - msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); - msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); - msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); - msg->setHandlerFunc("ScriptDialog", process_script_dialog); - msg->setHandlerFunc("LoadURL", process_load_url); - msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); - msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); - - // calling cards - msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); - msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); - msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); - - msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); - - msg->setHandlerFunc("InitiateDownload", process_initiate_download); - msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); + msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); + msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); + msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); + msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); + msg->setHandlerFunc("SimStats", process_sim_stats); + msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); + msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); + msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); + + msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); + msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); + msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); + msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); + msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); + msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); + + msg->setHandlerFunc("CrossedRegion", process_crossed_region); + msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); + + msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); + msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); + msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); + msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); + + msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); + msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); + msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); + msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); + msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); + msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); + msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); + msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); + + msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); + msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); + msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); + msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); + msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); + + msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); + msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); + msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); + msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); + msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, + &LLLiveLSLEditor::processScriptRunningReply); + + msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); + + msg->setHandlerFunc("LogoutReply", process_logout_reply); + + //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, + // &LLAgent::processAddModifyAbility); + //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, + // &LLAgent::processRemoveModifyAbility); + msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, + &LLAgent::processAgentDataUpdate); + msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, + &LLAgent::processAgentGroupDataUpdate); + msg->setHandlerFunc("AgentDropGroup", + &LLAgent::processAgentDropGroup); + // land ownership messages + msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, + LLViewerParcelMgr::processParcelOverlay); + msg->setHandlerFuncFast(_PREHASH_ParcelProperties, + LLViewerParcelMgr::processParcelProperties); + msg->setHandlerFunc("ParcelAccessListReply", + LLViewerParcelMgr::processParcelAccessListReply); + msg->setHandlerFunc("ParcelDwellReply", + LLViewerParcelMgr::processParcelDwellReply); + + msg->setHandlerFunc("AvatarPropertiesReply", + &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); + msg->setHandlerFunc("AvatarInterestsReply", + &LLAvatarPropertiesProcessor::processAvatarInterestsReply); + msg->setHandlerFunc("AvatarGroupsReply", + &LLAvatarPropertiesProcessor::processAvatarGroupsReply); + // ratings deprecated + //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, + // LLPanelAvatar::processAvatarStatisticsReply); + msg->setHandlerFunc("AvatarNotesReply", + &LLAvatarPropertiesProcessor::processAvatarNotesReply); + msg->setHandlerFunc("AvatarPicksReply", + &LLAvatarPropertiesProcessor::processAvatarPicksReply); + msg->setHandlerFunc("AvatarClassifiedReply", + &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); + + msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, + LLGroupMgr::processCreateGroupReply); + msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, + LLGroupMgr::processJoinGroupReply); + msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, + LLGroupMgr::processEjectGroupMemberReply); + msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, + LLGroupMgr::processLeaveGroupReply); + msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, + LLGroupMgr::processGroupPropertiesReply); + + // ratings deprecated + // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, + // LLFloaterRate::processReputationIndividualReply); + + msg->setHandlerFunc("ScriptControlChange", + LLAgent::processScriptControlChange ); + + msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); + + msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); + + msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, + LLPanelGroupLandMoney::processGroupAccountSummaryReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, + LLPanelGroupLandMoney::processGroupAccountDetailsReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, + LLPanelGroupLandMoney::processGroupAccountTransactionsReply); + + msg->setHandlerFuncFast(_PREHASH_UserInfoReply, + process_user_info_reply); + + msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); + + msg->setHandlerFunc("TeleportStart", process_teleport_start ); + msg->setHandlerFunc("TeleportProgress", process_teleport_progress); + msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); + msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); + + msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); + + msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, + LLGroupMgr::processGroupMembersReply); + msg->setHandlerFunc("GroupRoleDataReply", + LLGroupMgr::processGroupRoleDataReply); + msg->setHandlerFunc("GroupRoleMembersReply", + LLGroupMgr::processGroupRoleMembersReply); + msg->setHandlerFunc("GroupTitlesReply", + LLGroupMgr::processGroupTitlesReply); + // Special handler as this message is sometimes used for group land. + msg->setHandlerFunc("PlacesReply", process_places_reply); + msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); + + msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); + + msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); + msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); + msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); + + msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); + msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); + msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); + msg->setHandlerFunc("ScriptDialog", process_script_dialog); + msg->setHandlerFunc("LoadURL", process_load_url); + msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); + msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); + + // calling cards + msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); + msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); + msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); + + msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); + + msg->setHandlerFunc("InitiateDownload", process_initiate_download); + msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); msg->setHandlerFunc("GenericMessage", process_generic_message); msg->setHandlerFunc("GenericStreamingMessage", process_generic_streaming_message); msg->setHandlerFunc("LargeGenericMessage", process_large_generic_message); - msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); + msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32) { - // nothing + // nothing } const S32 OPT_CLOSED_WINDOW = -1; @@ -2821,27 +2821,27 @@ const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; const S32 OPT_TRUST_CERT = 0; const S32 OPT_CANCEL_TRUST = 1; - + bool callback_choose_gender(const LLSD& notification, const LLSD& response) { - - // These defaults are returned from the server on login. They are set in login.xml. - // If no default is returned from the server, they are retrieved from settings.xml. - - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case OPT_MALE: - LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); - break; - + + // These defaults are returned from the server on login. They are set in login.xml. + // If no default is returned from the server, they are retrieved from settings.xml. + + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_MALE: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); + break; + case OPT_FEMALE: case OPT_CLOSED_WINDOW: default: - LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); - break; - } - return false; + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); + break; + } + return false; } std::string get_screen_filename(const std::string& pattern) @@ -2873,66 +2873,66 @@ std::string LLStartUp::getScreenHomeFilename() //static void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, - const std::string& gender_name ) + const std::string& gender_name ) { - LL_DEBUGS() << "starting" << LL_ENDL; - - // Not going through the processAgentInitialWearables path, so need to set this here. - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - // Initiate creation of COF, since we're also bypassing that. - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); - - ESex gender; - if (gender_name == "male") - { - LL_DEBUGS() << "male" << LL_ENDL; - gender = SEX_MALE; - } - else - { - LL_DEBUGS() << "female" << LL_ENDL; - gender = SEX_FEMALE; - } - - if (!isAgentAvatarValid()) - { - LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; - return; - } - - gAgentAvatarp->setSex(gender); - - // try to find the requested outfit or folder - - // -- check for existing outfit in My Outfits - bool do_copy = false; - LLUUID cat_id = findDescendentCategoryIDByName( - gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), - outfit_folder_name); - - // -- check for existing folder in Library - if (cat_id.isNull()) - { - cat_id = findDescendentCategoryIDByName( - gInventory.getLibraryRootFolderID(), - outfit_folder_name); - if (!cat_id.isNull()) - { - do_copy = true; - } - } - - if (cat_id.isNull()) - { - // -- final fallback: create standard wearables - LL_DEBUGS() << "standard wearables" << LL_ENDL; - gAgentWearables.createStandardWearables(); - } - else - { - bool do_append = false; - LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); - // Need to fetch cof contents before we can wear. + LL_DEBUGS() << "starting" << LL_ENDL; + + // Not going through the processAgentInitialWearables path, so need to set this here. + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + // Initiate creation of COF, since we're also bypassing that. + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + + ESex gender; + if (gender_name == "male") + { + LL_DEBUGS() << "male" << LL_ENDL; + gender = SEX_MALE; + } + else + { + LL_DEBUGS() << "female" << LL_ENDL; + gender = SEX_FEMALE; + } + + if (!isAgentAvatarValid()) + { + LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; + return; + } + + gAgentAvatarp->setSex(gender); + + // try to find the requested outfit or folder + + // -- check for existing outfit in My Outfits + bool do_copy = false; + LLUUID cat_id = findDescendentCategoryIDByName( + gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), + outfit_folder_name); + + // -- check for existing folder in Library + if (cat_id.isNull()) + { + cat_id = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + if (!cat_id.isNull()) + { + do_copy = true; + } + } + + if (cat_id.isNull()) + { + // -- final fallback: create standard wearables + LL_DEBUGS() << "standard wearables" << LL_ENDL; + gAgentWearables.createStandardWearables(); + } + else + { + bool do_append = false; + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + // Need to fetch cof contents before we can wear. if (do_copy) { callAfterCOFFetch(boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); @@ -2941,16 +2941,16 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, { callAfterCategoryLinksFetch(cat_id, boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); } - LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; - } + LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; + } - gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); } std::string& LLStartUp::getInitialOutfitName() { - return sInitialOutfit; + return sInitialOutfit; } std::string LLStartUp::getUserId() @@ -2966,8 +2966,8 @@ std::string LLStartUp::getUserId() // frees the bitmap void release_start_screen() { - LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; - gStartTexture = NULL; + LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; + gStartTexture = NULL; } @@ -2975,77 +2975,77 @@ void release_start_screen() std::string LLStartUp::startupStateToString(EStartupState state) { #define RTNENUM(E) case E: return #E - switch(state){ - RTNENUM( STATE_FIRST ); - RTNENUM( STATE_BROWSER_INIT ); - RTNENUM( STATE_LOGIN_SHOW ); - RTNENUM( STATE_LOGIN_WAIT ); - RTNENUM( STATE_LOGIN_CLEANUP ); - RTNENUM( STATE_LOGIN_AUTH_INIT ); - RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); - RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); - RTNENUM( STATE_WORLD_INIT ); - RTNENUM( STATE_MULTIMEDIA_INIT ); - RTNENUM( STATE_FONT_INIT ); - RTNENUM( STATE_SEED_GRANTED_WAIT ); - RTNENUM( STATE_SEED_CAP_GRANTED ); - RTNENUM( STATE_WORLD_WAIT ); - RTNENUM( STATE_AGENT_SEND ); - RTNENUM( STATE_AGENT_WAIT ); - RTNENUM( STATE_INVENTORY_SEND ); + switch(state){ + RTNENUM( STATE_FIRST ); + RTNENUM( STATE_BROWSER_INIT ); + RTNENUM( STATE_LOGIN_SHOW ); + RTNENUM( STATE_LOGIN_WAIT ); + RTNENUM( STATE_LOGIN_CLEANUP ); + RTNENUM( STATE_LOGIN_AUTH_INIT ); + RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); + RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); + RTNENUM( STATE_WORLD_INIT ); + RTNENUM( STATE_MULTIMEDIA_INIT ); + RTNENUM( STATE_FONT_INIT ); + RTNENUM( STATE_SEED_GRANTED_WAIT ); + RTNENUM( STATE_SEED_CAP_GRANTED ); + RTNENUM( STATE_WORLD_WAIT ); + RTNENUM( STATE_AGENT_SEND ); + RTNENUM( STATE_AGENT_WAIT ); + RTNENUM( STATE_INVENTORY_SEND ); RTNENUM(STATE_INVENTORY_CALLBACKS ); - RTNENUM( STATE_MISC ); - RTNENUM( STATE_PRECACHE ); - RTNENUM( STATE_WEARABLES_WAIT ); - RTNENUM( STATE_CLEANUP ); - RTNENUM( STATE_STARTED ); - default: - return llformat("(state #%d)", state); - } + RTNENUM( STATE_MISC ); + RTNENUM( STATE_PRECACHE ); + RTNENUM( STATE_WEARABLES_WAIT ); + RTNENUM( STATE_CLEANUP ); + RTNENUM( STATE_STARTED ); + default: + return llformat("(state #%d)", state); + } #undef RTNENUM } // static void LLStartUp::setStartupState( EStartupState state ) { - LL_INFOS("AppInit") << "Startup state changing from " << - getStartupStateString() << " to " << - startupStateToString(state) << LL_ENDL; + LL_INFOS("AppInit") << "Startup state changing from " << + getStartupStateString() << " to " << + startupStateToString(state) << LL_ENDL; - getPhases().stopPhase(getStartupStateString()); - gStartupState = state; - getPhases().startPhase(getStartupStateString()); + getPhases().stopPhase(getStartupStateString()); + gStartupState = state; + getPhases().startPhase(getStartupStateString()); - postStartupState(); + postStartupState(); } void LLStartUp::postStartupState() { - LLSD stateInfo; - stateInfo["str"] = getStartupStateString(); - stateInfo["enum"] = gStartupState; - sStateWatcher->post(stateInfo); - gDebugInfo["StartupState"] = getStartupStateString(); + LLSD stateInfo; + stateInfo["str"] = getStartupStateString(); + stateInfo["enum"] = gStartupState; + sStateWatcher->post(stateInfo); + gDebugInfo["StartupState"] = getStartupStateString(); } void reset_login() { - gAgentWearables.cleanup(); - gAgentCamera.cleanup(); - gAgent.cleanup(); + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + gAgent.cleanup(); gSky.cleanup(); // mVOSkyp is an inworld object. - LLWorld::getInstance()->resetClass(); + LLWorld::getInstance()->resetClass(); - if ( gViewerWindow ) - { // Hide menus and normal buttons - gViewerWindow->setNormalControlsVisible( FALSE ); - gLoginMenuBarView->setVisible( TRUE ); - gLoginMenuBarView->setEnabled( TRUE ); - } + if ( gViewerWindow ) + { // Hide menus and normal buttons + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + } - // Hide any other stuff - LLFloaterReg::hideVisibleInstances(); + // Hide any other stuff + LLFloaterReg::hideVisibleInstances(); LLStartUp::setStartupState( STATE_BROWSER_INIT ); if (LLVoiceClient::instanceExists()) @@ -3065,117 +3065,117 @@ void reset_login() // early, before the login screen). JC void LLStartUp::multimediaInit() { - LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingMultimedia"); - set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); + LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingMultimedia"); + set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); } void LLStartUp::fontInit() { - LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingFonts"); - set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); + LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingFonts"); + set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); - LLFontGL::loadDefaultFonts(); + LLFontGL::loadDefaultFonts(); } void LLStartUp::initNameCache() { - // Can be called multiple times - if ( gCacheName ) return; - - gCacheName = new LLCacheName(gMessageSystem); - gCacheName->addObserver(&callback_cache_name); - gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); - gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); - gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); - // Load stored cache if possible - LLAppViewer::instance()->loadNameCache(); - - // Start cache in not-running state until we figure out if we have - // capabilities for display name lookup - LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); - cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); - cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); - cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + // Can be called multiple times + if ( gCacheName ) return; + + gCacheName = new LLCacheName(gMessageSystem); + gCacheName->addObserver(&callback_cache_name); + gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); + gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); + gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); + // Load stored cache if possible + LLAppViewer::instance()->loadNameCache(); + + // Start cache in not-running state until we figure out if we have + // capabilities for display name lookup + LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); + cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); + cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); + cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); } void LLStartUp::initExperiences() -{ +{ // Should trigger loading the cache. LLExperienceCache::instance().setCapabilityQuery( boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); - LLExperienceLog::instance().initialize(); + LLExperienceLog::instance().initialize(); } void LLStartUp::cleanupNameCache() { - delete gCacheName; - gCacheName = NULL; + delete gCacheName; + gCacheName = NULL; } bool LLStartUp::dispatchURL() { - // ok, if we've gotten this far and have a startup URL + // ok, if we've gotten this far and have a startup URL if (!getStartSLURL().isValid()) - { - return false; - } + { + return false; + } if(getStartSLURL().getType() != LLSLURL::APP) - { - - // If we started with a location, but we're already - // at that location, don't pop dialogs open. - LLVector3 pos = gAgent.getPositionAgent(); - LLVector3 slurlpos = getStartSLURL().getPosition(); - F32 dx = pos.mV[VX] - slurlpos.mV[VX]; - F32 dy = pos.mV[VY] - slurlpos.mV[VY]; - const F32 SLOP = 2.f; // meters - - if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() - || (dx*dx > SLOP*SLOP) - || (dy*dy > SLOP*SLOP) ) - { - LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, - NULL, false); - } - return true; - } - return false; + { + + // If we started with a location, but we're already + // at that location, don't pop dialogs open. + LLVector3 pos = gAgent.getPositionAgent(); + LLVector3 slurlpos = getStartSLURL().getPosition(); + F32 dx = pos.mV[VX] - slurlpos.mV[VX]; + F32 dy = pos.mV[VY] - slurlpos.mV[VY]; + const F32 SLOP = 2.f; // meters + + if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() + || (dx*dx > SLOP*SLOP) + || (dy*dy > SLOP*SLOP) ) + { + LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, + NULL, false); + } + return true; + } + return false; } -void LLStartUp::setStartSLURL(const LLSLURL& slurl) +void LLStartUp::setStartSLURL(const LLSLURL& slurl) { - LL_DEBUGS("AppInit")<<slurl.asString()<<LL_ENDL; - - if ( slurl.isSpatial() ) - { - std::string new_start = slurl.getSLURLString(); - LL_DEBUGS("AppInit")<<new_start<<LL_ENDL; - sStartSLURL = slurl; - LLPanelLogin::onUpdateStartSLURL(slurl); // updates grid if needed - - // remember that this is where we wanted to log in...if the login fails, - // the next attempt will default to the same place. - gSavedSettings.setString("NextLoginLocation", new_start); - // following a successful login, this is cleared - // and the default reverts to LoginLocation - } - else - { - LL_WARNS("AppInit")<<"Invalid start SLURL (ignored): "<<slurl.asString()<<LL_ENDL; - } + LL_DEBUGS("AppInit")<<slurl.asString()<<LL_ENDL; + + if ( slurl.isSpatial() ) + { + std::string new_start = slurl.getSLURLString(); + LL_DEBUGS("AppInit")<<new_start<<LL_ENDL; + sStartSLURL = slurl; + LLPanelLogin::onUpdateStartSLURL(slurl); // updates grid if needed + + // remember that this is where we wanted to log in...if the login fails, + // the next attempt will default to the same place. + gSavedSettings.setString("NextLoginLocation", new_start); + // following a successful login, this is cleared + // and the default reverts to LoginLocation + } + else + { + LL_WARNS("AppInit")<<"Invalid start SLURL (ignored): "<<slurl.asString()<<LL_ENDL; + } } // static LLSLURL& LLStartUp::getStartSLURL() { - return sStartSLURL; -} + return sStartSLURL; +} /** * Read all proxy configuration settings and set up both the HTTP proxy and @@ -3188,680 +3188,680 @@ LLSLURL& LLStartUp::getStartSLURL() */ bool LLStartUp::startLLProxy() { - bool proxy_ok = true; - std::string httpProxyType = gSavedSettings.getString("HttpProxyType"); - - // Set up SOCKS proxy (if needed) - if (gSavedSettings.getBOOL("Socks5ProxyEnabled")) - { - // Determine and update LLProxy with the saved authentication system - std::string auth_type = gSavedSettings.getString("Socks5AuthType"); - - if (auth_type.compare("UserPass") == 0) - { - LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); - std::string socks_user = socks_cred->getIdentifier()["username"].asString(); - std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); - - bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); - - if (!ok) - { - LLNotificationsUtil::add("SOCKS_BAD_CREDS"); - proxy_ok = false; - } - } - else if (auth_type.compare("None") == 0) - { - LLProxy::getInstance()->setAuthNone(); - } - else - { - LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; - - // Unknown or missing setting. - gSavedSettings.setString("Socks5AuthType", "None"); - - // Clear the SOCKS credentials. - LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5"); - gSecAPIHandler->deleteCredential(socks_cred); - - LLProxy::getInstance()->setAuthNone(); - } - - if (proxy_ok) - { - // Start the proxy and check for errors - // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. - LLHost socks_host; - socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); - socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); - int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); - - if (status != SOCKS_OK) - { - LLSD subs; - subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); - subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); - - std::string error_string; - - switch(status) - { - case SOCKS_CONNECT_ERROR: // TCP Fail - error_string = "SOCKS_CONNECT_ERROR"; - break; - - case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection - error_string = "SOCKS_NOT_PERMITTED"; - break; - - case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server - error_string = "SOCKS_NOT_ACCEPTABLE"; - break; - - case SOCKS_AUTH_FAIL: // Authentication failed - error_string = "SOCKS_AUTH_FAIL"; - break; - - case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed - error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; - break; - - case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server - error_string = "SOCKS_HOST_CONNECT_FAILED"; - break; - - case SOCKS_INVALID_HOST: // Improperly formatted host address or port. - error_string = "SOCKS_INVALID_HOST"; - break; - - default: - error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, - LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; - break; - } - - LLNotificationsUtil::add(error_string, subs); - proxy_ok = false; - } - } - } - else - { - LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up - } - - if (proxy_ok) - { - // Determine the HTTP proxy type (if any) - if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) - { - LLHost http_host; - http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); - http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); - if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) - { - LLSD subs; - subs["HOST"] = http_host.getIPString(); - subs["PORT"] = (S32)http_host.getPort(); - LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); - proxy_ok = false; - } - } - else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) - { - LLHost socks_host; - socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); - socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); - if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) - { - LLSD subs; - subs["HOST"] = socks_host.getIPString(); - subs["PORT"] = (S32)socks_host.getPort(); - LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); - proxy_ok = false; - } - } - else if (httpProxyType.compare("None") == 0) - { - LLProxy::getInstance()->disableHTTPProxy(); - } - else - { - LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; - - // Set the missing or wrong configuration back to something valid. - gSavedSettings.setString("HttpProxyType", "None"); - LLProxy::getInstance()->disableHTTPProxy(); - - // Leave proxy_ok alone, since this isn't necessarily fatal. - } - } - - return proxy_ok; + bool proxy_ok = true; + std::string httpProxyType = gSavedSettings.getString("HttpProxyType"); + + // Set up SOCKS proxy (if needed) + if (gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + // Determine and update LLProxy with the saved authentication system + std::string auth_type = gSavedSettings.getString("Socks5AuthType"); + + if (auth_type.compare("UserPass") == 0) + { + LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + std::string socks_user = socks_cred->getIdentifier()["username"].asString(); + std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); + + bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); + + if (!ok) + { + LLNotificationsUtil::add("SOCKS_BAD_CREDS"); + proxy_ok = false; + } + } + else if (auth_type.compare("None") == 0) + { + LLProxy::getInstance()->setAuthNone(); + } + else + { + LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; + + // Unknown or missing setting. + gSavedSettings.setString("Socks5AuthType", "None"); + + // Clear the SOCKS credentials. + LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + + LLProxy::getInstance()->setAuthNone(); + } + + if (proxy_ok) + { + // Start the proxy and check for errors + // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. + LLHost socks_host; + socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); + + if (status != SOCKS_OK) + { + LLSD subs; + subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); + subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); + + std::string error_string; + + switch(status) + { + case SOCKS_CONNECT_ERROR: // TCP Fail + error_string = "SOCKS_CONNECT_ERROR"; + break; + + case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection + error_string = "SOCKS_NOT_PERMITTED"; + break; + + case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server + error_string = "SOCKS_NOT_ACCEPTABLE"; + break; + + case SOCKS_AUTH_FAIL: // Authentication failed + error_string = "SOCKS_AUTH_FAIL"; + break; + + case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed + error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; + break; + + case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server + error_string = "SOCKS_HOST_CONNECT_FAILED"; + break; + + case SOCKS_INVALID_HOST: // Improperly formatted host address or port. + error_string = "SOCKS_INVALID_HOST"; + break; + + default: + error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, + LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; + break; + } + + LLNotificationsUtil::add(error_string, subs); + proxy_ok = false; + } + } + } + else + { + LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up + } + + if (proxy_ok) + { + // Determine the HTTP proxy type (if any) + if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) + { + LLHost http_host; + http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); + http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); + if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) + { + LLSD subs; + subs["HOST"] = http_host.getIPString(); + subs["PORT"] = (S32)http_host.getPort(); + LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); + proxy_ok = false; + } + } + else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + LLHost socks_host; + socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) + { + LLSD subs; + subs["HOST"] = socks_host.getIPString(); + subs["PORT"] = (S32)socks_host.getPort(); + LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); + proxy_ok = false; + } + } + else if (httpProxyType.compare("None") == 0) + { + LLProxy::getInstance()->disableHTTPProxy(); + } + else + { + LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; + + // Set the missing or wrong configuration back to something valid. + gSavedSettings.setString("HttpProxyType", "None"); + LLProxy::getInstance()->disableHTTPProxy(); + + // Leave proxy_ok alone, since this isn't necessarily fatal. + } + } + + return proxy_ok; } bool login_alert_done(const LLSD& notification, const LLSD& response) { - LLPanelLogin::giveFocus(); - return false; + LLPanelLogin::giveFocus(); + return false; } -// parse the certificate information into args for the +// parse the certificate information into args for the // certificate notifications LLSD transform_cert_args(LLPointer<LLCertificate> cert) { - LLSD args = LLSD::emptyMap(); - std::string value; - LLSD cert_info; - cert->getLLSD(cert_info); - // convert all of the elements in the cert into - // args for the xml dialog, so we have flexability to - // display various parts of the cert by only modifying - // the cert alert dialog xml. - for(LLSD::map_iterator iter = cert_info.beginMap(); - iter != cert_info.endMap(); - iter++) - { - // key usage and extended key usage - // are actually arrays, and we want to format them as comma separated - // strings, so special case those. - LLSDSerialize::toXML(cert_info[iter->first], std::cout); - if((iter->first == std::string(CERT_KEY_USAGE)) || - (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) - { - value = ""; - LLSD usage = cert_info[iter->first]; - for (LLSD::array_iterator usage_iter = usage.beginArray(); - usage_iter != usage.endArray(); - usage_iter++) - { - - if(usage_iter != usage.beginArray()) - { - value += ", "; - } - - value += (*usage_iter).asString(); - } - - } - else - { - value = iter->second.asString(); - } - - std::string name = iter->first; - std::transform(name.begin(), name.end(), name.begin(), - (int(*)(int))toupper); - args[name.c_str()] = value; - } - return args; + LLSD args = LLSD::emptyMap(); + std::string value; + LLSD cert_info; + cert->getLLSD(cert_info); + // convert all of the elements in the cert into + // args for the xml dialog, so we have flexability to + // display various parts of the cert by only modifying + // the cert alert dialog xml. + for(LLSD::map_iterator iter = cert_info.beginMap(); + iter != cert_info.endMap(); + iter++) + { + // key usage and extended key usage + // are actually arrays, and we want to format them as comma separated + // strings, so special case those. + LLSDSerialize::toXML(cert_info[iter->first], std::cout); + if((iter->first == std::string(CERT_KEY_USAGE)) || + (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) + { + value = ""; + LLSD usage = cert_info[iter->first]; + for (LLSD::array_iterator usage_iter = usage.beginArray(); + usage_iter != usage.endArray(); + usage_iter++) + { + + if(usage_iter != usage.beginArray()) + { + value += ", "; + } + + value += (*usage_iter).asString(); + } + + } + else + { + value = iter->second.asString(); + } + + std::string name = iter->first; + std::transform(name.begin(), name.end(), name.begin(), + (int(*)(int))toupper); + args[name.c_str()] = value; + } + return args; } // when we handle a cert error, give focus back to the login panel void general_cert_done(const LLSD& notification, const LLSD& response) { - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - LLPanelLogin::giveFocus(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + LLPanelLogin::giveFocus(); } // check to see if the user wants to trust the cert. -// if they do, add it to the cert store and +// if they do, add it to the cert store and void trust_cert_done(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case OPT_TRUST_CERT: - { - LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); - LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); - store->add(cert); - store->save(); - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - break; - } - case OPT_CANCEL_TRUST: - reset_login(); - gSavedSettings.setBOOL("AutoLogin", FALSE); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - default: - LLPanelLogin::giveFocus(); - break; - } + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_TRUST_CERT: + { + LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); + LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); + store->add(cert); + store->save(); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + break; + } + case OPT_CANCEL_TRUST: + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + default: + LLPanelLogin::giveFocus(); + break; + } } void apply_udp_blacklist(const std::string& csv) { - std::string::size_type start = 0; - std::string::size_type comma = 0; - do - { - comma = csv.find(",", start); - if (comma == std::string::npos) - { - comma = csv.length(); - } - std::string item(csv, start, comma-start); - - LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; - gMessageSystem->banUdpMessage(item); - - start = comma + 1; - - } - while(comma < csv.length()); - + std::string::size_type start = 0; + std::string::size_type comma = 0; + do + { + comma = csv.find(",", start); + if (comma == std::string::npos) + { + comma = csv.length(); + } + std::string item(csv, start, comma-start); + + LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; + gMessageSystem->banUdpMessage(item); + + start = comma + 1; + + } + while(comma < csv.length()); + } void on_benefits_failed_callback(const LLSD& notification, const LLSD& response) { - LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; + LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; } bool init_benefits(LLSD& response) { - bool succ = true; - - std::string package_name = response["account_type"].asString(); - const LLSD& benefits_sd = response["account_level_benefits"]; - if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || - !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) - { - succ = false; - } - else - { - LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; - } - const LLSD& packages_sd = response["premium_packages"]; - for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); - package_iter != packages_sd.endMap(); - ++package_iter) - { - std::string package_name = package_iter->first; - const LLSD& benefits_sd = package_iter->second["benefits"]; - if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) - { - LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; - } - else - { - LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; - succ = false; - } - } - - if (!LLAgentBenefitsMgr::has("Base")) - { - LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; - succ = false; - } - if (!LLAgentBenefitsMgr::has("Premium")) - { - LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; - succ = false; - } - - return succ; + bool succ = true; + + std::string package_name = response["account_type"].asString(); + const LLSD& benefits_sd = response["account_level_benefits"]; + if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || + !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) + { + succ = false; + } + else + { + LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; + } + const LLSD& packages_sd = response["premium_packages"]; + for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); + package_iter != packages_sd.endMap(); + ++package_iter) + { + std::string package_name = package_iter->first; + const LLSD& benefits_sd = package_iter->second["benefits"]; + if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) + { + LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; + } + else + { + LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; + succ = false; + } + } + + if (!LLAgentBenefitsMgr::has("Base")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; + succ = false; + } + if (!LLAgentBenefitsMgr::has("Premium")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; + succ = false; + } + + return succ; } bool process_login_success_response() { - LLSD response = LLLoginInstance::getInstance()->getResponse(); - - mBenefitsSuccessfullyInit = init_benefits(response); - - std::string text(response["udp_blacklist"]); - if(!text.empty()) - { - apply_udp_blacklist(text); - } - - // unpack login data needed by the application - text = response["agent_id"].asString(); - if(!text.empty()) gAgentID.set(text); - gDebugInfo["AgentID"] = text; - - LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); - LLPerfStats::StatsRecorder::setFocusAv(gAgentID); - - // Agent id needed for parcel info request in LLUrlEntryParcel - // to resolve parcel name. - LLUrlEntryParcel::setAgentID(gAgentID); - - text = response["session_id"].asString(); - if(!text.empty()) gAgentSessionID.set(text); - gDebugInfo["SessionID"] = text; - - // Session id needed for parcel info request in LLUrlEntryParcel - // to resolve parcel name. - LLUrlEntryParcel::setSessionID(gAgentSessionID); - - text = response["secure_session_id"].asString(); - if(!text.empty()) gAgent.mSecureSessionID.set(text); - - // if the response contains a display name, use that, - // otherwise if the response contains a first and/or last name, - // use those. Otherwise use the credential identifier - - gDisplayName = ""; - if (response.has("display_name")) - { - gDisplayName.assign(response["display_name"].asString()); - if(!gDisplayName.empty()) - { - // Remove quotes from string. Login.cgi sends these to force - // names that look like numbers into strings. - LLStringUtil::replaceChar(gDisplayName, '"', ' '); - LLStringUtil::trim(gDisplayName); - } - } - std::string first_name; - if(response.has("first_name")) - { - first_name = response["first_name"].asString(); - LLStringUtil::replaceChar(first_name, '"', ' '); - LLStringUtil::trim(first_name); - gAgentUsername = first_name; - } - - if(response.has("last_name") && !gAgentUsername.empty()) - { - std::string last_name = response["last_name"].asString(); - if (last_name != "Resident") - { - LLStringUtil::replaceChar(last_name, '"', ' '); - LLStringUtil::trim(last_name); - gAgentUsername = gAgentUsername + " " + last_name; - } - } - - if(gDisplayName.empty()) - { - if(response.has("first_name")) - { - gDisplayName.assign(response["first_name"].asString()); - LLStringUtil::replaceChar(gDisplayName, '"', ' '); - LLStringUtil::trim(gDisplayName); - } - if(response.has("last_name")) - { - text.assign(response["last_name"].asString()); - LLStringUtil::replaceChar(text, '"', ' '); - LLStringUtil::trim(text); - if(!gDisplayName.empty()) - { - gDisplayName += " "; - } - gDisplayName += text; - } - } - - if(gDisplayName.empty()) - { - gDisplayName.assign(gUserCredential->asString()); - } - - // this is their actual ability to access content - text = response["agent_access_max"].asString(); - if (!text.empty()) - { - // agent_access can be 'A', 'M', and 'PG'. - gAgent.setMaturity(text[0]); - } - - // this is the value of their preference setting for that content - // which will always be <= agent_access_max - text = response["agent_region_access"].asString(); - if (!text.empty()) - { - U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); - - gSavedSettings.setU32("PreferredMaturity", preferredMaturity); - } - - text = response["start_location"].asString(); - if(!text.empty()) - { - gAgentStartLocation.assign(text); - } - - text = response["circuit_code"].asString(); - if(!text.empty()) - { - gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); - } - std::string sim_ip_str = response["sim_ip"]; - std::string sim_port_str = response["sim_port"]; - if(!sim_ip_str.empty() && !sim_port_str.empty()) - { - U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); - gFirstSim.set(sim_ip_str, sim_port); - if (gFirstSim.isOk()) - { - gMessageSystem->enableCircuit(gFirstSim, TRUE); - } - } - std::string region_x_str = response["region_x"]; - std::string region_y_str = response["region_y"]; - if(!region_x_str.empty() && !region_y_str.empty()) - { - U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); - U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); - gFirstSimHandle = to_region_handle(region_x, region_y); - } - - const std::string look_at_str = response["look_at"]; - if (!look_at_str.empty()) - { - size_t len = look_at_str.size(); - LLMemoryStream mstr((U8*)look_at_str.c_str(), len); - LLSD sd = LLSDSerialize::fromNotation(mstr, len); - gAgentStartLookAt = ll_vector3_from_sd(sd); - } - - text = response["seed_capability"].asString(); - if (!text.empty()) gFirstSimSeedCap = text; - - text = response["seconds_since_epoch"].asString(); - if(!text.empty()) - { - U32 server_utc_time = strtoul(text.c_str(), NULL, 10); - if(server_utc_time) - { - time_t now = time(NULL); - gUTCOffset = (server_utc_time - now); - - // Print server timestamp - LLSD substitution; - substitution["datetime"] = (S32)server_utc_time; - std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; - LLStringUtil::format(timeStr, substitution); - LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; - } - } - - // this is the base used to construct help URLs - text = response["help_url_format"].asString(); - if (!text.empty()) - { - // replace the default help URL format - gSavedSettings.setString("HelpURLFormat",text); - } - - std::string home_location = response["home"]; - if(!home_location.empty()) - { - size_t len = home_location.size(); - LLMemoryStream mstr((U8*)home_location.c_str(), len); - LLSD sd = LLSDSerialize::fromNotation(mstr, len); - S32 region_x = sd["region_handle"][0].asInteger(); - S32 region_y = sd["region_handle"][1].asInteger(); - U64 region_handle = to_region_handle(region_x, region_y); - LLVector3 position = ll_vector3_from_sd(sd["position"]); - gAgent.setHomePosRegion(region_handle, position); - } - - gAgent.mMOTD.assign(response["message"]); - - // Options... - // Each 'option' is an array of submaps. - // It appears that we only ever use the first element of the array. - LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; - if(inv_root_folder_id.notNull()) - { - gInventory.setRootFolderID(inv_root_folder_id); - //gInventory.mock(gAgent.getInventoryRootID()); - } - - LLSD login_flags = response["login-flags"][0]; - if(login_flags.size()) - { - std::string flag = login_flags["ever_logged_in"]; - if(!flag.empty()) - { - gAgent.setFirstLogin(flag == "N"); - } - - /* Flag is currently ignored by the viewer. - flag = login_flags["stipend_since_login"]; - if(flag == "Y") - { - stipend_since_login = true; - } - */ - - flag = login_flags["gendered"].asString(); - if(flag == "Y") - { - // We don't care about this flag anymore; now base whether - // outfit is chosen on COF contents, initial outfit - // requested and available, etc. - - //gAgent.setGenderChosen(TRUE); - } - - bool pacific_daylight_time = false; - flag = login_flags["daylight_savings"].asString(); - if(flag == "Y") - { - pacific_daylight_time = (flag == "Y"); - } - - //setup map of datetime strings to codes and slt & local time offset from utc - LLStringOps::setupDatetimeInfo(pacific_daylight_time); - } - - // set up the voice configuration. Ultimately, we should pass this up as part of each voice - // channel if we need to move to multiple voice servers per grid. - LLSD voice_config_info = response["voice-config"]; - if(voice_config_info.has("VoiceServerType")) - { - gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); - } - - // Request the map server url - std::string map_server_url = response["map-server-url"]; - if(!map_server_url.empty()) - { - // We got an answer from the grid -> use that for map for the current session - gSavedSettings.setString("CurrentMapServerURL", map_server_url); - LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; - } - else - { - // No answer from the grid -> use the default setting for current session - map_server_url = gSavedSettings.getString("MapServerURL"); - gSavedSettings.setString("CurrentMapServerURL", map_server_url); - LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; - } - - // Default male and female avatars allowing the user to choose their avatar on first login. - // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard - // "new ruth." Not to be confused with 'initial-outfit' below - LLSD newuser_config = response["newuser-config"][0]; - if(newuser_config.has("DefaultFemaleAvatar")) - { - gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); - } - if(newuser_config.has("DefaultMaleAvatar")) - { - gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); - } - - // Initial outfit for the user. - LLSD initial_outfit = response["initial-outfit"][0]; - if(initial_outfit.size()) - { - std::string flag = initial_outfit["folder_name"]; - if(!flag.empty()) - { - // Initial outfit is a folder in your inventory, - // must be an exact folder-name match. - sInitialOutfit = flag; - } - - flag = initial_outfit["gender"].asString(); - if(!flag.empty()) - { - sInitialOutfitGender = flag; - } - } - - std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); - if (!fake_initial_outfit_name.empty()) - { - gAgent.setFirstLogin(true); - sInitialOutfit = fake_initial_outfit_name; - if (sInitialOutfitGender.empty()) - { - sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. - } - - LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; - } - - // set the location of the Agent Appearance service, from which we can request - // avatar baked textures if they are supported by the current region - std::string agent_appearance_url = response["agent_appearance_service"]; - if (!agent_appearance_url.empty()) - { - LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); - } - - // Set the location of the snapshot sharing config endpoint - std::string snapshot_config_url = response["snapshot_config_url"]; - if(!snapshot_config_url.empty()) - { - gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); - } - - // Start the process of fetching the OpenID session cookie for this user login - std::string openid_url = response["openid_url"]; - if(!openid_url.empty()) - { - std::string openid_token = response["openid_token"]; - LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); - } - - - // Only save mfa_hash for future logins if the user wants their info remembered. - if(response.has("mfa_hash") + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + mBenefitsSuccessfullyInit = init_benefits(response); + + std::string text(response["udp_blacklist"]); + if(!text.empty()) + { + apply_udp_blacklist(text); + } + + // unpack login data needed by the application + text = response["agent_id"].asString(); + if(!text.empty()) gAgentID.set(text); + gDebugInfo["AgentID"] = text; + + LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); + LLPerfStats::StatsRecorder::setFocusAv(gAgentID); + + // Agent id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setAgentID(gAgentID); + + text = response["session_id"].asString(); + if(!text.empty()) gAgentSessionID.set(text); + gDebugInfo["SessionID"] = text; + + // Session id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setSessionID(gAgentSessionID); + + text = response["secure_session_id"].asString(); + if(!text.empty()) gAgent.mSecureSessionID.set(text); + + // if the response contains a display name, use that, + // otherwise if the response contains a first and/or last name, + // use those. Otherwise use the credential identifier + + gDisplayName = ""; + if (response.has("display_name")) + { + gDisplayName.assign(response["display_name"].asString()); + if(!gDisplayName.empty()) + { + // Remove quotes from string. Login.cgi sends these to force + // names that look like numbers into strings. + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + } + std::string first_name; + if(response.has("first_name")) + { + first_name = response["first_name"].asString(); + LLStringUtil::replaceChar(first_name, '"', ' '); + LLStringUtil::trim(first_name); + gAgentUsername = first_name; + } + + if(response.has("last_name") && !gAgentUsername.empty()) + { + std::string last_name = response["last_name"].asString(); + if (last_name != "Resident") + { + LLStringUtil::replaceChar(last_name, '"', ' '); + LLStringUtil::trim(last_name); + gAgentUsername = gAgentUsername + " " + last_name; + } + } + + if(gDisplayName.empty()) + { + if(response.has("first_name")) + { + gDisplayName.assign(response["first_name"].asString()); + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + if(response.has("last_name")) + { + text.assign(response["last_name"].asString()); + LLStringUtil::replaceChar(text, '"', ' '); + LLStringUtil::trim(text); + if(!gDisplayName.empty()) + { + gDisplayName += " "; + } + gDisplayName += text; + } + } + + if(gDisplayName.empty()) + { + gDisplayName.assign(gUserCredential->asString()); + } + + // this is their actual ability to access content + text = response["agent_access_max"].asString(); + if (!text.empty()) + { + // agent_access can be 'A', 'M', and 'PG'. + gAgent.setMaturity(text[0]); + } + + // this is the value of their preference setting for that content + // which will always be <= agent_access_max + text = response["agent_region_access"].asString(); + if (!text.empty()) + { + U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); + + gSavedSettings.setU32("PreferredMaturity", preferredMaturity); + } + + text = response["start_location"].asString(); + if(!text.empty()) + { + gAgentStartLocation.assign(text); + } + + text = response["circuit_code"].asString(); + if(!text.empty()) + { + gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); + } + std::string sim_ip_str = response["sim_ip"]; + std::string sim_port_str = response["sim_port"]; + if(!sim_ip_str.empty() && !sim_port_str.empty()) + { + U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); + gFirstSim.set(sim_ip_str, sim_port); + if (gFirstSim.isOk()) + { + gMessageSystem->enableCircuit(gFirstSim, TRUE); + } + } + std::string region_x_str = response["region_x"]; + std::string region_y_str = response["region_y"]; + if(!region_x_str.empty() && !region_y_str.empty()) + { + U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); + U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); + gFirstSimHandle = to_region_handle(region_x, region_y); + } + + const std::string look_at_str = response["look_at"]; + if (!look_at_str.empty()) + { + size_t len = look_at_str.size(); + LLMemoryStream mstr((U8*)look_at_str.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + gAgentStartLookAt = ll_vector3_from_sd(sd); + } + + text = response["seed_capability"].asString(); + if (!text.empty()) gFirstSimSeedCap = text; + + text = response["seconds_since_epoch"].asString(); + if(!text.empty()) + { + U32 server_utc_time = strtoul(text.c_str(), NULL, 10); + if(server_utc_time) + { + time_t now = time(NULL); + gUTCOffset = (server_utc_time - now); + + // Print server timestamp + LLSD substitution; + substitution["datetime"] = (S32)server_utc_time; + std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; + LLStringUtil::format(timeStr, substitution); + LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; + } + } + + // this is the base used to construct help URLs + text = response["help_url_format"].asString(); + if (!text.empty()) + { + // replace the default help URL format + gSavedSettings.setString("HelpURLFormat",text); + } + + std::string home_location = response["home"]; + if(!home_location.empty()) + { + size_t len = home_location.size(); + LLMemoryStream mstr((U8*)home_location.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + S32 region_x = sd["region_handle"][0].asInteger(); + S32 region_y = sd["region_handle"][1].asInteger(); + U64 region_handle = to_region_handle(region_x, region_y); + LLVector3 position = ll_vector3_from_sd(sd["position"]); + gAgent.setHomePosRegion(region_handle, position); + } + + gAgent.mMOTD.assign(response["message"]); + + // Options... + // Each 'option' is an array of submaps. + // It appears that we only ever use the first element of the array. + LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; + if(inv_root_folder_id.notNull()) + { + gInventory.setRootFolderID(inv_root_folder_id); + //gInventory.mock(gAgent.getInventoryRootID()); + } + + LLSD login_flags = response["login-flags"][0]; + if(login_flags.size()) + { + std::string flag = login_flags["ever_logged_in"]; + if(!flag.empty()) + { + gAgent.setFirstLogin(flag == "N"); + } + + /* Flag is currently ignored by the viewer. + flag = login_flags["stipend_since_login"]; + if(flag == "Y") + { + stipend_since_login = true; + } + */ + + flag = login_flags["gendered"].asString(); + if(flag == "Y") + { + // We don't care about this flag anymore; now base whether + // outfit is chosen on COF contents, initial outfit + // requested and available, etc. + + //gAgent.setGenderChosen(TRUE); + } + + bool pacific_daylight_time = false; + flag = login_flags["daylight_savings"].asString(); + if(flag == "Y") + { + pacific_daylight_time = (flag == "Y"); + } + + //setup map of datetime strings to codes and slt & local time offset from utc + LLStringOps::setupDatetimeInfo(pacific_daylight_time); + } + + // set up the voice configuration. Ultimately, we should pass this up as part of each voice + // channel if we need to move to multiple voice servers per grid. + LLSD voice_config_info = response["voice-config"]; + if(voice_config_info.has("VoiceServerType")) + { + gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); + } + + // Request the map server url + std::string map_server_url = response["map-server-url"]; + if(!map_server_url.empty()) + { + // We got an answer from the grid -> use that for map for the current session + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; + } + else + { + // No answer from the grid -> use the default setting for current session + map_server_url = gSavedSettings.getString("MapServerURL"); + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; + } + + // Default male and female avatars allowing the user to choose their avatar on first login. + // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard + // "new ruth." Not to be confused with 'initial-outfit' below + LLSD newuser_config = response["newuser-config"][0]; + if(newuser_config.has("DefaultFemaleAvatar")) + { + gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); + } + if(newuser_config.has("DefaultMaleAvatar")) + { + gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); + } + + // Initial outfit for the user. + LLSD initial_outfit = response["initial-outfit"][0]; + if(initial_outfit.size()) + { + std::string flag = initial_outfit["folder_name"]; + if(!flag.empty()) + { + // Initial outfit is a folder in your inventory, + // must be an exact folder-name match. + sInitialOutfit = flag; + } + + flag = initial_outfit["gender"].asString(); + if(!flag.empty()) + { + sInitialOutfitGender = flag; + } + } + + std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); + if (!fake_initial_outfit_name.empty()) + { + gAgent.setFirstLogin(true); + sInitialOutfit = fake_initial_outfit_name; + if (sInitialOutfitGender.empty()) + { + sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. + } + + LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; + } + + // set the location of the Agent Appearance service, from which we can request + // avatar baked textures if they are supported by the current region + std::string agent_appearance_url = response["agent_appearance_service"]; + if (!agent_appearance_url.empty()) + { + LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); + } + + // Set the location of the snapshot sharing config endpoint + std::string snapshot_config_url = response["snapshot_config_url"]; + if(!snapshot_config_url.empty()) + { + gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); + } + + // Start the process of fetching the OpenID session cookie for this user login + std::string openid_url = response["openid_url"]; + if(!openid_url.empty()) + { + std::string openid_token = response["openid_token"]; + LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); + } + + + // Only save mfa_hash for future logins if the user wants their info remembered. + if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && LLLoginInstance::getInstance()->saveMFA()) - { - std::string grid(LLGridManager::getInstance()->getGridId()); - std::string user_id(gUserCredential->userID()); - gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); - // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically - gSecAPIHandler->syncProtectedMap(); - } + { + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id(gUserCredential->userID()); + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); + // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically + gSecAPIHandler->syncProtectedMap(); + } else if (!LLLoginInstance::getInstance()->saveMFA()) { std::string grid(LLGridManager::getInstance()->getGridId()); @@ -3870,26 +3870,26 @@ bool process_login_success_response() gSecAPIHandler->syncProtectedMap(); } - bool success = false; - // JC: gesture loading done below, when we have an asset system - // in place. Don't delete/clear gUserCredentials until then. - if(gAgentID.notNull() - && gAgentSessionID.notNull() - && gMessageSystem->mOurCircuitCode - && gFirstSim.isOk() - && gInventory.getRootFolderID().notNull()) - { - success = true; - } + bool success = false; + // JC: gesture loading done below, when we have an asset system + // in place. Don't delete/clear gUserCredentials until then. + if(gAgentID.notNull() + && gAgentSessionID.notNull() + && gMessageSystem->mOurCircuitCode + && gFirstSim.isOk() + && gInventory.getRootFolderID().notNull()) + { + success = true; + } LLAppViewer* pApp = LLAppViewer::instance(); - pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. - return success; + pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. + return success; } void transition_back_to_login_panel(const std::string& emsg) { - // Bounce back to the login screen. - reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - gSavedSettings.setBOOL("AutoLogin", FALSE); + // Bounce back to the login screen. + reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + gSavedSettings.setBOOL("AutoLogin", FALSE); } diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index d2a650f200..5fc0ea855e 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltoast.cpp * @brief This class implements a placeholder for any notification panel. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,8 +38,8 @@ std::list<LLToast*> LLToast::sModalToastsList; //-------------------------------------------------------------------------- LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period) - : mToast(toast), - LLEventTimer(period) + : mToast(toast), + LLEventTimer(period) { } @@ -51,159 +51,159 @@ bool LLToastLifeTimer::tick() void LLToastLifeTimer::restart() { - // start() discards any previously-running mTimer - start(); + // start() discards any previously-running mTimer + start(); } bool LLToastLifeTimer::getStarted() { - return isRunning(); + return isRunning(); } void LLToastLifeTimer::setPeriod(F32 period) { - mPeriod = period; + mPeriod = period; } /*==========================================================================*| F32 LLToastLifeTimer::getRemainingTimeF32() { - F32 et = mEventTimer.getElapsedTimeF32(); - if (!getStarted() || et > mPeriod) return 0.0f; - return mPeriod - et; + F32 et = mEventTimer.getElapsedTimeF32(); + if (!getStarted() || et > mPeriod) return 0.0f; + return mPeriod - et; } |*==========================================================================*/ //-------------------------------------------------------------------------- -LLToast::Params::Params() -: can_fade("can_fade", true), - can_be_stored("can_be_stored", true), - is_modal("is_modal", false), - is_tip("is_tip", false), - enable_hide_btn("enable_hide_btn", true), - force_show("force_show", false), - force_store("force_store", false), - fading_time_secs("fading_time_secs", gSavedSettings.getS32("ToastFadingTime")), - lifetime_secs("lifetime_secs", gSavedSettings.getS32("NotificationToastLifeTime")) +LLToast::Params::Params() +: can_fade("can_fade", true), + can_be_stored("can_be_stored", true), + is_modal("is_modal", false), + is_tip("is_tip", false), + enable_hide_btn("enable_hide_btn", true), + force_show("force_show", false), + force_store("force_store", false), + fading_time_secs("fading_time_secs", gSavedSettings.getS32("ToastFadingTime")), + lifetime_secs("lifetime_secs", gSavedSettings.getS32("NotificationToastLifeTime")) {}; -LLToast::LLToast(const LLToast::Params& p) -: LLModalDialog(LLSD(), p.is_modal), - mToastLifetime(p.lifetime_secs), - mToastFadingTime(p.fading_time_secs), - mNotificationID(p.notif_id), - mSessionID(p.session_id), - mCanFade(p.can_fade), - mCanBeStored(p.can_be_stored), - mHideBtnEnabled(p.enable_hide_btn), - mHideBtn(NULL), - mPanel(NULL), - mNotification(p.notification), - mIsHidden(false), - mHideBtnPressed(false), - mIsTip(p.is_tip), - mWrapperPanel(NULL), - mIsFading(false), - mIsHovered(false) -{ - mTimer.reset(new LLToastLifeTimer(this, p.lifetime_secs)); - - buildFromFile("panel_toast.xml"); - - setCanDrag(FALSE); - - mWrapperPanel = getChild<LLPanel>("wrapper_panel"); - - setBackgroundOpaque(TRUE); // *TODO: obsolete - updateTransparency(); - - if(p.panel()) - { - insertPanel(p.panel); - } - - if(mHideBtnEnabled) - { - mHideBtn = getChild<LLButton>("hide_btn"); - mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); - } - - // init callbacks if present - if(!p.on_delete_toast().empty()) - { - mOnDeleteToastSignal.connect(p.on_delete_toast()); - } - - if (isModal()) - { - sModalToastsList.push_front(this); - } +LLToast::LLToast(const LLToast::Params& p) +: LLModalDialog(LLSD(), p.is_modal), + mToastLifetime(p.lifetime_secs), + mToastFadingTime(p.fading_time_secs), + mNotificationID(p.notif_id), + mSessionID(p.session_id), + mCanFade(p.can_fade), + mCanBeStored(p.can_be_stored), + mHideBtnEnabled(p.enable_hide_btn), + mHideBtn(NULL), + mPanel(NULL), + mNotification(p.notification), + mIsHidden(false), + mHideBtnPressed(false), + mIsTip(p.is_tip), + mWrapperPanel(NULL), + mIsFading(false), + mIsHovered(false) +{ + mTimer.reset(new LLToastLifeTimer(this, p.lifetime_secs)); + + buildFromFile("panel_toast.xml"); + + setCanDrag(FALSE); + + mWrapperPanel = getChild<LLPanel>("wrapper_panel"); + + setBackgroundOpaque(TRUE); // *TODO: obsolete + updateTransparency(); + + if(p.panel()) + { + insertPanel(p.panel); + } + + if(mHideBtnEnabled) + { + mHideBtn = getChild<LLButton>("hide_btn"); + mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); + } + + // init callbacks if present + if(!p.on_delete_toast().empty()) + { + mOnDeleteToastSignal.connect(p.on_delete_toast()); + } + + if (isModal()) + { + sModalToastsList.push_front(this); + } } void LLToast::reshape(S32 width, S32 height, BOOL called_from_parent) { - // We shouldn't use reshape from LLModalDialog since it changes toasts position. - // Toasts position should be controlled only by toast screen channel, see LLScreenChannelBase. - // see EXT-8044 - LLFloater::reshape(width, height, called_from_parent); + // We shouldn't use reshape from LLModalDialog since it changes toasts position. + // Toasts position should be controlled only by toast screen channel, see LLScreenChannelBase. + // see EXT-8044 + LLFloater::reshape(width, height, called_from_parent); } //-------------------------------------------------------------------------- BOOL LLToast::postBuild() { - if(!mCanFade) - { - mTimer->stop(); - } + if(!mCanFade) + { + mTimer->stop(); + } - return TRUE; + return TRUE; } //-------------------------------------------------------------------------- void LLToast::setHideButtonEnabled(bool enabled) { - if(mHideBtn) - mHideBtn->setEnabled(enabled); + if(mHideBtn) + mHideBtn->setEnabled(enabled); } //-------------------------------------------------------------------------- LLToast::~LLToast() { - if(LLApp::isQuitting()) - { - mOnFadeSignal.disconnect_all_slots(); - mOnDeleteToastSignal.disconnect_all_slots(); - mOnToastDestroyedSignal.disconnect_all_slots(); - mOnToastHoverSignal.disconnect_all_slots(); - mToastMouseEnterSignal.disconnect_all_slots(); - mToastMouseLeaveSignal.disconnect_all_slots(); - } - else - { - mOnToastDestroyedSignal(this); - } - - if (isModal()) - { - std::list<LLToast*>::iterator iter = std::find(sModalToastsList.begin(), sModalToastsList.end(), this); - if (iter != sModalToastsList.end()) - { - sModalToastsList.erase(iter); - } - } + if(LLApp::isQuitting()) + { + mOnFadeSignal.disconnect_all_slots(); + mOnDeleteToastSignal.disconnect_all_slots(); + mOnToastDestroyedSignal.disconnect_all_slots(); + mOnToastHoverSignal.disconnect_all_slots(); + mToastMouseEnterSignal.disconnect_all_slots(); + mToastMouseLeaveSignal.disconnect_all_slots(); + } + else + { + mOnToastDestroyedSignal(this); + } + + if (isModal()) + { + std::list<LLToast*>::iterator iter = std::find(sModalToastsList.begin(), sModalToastsList.end(), this); + if (iter != sModalToastsList.end()) + { + sModalToastsList.erase(iter); + } + } } //-------------------------------------------------------------------------- void LLToast::hide() { - if (!mIsHidden) - { - setVisible(FALSE); - setFading(false); - mTimer->stop(); - mIsHidden = true; - mOnFadeSignal(this); - } + if (!mIsHidden) + { + setVisible(FALSE); + setFading(false); + mTimer->stop(); + mIsHidden = true; + mOnFadeSignal(this); + } } /*virtual*/ @@ -227,188 +227,188 @@ void LLToast::setFocus(BOOL b) void LLToast::onFocusLost() { - if(mWrapperPanel && !isBackgroundVisible()) - { - // Lets make wrapper panel behave like a floater - updateTransparency(); - } + if(mWrapperPanel && !isBackgroundVisible()) + { + // Lets make wrapper panel behave like a floater + updateTransparency(); + } } void LLToast::onFocusReceived() { - if(mWrapperPanel && !isBackgroundVisible()) - { - // Lets make wrapper panel behave like a floater - updateTransparency(); - } + if(mWrapperPanel && !isBackgroundVisible()) + { + // Lets make wrapper panel behave like a floater + updateTransparency(); + } } void LLToast::setLifetime(S32 seconds) { - mToastLifetime = seconds; + mToastLifetime = seconds; } void LLToast::setFadingTime(S32 seconds) { - mToastFadingTime = seconds; + mToastFadingTime = seconds; } void LLToast::closeToast() { - mOnDeleteToastSignal(this); + mOnDeleteToastSignal(this); - setSoundFlags(SILENT); + setSoundFlags(SILENT); - closeFloater(); + closeFloater(); } S32 LLToast::getTopPad() { - if(mWrapperPanel) - { - return getRect().getHeight() - mWrapperPanel->getRect().getHeight(); - } - return 0; + if(mWrapperPanel) + { + return getRect().getHeight() - mWrapperPanel->getRect().getHeight(); + } + return 0; } S32 LLToast::getRightPad() { - if(mWrapperPanel) - { - return getRect().getWidth() - mWrapperPanel->getRect().getWidth(); - } - return 0; + if(mWrapperPanel) + { + return getRect().getWidth() - mWrapperPanel->getRect().getWidth(); + } + return 0; } //-------------------------------------------------------------------------- -void LLToast::setCanFade(bool can_fade) -{ - mCanFade = can_fade; - if(!mCanFade) - { - mTimer->stop(); - } +void LLToast::setCanFade(bool can_fade) +{ + mCanFade = can_fade; + if(!mCanFade) + { + mTimer->stop(); + } } //-------------------------------------------------------------------------- void LLToast::expire() { - if (mCanFade) - { - if (mIsFading) - { - // Fade timer expired. Time to hide. - hide(); - } - else - { - // "Life" time has ended. Time to fade. - setFading(true); - mTimer->restart(); - } - } + if (mCanFade) + { + if (mIsFading) + { + // Fade timer expired. Time to hide. + hide(); + } + else + { + // "Life" time has ended. Time to fade. + setFading(true); + mTimer->restart(); + } + } } void LLToast::setFading(bool transparent) { - mIsFading = transparent; - updateTransparency(); + mIsFading = transparent; + updateTransparency(); - if (transparent) - { - mTimer->setPeriod(mToastFadingTime); - } - else - { - mTimer->setPeriod(mToastLifetime); - } + if (transparent) + { + mTimer->setPeriod(mToastFadingTime); + } + else + { + mTimer->setPeriod(mToastLifetime); + } } F32 LLToast::getTimeLeftToLive() { - F32 time_to_live = mTimer->getRemaining(); + F32 time_to_live = mTimer->getRemaining(); - if (!mIsFading) - { - time_to_live += mToastFadingTime; - } + if (!mIsFading) + { + time_to_live += mToastFadingTime; + } - return time_to_live; + return time_to_live; } //-------------------------------------------------------------------------- void LLToast::reshapeToPanel() { - LLPanel* panel = getPanel(); - if(!panel) - return; + LLPanel* panel = getPanel(); + if(!panel) + return; - LLRect panel_rect = panel->getLocalRect(); - panel->setShape(panel_rect); - - LLRect toast_rect = getRect(); + LLRect panel_rect = panel->getLocalRect(); + panel->setShape(panel_rect); - toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, - panel_rect.getWidth() + getRightPad(), panel_rect.getHeight() + getTopPad()); - setShape(toast_rect); + LLRect toast_rect = getRect(); + + toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, + panel_rect.getWidth() + getRightPad(), panel_rect.getHeight() + getTopPad()); + setShape(toast_rect); } void LLToast::insertPanel(LLPanel* panel) { - mPanel = panel; - mWrapperPanel->addChild(panel); - reshapeToPanel(); + mPanel = panel; + mWrapperPanel->addChild(panel); + reshapeToPanel(); } //-------------------------------------------------------------------------- void LLToast::draw() { - LLFloater::draw(); - - if(!isBackgroundVisible()) - { - // Floater background is invisible, lets make wrapper panel look like a - // floater - draw shadow. - drawShadow(mWrapperPanel); + LLFloater::draw(); - // Shadow will probably overlap close button, lets redraw the button - if(mHideBtn) - { - drawChild(mHideBtn); - } - } + if(!isBackgroundVisible()) + { + // Floater background is invisible, lets make wrapper panel look like a + // floater - draw shadow. + drawShadow(mWrapperPanel); + + // Shadow will probably overlap close button, lets redraw the button + if(mHideBtn) + { + drawChild(mHideBtn); + } + } } //-------------------------------------------------------------------------- void LLToast::setVisible(BOOL show) { - if(mIsHidden) - { - // this toast is invisible after fade until its ScreenChannel will allow it - // - // (EXT-1849) according to this bug a toast can be resurrected from - // invisible state if it faded during a teleportation - // then it fades a second time and causes a crash - return; - } - - if (show && getVisible()) - { - return; - } - - if(show) - { - if(!mTimer->getStarted() && mCanFade) - { - mTimer->start(); - } - } - else - { - //hide "hide" button in case toast was hidden without mouse_leave - if(mHideBtn) - mHideBtn->setVisible(show); + if(mIsHidden) + { + // this toast is invisible after fade until its ScreenChannel will allow it + // + // (EXT-1849) according to this bug a toast can be resurrected from + // invisible state if it faded during a teleportation + // then it fades a second time and causes a crash + return; + } + + if (show && getVisible()) + { + return; + } + + if(show) + { + if(!mTimer->getStarted() && mCanFade) + { + mTimer->start(); + } + } + else + { + //hide "hide" button in case toast was hidden without mouse_leave + if(mHideBtn) + mHideBtn->setVisible(show); } LLFloater::setVisible(show); if (mPanel @@ -425,198 +425,198 @@ void LLToast::setVisible(BOOL show) void LLToast::updateHoveredState() { - S32 x, y; - LLUI::getInstance()->getMousePositionScreen(&x, &y); - - LLRect panel_rc = mWrapperPanel->calcScreenRect(); - LLRect button_rc; - if(mHideBtn) - { - button_rc = mHideBtn->calcScreenRect(); - } - - if (!panel_rc.pointInRect(x, y) && !button_rc.pointInRect(x, y)) - { - // mouse is not over this toast - mIsHovered = false; - } - else - { - bool is_overlapped_by_other_floater = false; - - const child_list_t* child_list = gFloaterView->getChildList(); - - // find this toast in gFloaterView child list to check whether any floater - // with higher Z-order is visible under the mouse pointer overlapping this toast - child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this); - if (r_iter != child_list->rend()) - { - // skip this toast and proceed to views above in Z-order - for (++r_iter; r_iter != child_list->rend(); ++r_iter) - { - LLView* view = *r_iter; - is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y); - if (is_overlapped_by_other_floater) - { - break; - } - } - } - - mIsHovered = !is_overlapped_by_other_floater; - } - - LLToastLifeTimer* timer = getTimer(); - - if (timer) - { - // Started timer means the mouse had left the toast previously. - // If toast is hovered in the current frame we should handle - // a mouse enter event. - if(timer->getStarted() && mIsHovered) - { - mOnToastHoverSignal(this, MOUSE_ENTER); - - updateTransparency(); - - //toasts fading is management by Screen Channel - - sendChildToFront(mHideBtn); - if(mHideBtn && mHideBtn->getEnabled()) - { - mHideBtn->setVisible(TRUE); - } - - mToastMouseEnterSignal(this, getValue()); - } - // Stopped timer means the mouse had entered the toast previously. - // If the toast is not hovered in the current frame we should handle - // a mouse leave event. - else if(!timer->getStarted() && !mIsHovered) - { - mOnToastHoverSignal(this, MOUSE_LEAVE); - - updateTransparency(); - - //toasts fading is management by Screen Channel - - if(mHideBtn && mHideBtn->getEnabled()) - { - if( mHideBtnPressed ) - { - mHideBtnPressed = false; - return; - } - mHideBtn->setVisible(FALSE); - } - - mToastMouseLeaveSignal(this, getValue()); - } - } + S32 x, y; + LLUI::getInstance()->getMousePositionScreen(&x, &y); + + LLRect panel_rc = mWrapperPanel->calcScreenRect(); + LLRect button_rc; + if(mHideBtn) + { + button_rc = mHideBtn->calcScreenRect(); + } + + if (!panel_rc.pointInRect(x, y) && !button_rc.pointInRect(x, y)) + { + // mouse is not over this toast + mIsHovered = false; + } + else + { + bool is_overlapped_by_other_floater = false; + + const child_list_t* child_list = gFloaterView->getChildList(); + + // find this toast in gFloaterView child list to check whether any floater + // with higher Z-order is visible under the mouse pointer overlapping this toast + child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this); + if (r_iter != child_list->rend()) + { + // skip this toast and proceed to views above in Z-order + for (++r_iter; r_iter != child_list->rend(); ++r_iter) + { + LLView* view = *r_iter; + is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y); + if (is_overlapped_by_other_floater) + { + break; + } + } + } + + mIsHovered = !is_overlapped_by_other_floater; + } + + LLToastLifeTimer* timer = getTimer(); + + if (timer) + { + // Started timer means the mouse had left the toast previously. + // If toast is hovered in the current frame we should handle + // a mouse enter event. + if(timer->getStarted() && mIsHovered) + { + mOnToastHoverSignal(this, MOUSE_ENTER); + + updateTransparency(); + + //toasts fading is management by Screen Channel + + sendChildToFront(mHideBtn); + if(mHideBtn && mHideBtn->getEnabled()) + { + mHideBtn->setVisible(TRUE); + } + + mToastMouseEnterSignal(this, getValue()); + } + // Stopped timer means the mouse had entered the toast previously. + // If the toast is not hovered in the current frame we should handle + // a mouse leave event. + else if(!timer->getStarted() && !mIsHovered) + { + mOnToastHoverSignal(this, MOUSE_LEAVE); + + updateTransparency(); + + //toasts fading is management by Screen Channel + + if(mHideBtn && mHideBtn->getEnabled()) + { + if( mHideBtnPressed ) + { + mHideBtnPressed = false; + return; + } + mHideBtn->setVisible(FALSE); + } + + mToastMouseLeaveSignal(this, getValue()); + } + } } void LLToast::setBackgroundOpaque(BOOL b) { - if(mWrapperPanel && !isBackgroundVisible()) - { - mWrapperPanel->setBackgroundOpaque(b); - } - else - { - LLModalDialog::setBackgroundOpaque(b); - } + if(mWrapperPanel && !isBackgroundVisible()) + { + mWrapperPanel->setBackgroundOpaque(b); + } + else + { + LLModalDialog::setBackgroundOpaque(b); + } } void LLToast::updateTransparency() { - ETypeTransparency transparency_type; - - if (mCanFade) - { - // Notification toasts (including IM/chat toasts) change their transparency on hover. - if (isHovered()) - { - transparency_type = TT_ACTIVE; - } - else - { - transparency_type = mIsFading ? TT_FADING : TT_INACTIVE; - } - } - else - { - // Transparency of alert toasts depends on focus. - transparency_type = hasFocus() ? TT_ACTIVE : TT_INACTIVE; - } - - LLFloater::updateTransparency(transparency_type); + ETypeTransparency transparency_type; + + if (mCanFade) + { + // Notification toasts (including IM/chat toasts) change their transparency on hover. + if (isHovered()) + { + transparency_type = TT_ACTIVE; + } + else + { + transparency_type = mIsFading ? TT_FADING : TT_INACTIVE; + } + } + else + { + // Transparency of alert toasts depends on focus. + transparency_type = hasFocus() ? TT_ACTIVE : TT_INACTIVE; + } + + LLFloater::updateTransparency(transparency_type); } void LLNotificationsUI::LLToast::stopTimer() { - if(mCanFade) - { - setFading(false); - mTimer->stop(); - } + if(mCanFade) + { + setFading(false); + mTimer->stop(); + } } void LLNotificationsUI::LLToast::startTimer() { - if(mCanFade) - { - setFading(false); - mTimer->start(); - } + if(mCanFade) + { + setFading(false); + mTimer->start(); + } } //-------------------------------------------------------------------------- BOOL LLToast::handleMouseDown(S32 x, S32 y, MASK mask) { - if(mHideBtn && mHideBtn->getEnabled()) - { - mHideBtnPressed = mHideBtn->getRect().pointInRect(x, y); - } + if(mHideBtn && mHideBtn->getEnabled()) + { + mHideBtnPressed = mHideBtn->getRect().pointInRect(x, y); + } - return LLModalDialog::handleMouseDown(x, y, mask); + return LLModalDialog::handleMouseDown(x, y, mask); } //-------------------------------------------------------------------------- bool LLToast::isNotificationValid() { - if(mNotification) - { - return !mNotification->isCancelled(); - } - return false; + if(mNotification) + { + return !mNotification->isCancelled(); + } + return false; } //-------------------------------------------------------------------------- -S32 LLToast::notifyParent(const LLSD& info) +S32 LLToast::notifyParent(const LLSD& info) { - if (info.has("action") && "hide_toast" == info["action"].asString()) - { - hide(); - return 1; - } + if (info.has("action") && "hide_toast" == info["action"].asString()) + { + hide(); + return 1; + } - return LLModalDialog::notifyParent(info); + return LLModalDialog::notifyParent(info); } //static void LLToast::updateClass() { - for (auto& toast : LLInstanceTracker<LLToast>::instance_snapshot()) - { - toast.updateHoveredState(); - } + for (auto& toast : LLInstanceTracker<LLToast>::instance_snapshot()) + { + toast.updateHoveredState(); + } } -// static +// static void LLToast::cleanupToasts() { - LLInstanceTracker<LLToast>::instance_snapshot().deleteAll(); + LLInstanceTracker<LLToast>::instance_snapshot().deleteAll(); } diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 49969ab70a..460317aaa9 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -1,25 +1,25 @@ -/** +/** * @file lltoast.h * @brief This class implements a placeholder for any notification panel. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,18 +50,18 @@ class LLToast; class LLToastLifeTimer: public LLEventTimer { public: - LLToastLifeTimer(LLToast* toast, F32 period); + LLToastLifeTimer(LLToast* toast, F32 period); - /*virtual*/ - bool tick() override; - void restart(); - bool getStarted(); - void setPeriod(F32 period); -// F32 getRemainingTimeF32(); + /*virtual*/ + bool tick() override; + void restart(); + bool getStarted(); + void setPeriod(F32 period); +// F32 getRemainingTimeF32(); -// LLTimer& getEventTimer() { return mEventTimer;} +// LLTimer& getEventTimer() { return mEventTimer;} private : - LLToast* mToast; + LLToast* mToast; }; /** @@ -70,184 +70,184 @@ private : */ class LLToast : public LLModalDialog, public LLInstanceTracker<LLToast> { - friend class LLToastLifeTimer; + friend class LLToastLifeTimer; public: - typedef boost::function<void (LLToast* toast)> toast_callback_t; - typedef boost::signals2::signal<void (LLToast* toast)> toast_signal_t; - typedef boost::signals2::signal<void (LLToast* toast, bool mouse_enter)> toast_hover_check_signal_t; + typedef boost::function<void (LLToast* toast)> toast_callback_t; + typedef boost::signals2::signal<void (LLToast* toast)> toast_signal_t; + typedef boost::signals2::signal<void (LLToast* toast, bool mouse_enter)> toast_hover_check_signal_t; + + struct Params : public LLInitParam::Block<Params> + { + Mandatory<LLPanel*> panel; + Optional<LLUUID> notif_id, //notification ID + session_id; //im session ID + Optional<LLNotificationPtr> notification; - struct Params : public LLInitParam::Block<Params> - { - Mandatory<LLPanel*> panel; - Optional<LLUUID> notif_id, //notification ID - session_id; //im session ID - Optional<LLNotificationPtr> notification; + //NOTE: Life time of a toast (i.e. period of time from the moment toast was shown + //till the moment when toast was hidden) is the sum of lifetime_secs and fading_time_secs. - //NOTE: Life time of a toast (i.e. period of time from the moment toast was shown - //till the moment when toast was hidden) is the sum of lifetime_secs and fading_time_secs. + Optional<F32> lifetime_secs, // Number of seconds while a toast is non-transparent + fading_time_secs; // Number of seconds while a toast is transparent - Optional<F32> lifetime_secs, // Number of seconds while a toast is non-transparent - fading_time_secs; // Number of seconds while a toast is transparent + Optional<toast_callback_t> on_delete_toast; + Optional<bool> can_fade, + can_be_stored, + enable_hide_btn, + is_modal, + is_tip, + force_show, + force_store; - Optional<toast_callback_t> on_delete_toast; - Optional<bool> can_fade, - can_be_stored, - enable_hide_btn, - is_modal, - is_tip, - force_show, - force_store; + Params(); + }; - Params(); - }; - - static void updateClass(); - static void cleanupToasts(); + static void updateClass(); + static void cleanupToasts(); - static BOOL isAlertToastShown() { return sModalToastsList.size() > 0; } + static BOOL isAlertToastShown() { return sModalToastsList.size() > 0; } - LLToast(const LLToast::Params& p); - virtual ~LLToast(); - BOOL postBuild(); + LLToast(const LLToast::Params& p); + virtual ~LLToast(); + BOOL postBuild(); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - // Toast handlers - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + // Toast handlers + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - //Fading + //Fading - /** Stop lifetime/fading timer */ - virtual void stopTimer(); + /** Stop lifetime/fading timer */ + virtual void stopTimer(); - /** Start lifetime/fading timer */ - virtual void startTimer(); + /** Start lifetime/fading timer */ + virtual void startTimer(); - bool isHovered() { return mIsHovered; } + bool isHovered() { return mIsHovered; } - // Operating with toasts - // insert a panel to a toast - void insertPanel(LLPanel* panel); + // Operating with toasts + // insert a panel to a toast + void insertPanel(LLPanel* panel); - void reshapeToPanel(); + void reshapeToPanel(); - // get toast's panel - LLPanel* getPanel() const { return mPanel; } - // enable/disable Toast's Hide button - void setHideButtonEnabled(bool enabled); - // - F32 getTimeLeftToLive(); - // - LLToastLifeTimer* getTimer() { return mTimer.get();} - // - virtual void draw(); - // - virtual void setVisible(BOOL show); + // get toast's panel + LLPanel* getPanel() const { return mPanel; } + // enable/disable Toast's Hide button + void setHideButtonEnabled(bool enabled); + // + F32 getTimeLeftToLive(); + // + LLToastLifeTimer* getTimer() { return mTimer.get();} + // + virtual void draw(); + // + virtual void setVisible(BOOL show); - /*virtual*/ void setBackgroundOpaque(BOOL b); - // - virtual void hide(); + /*virtual*/ void setBackgroundOpaque(BOOL b); + // + virtual void hide(); - /*virtual*/ void setFocus(BOOL b); + /*virtual*/ void setFocus(BOOL b); - /*virtual*/ void onFocusLost(); + /*virtual*/ void onFocusLost(); - /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusReceived(); - void setLifetime(S32 seconds); + void setLifetime(S32 seconds); - void setFadingTime(S32 seconds); + void setFadingTime(S32 seconds); - void closeToast(); + void closeToast(); - /** - * Returns padding between floater top and wrapper_panel top. - * This padding should be taken into account when positioning or reshaping toasts - */ - S32 getTopPad(); + /** + * Returns padding between floater top and wrapper_panel top. + * This padding should be taken into account when positioning or reshaping toasts + */ + S32 getTopPad(); - S32 getRightPad(); + S32 getRightPad(); - // get/set Toast's flags or states - // get information whether the notification corresponding to the toast is valid or not - bool isNotificationValid(); + // get/set Toast's flags or states + // get information whether the notification corresponding to the toast is valid or not + bool isNotificationValid(); - // get toast's Notification ID - const LLUUID getNotificationID() const { return mNotificationID;} - // get toast's Session ID - const LLUUID getSessionID() const { return mSessionID;} - // - void setCanFade(bool can_fade); - // - void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } - // - bool getCanBeStored() { return mCanBeStored; } - // set whether this toast considered as hidden or not - void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; } + // get toast's Notification ID + const LLUUID getNotificationID() const { return mNotificationID;} + // get toast's Session ID + const LLUUID getSessionID() const { return mSessionID;} + // + void setCanFade(bool can_fade); + // + void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } + // + bool getCanBeStored() { return mCanBeStored; } + // set whether this toast considered as hidden or not + void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; } - const LLNotificationPtr& getNotification() const { return mNotification;} + const LLNotificationPtr& getNotification() const { return mNotification;} - // Registers signals/callbacks for events - boost::signals2::connection setOnFadeCallback(const toast_signal_t::slot_type& cb) { return mOnFadeSignal.connect(cb); } - boost::signals2::connection setOnToastDestroyedCallback(const toast_signal_t::slot_type& cb) { return mOnToastDestroyedSignal.connect(cb); } - boost::signals2::connection setOnToastHoverCallback(const toast_hover_check_signal_t::slot_type& cb) { return mOnToastHoverSignal.connect(cb); } + // Registers signals/callbacks for events + boost::signals2::connection setOnFadeCallback(const toast_signal_t::slot_type& cb) { return mOnFadeSignal.connect(cb); } + boost::signals2::connection setOnToastDestroyedCallback(const toast_signal_t::slot_type& cb) { return mOnToastDestroyedSignal.connect(cb); } + boost::signals2::connection setOnToastHoverCallback(const toast_hover_check_signal_t::slot_type& cb) { return mOnToastHoverSignal.connect(cb); } - boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseEnterSignal.connect(cb); }; - boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseLeaveSignal.connect(cb); }; + boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseEnterSignal.connect(cb); }; + boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseLeaveSignal.connect(cb); }; - virtual S32 notifyParent(const LLSD& info); + virtual S32 notifyParent(const LLSD& info); - LLHandle<LLToast> getHandle() const { return getDerivedHandle<LLToast>(); } + LLHandle<LLToast> getHandle() const { return getDerivedHandle<LLToast>(); } protected: - void updateTransparency(); + void updateTransparency(); private: - void updateHoveredState(); + void updateHoveredState(); + + void expire(); + + void setFading(bool fading); - void expire(); + LLUUID mNotificationID; + LLUUID mSessionID; + LLNotificationPtr mNotification; - void setFading(bool fading); + //LLRootHandle<LLToast> mHandle; - LLUUID mNotificationID; - LLUUID mSessionID; - LLNotificationPtr mNotification; + LLPanel* mWrapperPanel; - //LLRootHandle<LLToast> mHandle; - - LLPanel* mWrapperPanel; + // timer counts a lifetime of a toast + std::unique_ptr<LLToastLifeTimer> mTimer; - // timer counts a lifetime of a toast - std::unique_ptr<LLToastLifeTimer> mTimer; + F32 mToastLifetime; // in seconds + F32 mToastFadingTime; // in seconds - F32 mToastLifetime; // in seconds - F32 mToastFadingTime; // in seconds - - LLPanel* mPanel; - LLButton* mHideBtn; + LLPanel* mPanel; + LLButton* mHideBtn; - LLColor4 mBgColor; - bool mCanFade; - bool mCanBeStored; - bool mHideBtnEnabled; - bool mHideBtnPressed; - bool mIsHidden; // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849) - bool mIsTip; - bool mIsFading; - bool mIsHovered; + LLColor4 mBgColor; + bool mCanFade; + bool mCanBeStored; + bool mHideBtnEnabled; + bool mHideBtnPressed; + bool mIsHidden; // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849) + bool mIsTip; + bool mIsFading; + bool mIsHovered; - toast_signal_t mOnFadeSignal; - toast_signal_t mOnDeleteToastSignal; - toast_signal_t mOnToastDestroyedSignal; - toast_hover_check_signal_t mOnToastHoverSignal; + toast_signal_t mOnFadeSignal; + toast_signal_t mOnDeleteToastSignal; + toast_signal_t mOnToastDestroyedSignal; + toast_hover_check_signal_t mOnToastHoverSignal; - commit_signal_t mToastMouseEnterSignal; - commit_signal_t mToastMouseLeaveSignal; + commit_signal_t mToastMouseEnterSignal; + commit_signal_t mToastMouseLeaveSignal; - static std::list<LLToast*> sModalToastsList; + static std::list<LLToast*> sModalToastsList; }; } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index a4e6d20181..94aa4a61ac 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltoolplacer.cpp * @brief Tool for placing new objects into the world * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -60,480 +60,480 @@ // linden library headers #include "llprimitive.h" -#include "llwindow.h" // incBusyCount() +#include "llwindow.h" // incBusyCount() #include "material_codes.h" #include "lluiusage.h" const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f); -//static -LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; +//static +LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; LLToolPlacer::LLToolPlacer() -: LLTool( "Create" ) +: LLTool( "Create" ) { } -BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, - BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) +BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, + BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) { - F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; - - // Viewer-side pick to find the right sim to create the object on. - // First find the surface the object will be created on. - LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); - - // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok - // representations (if any) are NOT the same as their viewer representation. - if (pick.mPickType == LLPickInfo::PICK_FLORA) - { - *hit_obj = NULL; - *hit_face = -1; - } - else - { - *hit_obj = pick.getObject(); - *hit_face = pick.mObjectFace; - } - *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); - LLVector3d land_pos_global = pick.mPosGlobal; - - // Make sure there's a surface to place the new object on. - BOOL bypass_sim_raycast = FALSE; - LLVector3d surface_pos_global; - if (*b_hit_land) - { - surface_pos_global = land_pos_global; - bypass_sim_raycast = TRUE; - } - else - if (*hit_obj) - { - surface_pos_global = (*hit_obj)->getPositionGlobal(); - } - else - { - return FALSE; - } - - // Make sure the surface isn't too far away. - LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); - F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); - if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) - { - return FALSE; - } - - // Find the sim where the surface lives. - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); - if (!regionp) - { - LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; - return FALSE; - } - - // Find the simulator-side ray that will be used to place the object accurately - LLVector3d mouse_direction; - mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); - - *region = regionp; - *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); - F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. - *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; - - if( bypass_sim_raycast ) - { - // Hack to work around Havok's inability to ray cast onto height fields - *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point - } - else - { - LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. - *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); - } - - return TRUE; + F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; + + // Viewer-side pick to find the right sim to create the object on. + // First find the surface the object will be created on. + LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); + + // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok + // representations (if any) are NOT the same as their viewer representation. + if (pick.mPickType == LLPickInfo::PICK_FLORA) + { + *hit_obj = NULL; + *hit_face = -1; + } + else + { + *hit_obj = pick.getObject(); + *hit_face = pick.mObjectFace; + } + *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); + LLVector3d land_pos_global = pick.mPosGlobal; + + // Make sure there's a surface to place the new object on. + BOOL bypass_sim_raycast = FALSE; + LLVector3d surface_pos_global; + if (*b_hit_land) + { + surface_pos_global = land_pos_global; + bypass_sim_raycast = TRUE; + } + else + if (*hit_obj) + { + surface_pos_global = (*hit_obj)->getPositionGlobal(); + } + else + { + return FALSE; + } + + // Make sure the surface isn't too far away. + LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); + F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); + if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) + { + return FALSE; + } + + // Find the sim where the surface lives. + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); + if (!regionp) + { + LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; + return FALSE; + } + + // Find the simulator-side ray that will be used to place the object accurately + LLVector3d mouse_direction; + mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); + + *region = regionp; + *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); + F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. + *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; + + if( bypass_sim_raycast ) + { + // Hack to work around Havok's inability to ray cast onto height fields + *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point + } + else + { + LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. + *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); + } + + return TRUE; } BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - BOOL b_hit_land = FALSE; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - return FALSE; - } + LLVector3 ray_start_region; + LLVector3 ray_end_region; + LLViewerRegion* regionp = NULL; + BOOL b_hit_land = FALSE; + S32 hit_face = -1; + LLViewerObject* hit_obj = NULL; + BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); + if( !success ) + { + return FALSE; + } return rezNewObject(pcode,hit_obj, hit_face, b_hit_land, ray_start_region, ray_end_region, regionp, use_physics); } BOOL LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion* regionp, U8 use_physics) { - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - return FALSE; - } - - if (NULL == regionp) - { - LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; - return FALSE; - } - - if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) - { - //LLFirstUse::useSandbox(); - } - - // Set params for new object based on its PCode. - LLQuaternion rotation; - LLVector3 scale = DEFAULT_OBJECT_SCALE; - U8 material = LL_MCODE_WOOD; - BOOL create_selected = FALSE; - LLVolumeParams volume_params; + if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) + { + // Can't create objects on avatars or attachments + return FALSE; + } + + if (NULL == regionp) + { + LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; + return FALSE; + } + + if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) + { + //LLFirstUse::useSandbox(); + } + + // Set params for new object based on its PCode. + LLQuaternion rotation; + LLVector3 scale = DEFAULT_OBJECT_SCALE; + U8 material = LL_MCODE_WOOD; + BOOL create_selected = FALSE; + LLVolumeParams volume_params; U8 state = 0; - - switch (pcode) - { - case LL_PCODE_LEGACY_GRASS: - // Randomize size of grass patch - scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); - state = rand() % LLVOGrass::sMaxGrassSpecies; - break; - - - case LL_PCODE_LEGACY_TREE: - case LL_PCODE_TREE_NEW: - state = rand() % LLVOTree::sMaxTreeSpecies; - break; - - case LL_PCODE_SPHERE: - case LL_PCODE_CONE: - case LL_PCODE_CUBE: - case LL_PCODE_CYLINDER: - case LL_PCODE_TORUS: - case LLViewerObject::LL_VO_SQUARE_TORUS: - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - default: - create_selected = TRUE; - break; - } - - // Play creation sound - if (gAudiop) - { - gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), - gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - } - - LLUIUsage::instance().logCommand("Build.ObjectAdd"); - gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU8Fast(_PREHASH_Material, material); - - U32 flags = 0; // not selected - if (use_physics) - { - flags |= FLAGS_USE_PHYSICS; - } - if (create_selected) - { - flags |= FLAGS_CREATE_SELECTED; - } - gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); - - LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error - switch (pcode) - { - case LL_PCODE_SPHERE: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_SQUARE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_SPHERE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - //volume_params.setBeginAndEndS( 0.5f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 0.5f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CUBE: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PRISM: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 1 ); - volume_params.setShear ( -0.5f, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PYRAMID: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TETRAHEDRON: - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - default: - LLVolumeMessage::packVolumeParams(0, gMessageSystem); - volume_pcode = pcode; - break; - } - gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); - - gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); - gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); - gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); - gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); - gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); - gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); - gMessageSystem->addU8Fast(_PREHASH_State, state); - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); - - // Pack in name value pairs - gMessageSystem->sendReliable(regionp->getHost()); - - // Spawns a message, so must be after above send - if (create_selected) - { - LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->getWindow()->incBusyCount(); - } - - // VEFFECT: AddObject - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); - effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); - effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); - effectp->setDuration(LL_HUD_DUR_SHORT); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - - add(LLStatViewer::OBJECT_CREATE, 1); - - return TRUE; + + switch (pcode) + { + case LL_PCODE_LEGACY_GRASS: + // Randomize size of grass patch + scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); + state = rand() % LLVOGrass::sMaxGrassSpecies; + break; + + + case LL_PCODE_LEGACY_TREE: + case LL_PCODE_TREE_NEW: + state = rand() % LLVOTree::sMaxTreeSpecies; + break; + + case LL_PCODE_SPHERE: + case LL_PCODE_CONE: + case LL_PCODE_CUBE: + case LL_PCODE_CYLINDER: + case LL_PCODE_TORUS: + case LLViewerObject::LL_VO_SQUARE_TORUS: + case LLViewerObject::LL_VO_TRIANGLE_TORUS: + default: + create_selected = TRUE; + break; + } + + // Play creation sound + if (gAudiop) + { + gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), + gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + } + + LLUIUsage::instance().logCommand("Build.ObjectAdd"); + gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU8Fast(_PREHASH_Material, material); + + U32 flags = 0; // not selected + if (use_physics) + { + flags |= FLAGS_USE_PHYSICS; + } + if (create_selected) + { + flags |= FLAGS_CREATE_SELECTED; + } + gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); + + LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error + switch (pcode) + { + case LL_PCODE_SPHERE: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LLViewerObject::LL_VO_SQUARE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LLViewerObject::LL_VO_TRIANGLE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_SPHERE_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); + //volume_params.setBeginAndEndS( 0.5f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 0.5f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CUBE: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_PRISM: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 1 ); + volume_params.setShear ( -0.5f, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_PYRAMID: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_TETRAHEDRON: + volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CYLINDER: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CYLINDER_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.25f, 0.75f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CONE: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CONE_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.25f, 0.75f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + default: + LLVolumeMessage::packVolumeParams(0, gMessageSystem); + volume_pcode = pcode; + break; + } + gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); + + gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); + gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); + gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); + gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); + gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); + gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); + gMessageSystem->addU8Fast(_PREHASH_State, state); + + // Limit raycast to a single object. + // Speeds up server raycast + avoid problems with server ray hitting objects + // that were clipped by the near plane or culled on the viewer. + LLUUID ray_target_id; + if( hit_obj ) + { + ray_target_id = hit_obj->getID(); + } + else + { + ray_target_id.setNull(); + } + gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); + + // Pack in name value pairs + gMessageSystem->sendReliable(regionp->getHost()); + + // Spawns a message, so must be after above send + if (create_selected) + { + LLSelectMgr::getInstance()->deselectAll(); + gViewerWindow->getWindow()->incBusyCount(); + } + + // VEFFECT: AddObject + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); + effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); + effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + + add(LLStatViewer::OBJECT_CREATE, 1); + + return TRUE; } // Used by the placer tool to add copies of the current selection. // Inspired by add_object(). JC BOOL LLToolPlacer::addDuplicate(S32 x, S32 y) { - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - BOOL b_hit_land = FALSE; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - make_ui_sound("UISndInvalidOp"); - return FALSE; - } - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - make_ui_sound("UISndInvalidOp"); - return FALSE; - } - - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - - LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, - ray_end_region, - b_hit_land, // suppress raycast - FALSE, // intersection - ray_target_id, - gSavedSettings.getBOOL("CreateToolCopyCenters"), - gSavedSettings.getBOOL("CreateToolCopyRotates"), - FALSE); // select copy - - if (regionp - && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) - { - //LLFirstUse::useSandbox(); - } - - return TRUE; + LLVector3 ray_start_region; + LLVector3 ray_end_region; + LLViewerRegion* regionp = NULL; + BOOL b_hit_land = FALSE; + S32 hit_face = -1; + LLViewerObject* hit_obj = NULL; + BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); + if( !success ) + { + make_ui_sound("UISndInvalidOp"); + return FALSE; + } + if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) + { + // Can't create objects on avatars or attachments + make_ui_sound("UISndInvalidOp"); + return FALSE; + } + + + // Limit raycast to a single object. + // Speeds up server raycast + avoid problems with server ray hitting objects + // that were clipped by the near plane or culled on the viewer. + LLUUID ray_target_id; + if( hit_obj ) + { + ray_target_id = hit_obj->getID(); + } + else + { + ray_target_id.setNull(); + } + + LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, + ray_end_region, + b_hit_land, // suppress raycast + FALSE, // intersection + ray_target_id, + gSavedSettings.getBOOL("CreateToolCopyCenters"), + gSavedSettings.getBOOL("CreateToolCopyRotates"), + FALSE); // select copy + + if (regionp + && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) + { + //LLFirstUse::useSandbox(); + } + + return TRUE; } BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) { - BOOL added = TRUE; - - if (gSavedSettings.getBOOL("CreateToolCopySelection")) - { - added = addDuplicate(x, y); - } - else - { - added = addObject( sObjectType, x, y, FALSE ); - } - - // ...and go back to the default tool - if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) - { - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); - } - - return added; + BOOL added = TRUE; + + if (gSavedSettings.getBOOL("CreateToolCopySelection")) + { + added = addDuplicate(x, y); + } + else + { + added = addObject( sObjectType, x, y, FALSE ); + } + + // ...and go back to the default tool + if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) + { + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); + } + + return added; } BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask) { - LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; - gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); - return TRUE; + LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; + gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); + return TRUE; } void LLToolPlacer::handleSelect() { - gFloaterTools->setStatusText("place"); + gFloaterTools->setStatusText("place"); } void LLToolPlacer::handleDeselect() diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index d20d682710..8b56790f7d 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -1,25 +1,25 @@ -/** +/** * @file lltoolplacer.h * @brief Tool for placing new objects into the world * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,31 +37,31 @@ class LLViewerRegion; // LLToolPlacer class LLToolPlacer - : public LLTool + : public LLTool { public: - LLToolPlacer(); + LLToolPlacer(); - virtual BOOL placeObject(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual void handleSelect(); // do stuff when your tool is selected - virtual void handleDeselect(); // clean up when your tool is deselected + virtual BOOL placeObject(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual void handleSelect(); // do stuff when your tool is selected + virtual void handleDeselect(); // clean up when your tool is deselected - static void setObjectType( LLPCode type ) { sObjectType = type; } - static LLPCode getObjectType() { return sObjectType; } + static void setObjectType( LLPCode type ) { sObjectType = type; } + static LLPCode getObjectType() { return sObjectType; } static BOOL addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics); static BOOL rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion *regionp, U8 use_physics); protected: - static LLPCode sObjectType; + static LLPCode sObjectType; private: - - static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, - BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); - BOOL addDuplicate(S32 x, S32 y); + + static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, + BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); + BOOL addDuplicate(S32 x, S32 y); }; #endif diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 16c4084a77..4e39b03903 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2009-07-09 * @brief Implementation for llviewercontrollistener. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,182 +44,182 @@ LLViewerControlListener sSavedSettingsListener; } // unnamed namespace LLViewerControlListener::LLViewerControlListener() - : LLEventAPI("LLViewerControl", - "LLViewerControl listener: set, toggle or set default for various controls") + : LLEventAPI("LLViewerControl", + "LLViewerControl listener: set, toggle or set default for various controls") { - std::ostringstream groupnames; - groupnames << "[\"group\"] is one of "; - const char* delim = ""; - for (const auto& key : LLControlGroup::key_snapshot()) - { - groupnames << delim << '"' << key << '"'; - delim = ", "; - } - groupnames << '\n'; - std::string grouphelp(groupnames.str()); - std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); - - add("set", - std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" - "If [\"value\"] omitted, set to control's defined default value\n") + - grouphelp + replyhelp, - &LLViewerControlListener::set, - LLSDMap("group", LLSD())("key", LLSD())); - add("toggle", - std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, - &LLViewerControlListener::toggle, - LLSDMap("group", LLSD())("key", LLSD())); - add("get", - std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + - grouphelp, - &LLViewerControlListener::get, - LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); - add("groups", - "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", - &LLViewerControlListener::groups, - LLSDMap("reply", LLSD())); - add("vars", - std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" - "each of whose entries looks like:\n" - " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, - &LLViewerControlListener::vars, - LLSDMap("group", LLSD())("reply", LLSD())); + std::ostringstream groupnames; + groupnames << "[\"group\"] is one of "; + const char* delim = ""; + for (const auto& key : LLControlGroup::key_snapshot()) + { + groupnames << delim << '"' << key << '"'; + delim = ", "; + } + groupnames << '\n'; + std::string grouphelp(groupnames.str()); + std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); + + add("set", + std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" + "If [\"value\"] omitted, set to control's defined default value\n") + + grouphelp + replyhelp, + &LLViewerControlListener::set, + LLSDMap("group", LLSD())("key", LLSD())); + add("toggle", + std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, + &LLViewerControlListener::toggle, + LLSDMap("group", LLSD())("key", LLSD())); + add("get", + std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + + grouphelp, + &LLViewerControlListener::get, + LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); + add("groups", + "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", + &LLViewerControlListener::groups, + LLSDMap("reply", LLSD())); + add("vars", + std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" + "each of whose entries looks like:\n" + " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, + &LLViewerControlListener::vars, + LLSDMap("group", LLSD())("reply", LLSD())); } struct Info { - Info(const LLSD& request): - response(LLSD(), request), - groupname(request["group"]), - group(LLControlGroup::getInstance(groupname)), - key(request["key"]), - control(NULL) - { - if (! group) - { - response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); - return; - } - - control = group->getControl(key); - if (! control) - { - response.error(STRINGIZE("In group '" << groupname - << "', unrecognized control key '" << key << "'")); - } - } - - ~Info() - { - // If in fact the request passed to our constructor names a valid - // group and key, grab the final value of the indicated control and - // stuff it in our response. Since this outer destructor runs before - // the contained Response destructor, this data will go into the - // response we send. - if (control) - { - response["name"] = control->getName(); - response["type"] = LLControlGroup::typeEnumToString(control->type()); - response["value"] = control->get(); - response["comment"] = control->getComment(); - } - } - - LLEventAPI::Response response; - std::string groupname; - LLControlGroup::ptr_t group; - std::string key; - LLControlVariable* control; + Info(const LLSD& request): + response(LLSD(), request), + groupname(request["group"]), + group(LLControlGroup::getInstance(groupname)), + key(request["key"]), + control(NULL) + { + if (! group) + { + response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); + return; + } + + control = group->getControl(key); + if (! control) + { + response.error(STRINGIZE("In group '" << groupname + << "', unrecognized control key '" << key << "'")); + } + } + + ~Info() + { + // If in fact the request passed to our constructor names a valid + // group and key, grab the final value of the indicated control and + // stuff it in our response. Since this outer destructor runs before + // the contained Response destructor, this data will go into the + // response we send. + if (control) + { + response["name"] = control->getName(); + response["type"] = LLControlGroup::typeEnumToString(control->type()); + response["value"] = control->get(); + response["comment"] = control->getComment(); + } + } + + LLEventAPI::Response response; + std::string groupname; + LLControlGroup::ptr_t group; + std::string key; + LLControlVariable* control; }; //static void LLViewerControlListener::set(LLSD const & request) { - Info info(request); - if (! info.control) - return; + Info info(request); + if (! info.control) + return; - if (request.has("value")) - { + if (request.has("value")) + { LL_WARNS("LLViewerControlListener") << "Changing debug setting " << std::quoted(info.key) << " to " << request["value"] << LL_ENDL; - info.control->setValue(request["value"], false); - } - else - { - info.control->resetToDefault(); - } + info.control->setValue(request["value"], false); + } + else + { + info.control->resetToDefault(); + } } //static void LLViewerControlListener::toggle(LLSD const & request) { - Info info(request); - if (! info.control) - return; + Info info(request); + if (! info.control) + return; - if (info.control->isType(TYPE_BOOLEAN)) - { + if (info.control->isType(TYPE_BOOLEAN)) + { bool value = !info.control->get().asBoolean(); LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << " to " << value << LL_ENDL; info.control->set(value, false); - } - else - { - info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname - << "' control '" << info.key - << "', type is " - << LLControlGroup::typeEnumToString(info.control->type()))); - } + } + else + { + info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname + << "' control '" << info.key + << "', type is " + << LLControlGroup::typeEnumToString(info.control->type()))); + } } void LLViewerControlListener::get(LLSD const & request) { - // The Info constructor and destructor actually do all the work here. - Info info(request); + // The Info constructor and destructor actually do all the work here. + Info info(request); } void LLViewerControlListener::groups(LLSD const & request) { - // No Info, we're not looking up either a group or a control name. - Response response(LLSD(), request); - for (const auto& key : LLControlGroup::key_snapshot()) - { - response["groups"].append(key); - } + // No Info, we're not looking up either a group or a control name. + Response response(LLSD(), request); + for (const auto& key : LLControlGroup::key_snapshot()) + { + response["groups"].append(key); + } } struct CollectVars: public LLControlGroup::ApplyFunctor { - CollectVars(LLControlGroup::ptr_t g): - mGroup(g) - {} - - virtual void apply(const std::string& name, LLControlVariable* control) - { - vars.append(LLSDMap - ("name", name) - ("type", LLControlGroup::typeEnumToString(control->type())) - ("value", control->get()) - ("comment", control->getComment())); - } - - LLControlGroup::ptr_t mGroup; - LLSD vars; + CollectVars(LLControlGroup::ptr_t g): + mGroup(g) + {} + + virtual void apply(const std::string& name, LLControlVariable* control) + { + vars.append(LLSDMap + ("name", name) + ("type", LLControlGroup::typeEnumToString(control->type())) + ("value", control->get()) + ("comment", control->getComment())); + } + + LLControlGroup::ptr_t mGroup; + LLSD vars; }; void LLViewerControlListener::vars(LLSD const & request) { - // This method doesn't use Info, because we're not looking up a specific - // control name. - Response response(LLSD(), request); - std::string groupname(request["group"]); - auto group(LLControlGroup::getInstance(groupname)); - if (! group) - { - return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); - } - - CollectVars collector(group); - group->applyToAll(&collector); - response["vars"] = collector.vars; + // This method doesn't use Info, because we're not looking up a specific + // control name. + Response response(LLSD(), request); + std::string groupname(request["group"]); + auto group(LLControlGroup::getInstance(groupname)); + if (! group) + { + return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); + } + + CollectVars collector(group); + group->applyToAll(&collector); + response["vars"] = collector.vars; } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 60add691c5..67da34e071 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerfloaterreg.cpp * @brief LLViewerFloaterReg class registers floaters used in the viewer * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -182,8 +182,8 @@ const std::string FLOATER_PROFILE("profile"); class LLFloaterOpenHandler : public LLCommandHandler { public: - // requires trusted browser to trigger or an explicit click - LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } + // requires trusted browser to trigger or an explicit click + LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } bool canHandleUntrusted( const LLSD& params, @@ -195,7 +195,7 @@ public: { return true; // will fail silently } - + std::string fl_name = params[0].asString(); // External browsers explicitly ask user about opening links @@ -282,237 +282,237 @@ public: return true; } - bool handle( + bool handle( const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) override - { - if (params.size() != 1) - { - return false; - } + { + if (params.size() != 1) + { + return false; + } - const std::string floater_name = LLURI::unescape(params[0].asString()); + const std::string floater_name = LLURI::unescape(params[0].asString()); LLSD key; if (floater_name == FLOATER_PROFILE) { key["id"] = gAgentID; } - LLFloaterReg::showInstance(floater_name, key); + LLFloaterReg::showInstance(floater_name, key); - return true; - } + return true; + } }; LLFloaterOpenHandler gFloaterOpenHandler; void LLViewerFloaterReg::registerFloaters() { - if (gNonInteractive) - { - return; - } - // *NOTE: Please keep these alphabetized for easier merges - - LLFloaterAboutUtil::registerFloater(); - LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater360Capture>); - LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFastTimerView>); - LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLand>); - LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAddPaymentMethod>); - LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAssociateListing>); - LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAuction>); - LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatar>); - LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarPicker>); - LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarRenderSettings>); - LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarTextures>); - - LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build<LLFloaterBanDuration>); - LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBeacons>); - LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBulkPermission>); - LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); - LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyCurrencyHTML>); - LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); - LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuy>); - LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyContents>); - LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTools>); - LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuildOptions>); - LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); - - LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>); - LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>); - LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); + if (gNonInteractive) + { + return; + } + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterAboutUtil::registerFloater(); + LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater360Capture>); + LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFastTimerView>); + LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLand>); + LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAddPaymentMethod>); + LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAssociateListing>); + LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAuction>); + LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatar>); + LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarPicker>); + LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarRenderSettings>); + LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarTextures>); + + LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build<LLFloaterBanDuration>); + LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBeacons>); + LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBulkPermission>); + LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); + LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyCurrencyHTML>); + LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); + LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuy>); + LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyContents>); + LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTools>); + LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuildOptions>); + LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); + + LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>); + LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>); + LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); LLFloaterReg::add("change_item_thumbnail", "floater_change_item_thumbnail.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChangeItemThumbnail>); - LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); - LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>); - LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); - LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>); - LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>); - - LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>); - LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); - - LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>); - LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>); - LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); - - LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); - LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); - - LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); - - LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); - LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); - - LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); - LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>); - LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperienceProfile>); - LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); - - LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); - LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); - - LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); - LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); - LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGridStatus>); - LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>); - - LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>); - LLFloaterReg::add("edit_hover_height", "floater_edit_hover_height.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHoverHeight>); - LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); - - LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMSession>); - LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMContainer>); - LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>); - LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); - LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); + LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); + LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>); + LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); + LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>); + LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>); + + LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>); + LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); + + LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>); + LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>); + LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); + + LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); + LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); + + LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); + + LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); + LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); + + LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); + LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>); + LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperienceProfile>); + LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); + + LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); + + LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); + LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); + LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGridStatus>); + LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>); + + LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>); + LLFloaterReg::add("edit_hover_height", "floater_edit_hover_height.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHoverHeight>); + LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); + + LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMSession>); + LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterIMContainer>); + LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>); + LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); + LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); LLFloaterReg::add("inventory_thumbnails_helper", "floater_inventory_thumbnails_helper.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterInventoryThumbnailsHelper>); - LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>); + LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>); LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>); LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventorySettings>); - LLInspectAvatarUtil::registerFloater(); - LLInspectGroupUtil::registerFloater(); - LLInspectObjectUtil::registerFloater(); - LLInspectRemoteObjectUtil::registerFloater(); - LLFloaterVoiceVolumeUtil::registerFloater(); - LLNotificationsUI::registerFloater(); - LLFloaterDisplayNameUtil::registerFloater(); - - LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>); - LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); - LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLinkReplace>); - LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>); + LLInspectAvatarUtil::registerFloater(); + LLInspectGroupUtil::registerFloater(); + LLInspectObjectUtil::registerFloater(); + LLInspectRemoteObjectUtil::registerFloater(); + LLFloaterVoiceVolumeUtil::registerFloater(); + LLNotificationsUI::registerFloater(); + LLFloaterDisplayNameUtil::registerFloater(); + + LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>); + LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); + LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLinkReplace>); + LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>); LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUADebug>); LLFloaterReg::add("lua_scripts", "floater_lua_scripts.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUAScripts>); - - LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); - - LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>); - LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>); - LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>); - LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); - LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); - LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); - LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); - LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); + + LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); + + LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>); + LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>); + LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>); + LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); + LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); + LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); + LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); + LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); LLFloaterReg::add("new_feature_notification", "floater_new_feature_notification.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNewFeatureNotification>); - LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); - - LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>); - - LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>); - LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); - LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); - LLFloaterPayUtil::registerFloater(); - - LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>); - LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); - LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); - LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerformance>); - LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPermsDefault>); - LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); - LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); - LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceGraphicsAdvanced>); - LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceViewAdvanced>); - LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>); - LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>); - LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>); - LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>); - LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>); - LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>); - LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewAnim>, "preview"); - LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationPreview>); - LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewGesture>, "preview"); - LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewNotecard>, "preview"); - LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewLSL>, "preview"); - LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLLiveLSLEditor>, "preview"); - LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewSound>, "preview"); - LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewTexture>, "preview"); - LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreviewTrash>); - LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>); - LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>); - LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>); - LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>); + LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); + + LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>); + + LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>); + LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); + LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); + LLFloaterPayUtil::registerFloater(); + + LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>); + LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); + LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); + LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerformance>); + LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPermsDefault>); + LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); + LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceGraphicsAdvanced>); + LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceViewAdvanced>); + LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>); + LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>); + LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>); + LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>); + LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>); + LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>); + LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewAnim>, "preview"); + LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationPreview>); + LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewGesture>, "preview"); + LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewNotecard>, "preview"); + LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewLSL>, "preview"); + LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLLiveLSLEditor>, "preview"); + LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewSound>, "preview"); + LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewTexture>, "preview"); + LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreviewTrash>); + LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>); + LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>); + LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>); + LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>); LLFloaterReg::add("material_editor", "floater_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLMaterialEditor>); LLFloaterReg::add("live_material_editor", "floater_live_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLMaterialEditor>); - - LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>); - LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build<LLFloaterTestInspectors>); - //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build<LLFloaterTestListView>); - LLFloaterReg::add("test_textbox", "floater_test_textbox.xml", &LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("test_text_editor", "floater_test_text_editor.xml", &LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTopObjects>); - LLFloaterReg::add("toybox", "floater_toybox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterToybox>); - - LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>); - LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>); - LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); - LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); - LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); - - LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); - LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); - LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); - LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptLimits>); - LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyScripts>); - LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); - LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>); - LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>); - LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>); - LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>); - LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>); - LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>); - LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>); + + LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>); + LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build<LLFloaterTestInspectors>); + //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build<LLFloaterTestListView>); + LLFloaterReg::add("test_textbox", "floater_test_textbox.xml", &LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("test_text_editor", "floater_test_text_editor.xml", &LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTopObjects>); + LLFloaterReg::add("toybox", "floater_toybox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterToybox>); + + LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>); + LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>); + LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); + LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); + LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); + + LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); + LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); + LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); + LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptLimits>); + LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyScripts>); + LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); + LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>); + LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>); + LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>); + LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>); + LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>); + LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>); + LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>); LLFloaterReg::add("simple_snapshot", "floater_simple_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleSnapshot>); LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>); LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProfile>); - LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>); - - LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>); - - LLFloaterUIPreviewUtil::registerFloater(); - LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload"); - LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); - LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); - LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); - LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptPreview>, "upload"); - LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); - - LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); - - LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); - LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); - LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build<LLFloaterWindowSize>); - LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); - - // *NOTE: Please keep these alphabetized for easier merges - - LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving + LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>); + + LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBigPreview>); + + LLFloaterUIPreviewUtil::registerFloater(); + LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload"); + LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); + LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); + LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); + LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptPreview>, "upload"); + LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); + + LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); + + LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); + LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); + LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build<LLFloaterWindowSize>); + LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); + + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 52128a09ab..9f43fa1ac2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenu.cpp * @brief Builds menus out of items. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,7 +30,7 @@ #include "vld.h" #endif -#include "llviewermenu.h" +#include "llviewermenu.h" // linden library includes #include "llavatarnamecache.h" // IDEVO (I Are Not Men!) @@ -115,7 +115,7 @@ #include "llviewerdisplay.h" //for gWindowResized #include "llviewergenericmessage.h" #include "llviewerhelp.h" -#include "llviewermenufile.h" // init_menu_file() +#include "llviewermenufile.h" // init_menu_file() #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" @@ -159,7 +159,7 @@ void handle_test_load_url(void*); // // Evil hackish imported globals -//extern BOOL gHideSelectedObjects; +//extern BOOL gHideSelectedObjects; //extern BOOL gAllowSelectAvatar; //extern BOOL gDebugAvatarRotation; extern BOOL gDebugClicks; @@ -175,20 +175,20 @@ extern BOOL gShaderProfileFrame; LLUIListener sUIListener; -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuGL *gPopupMenuView = NULL; -LLMenuGL *gEditMenu = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; +LLMenuBarGL *gMenuBarView = NULL; +LLViewerMenuHolderGL *gMenuHolder = NULL; +LLMenuGL *gPopupMenuView = NULL; +LLMenuGL *gEditMenu = NULL; +LLMenuBarGL *gLoginMenuBarView = NULL; // Pie menus -LLContextMenu *gMenuAvatarSelf = NULL; -LLContextMenu *gMenuAvatarOther = NULL; -LLContextMenu *gMenuObject = NULL; -LLContextMenu *gMenuAttachmentSelf = NULL; -LLContextMenu *gMenuAttachmentOther = NULL; -LLContextMenu *gMenuLand = NULL; -LLContextMenu *gMenuMuteParticle = NULL; +LLContextMenu *gMenuAvatarSelf = NULL; +LLContextMenu *gMenuAvatarOther = NULL; +LLContextMenu *gMenuObject = NULL; +LLContextMenu *gMenuAttachmentSelf = NULL; +LLContextMenu *gMenuAttachmentOther = NULL; +LLContextMenu *gMenuLand = NULL; +LLContextMenu *gMenuMuteParticle = NULL; const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); @@ -286,7 +286,7 @@ void handle_force_parcel_owner_to_me(void*); void handle_force_parcel_to_content(void*); void handle_claim_public_land(void*); -void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry +void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry void reload_vertex_shader(void *); void handle_disconnect_viewer(void *); @@ -346,26 +346,26 @@ void menu_toggle_attached_particles(void* user_data); class LLMenuParcelObserver : public LLParcelObserver { public: - LLMenuParcelObserver(); - ~LLMenuParcelObserver(); - virtual void changed(); + LLMenuParcelObserver(); + ~LLMenuParcelObserver(); + virtual void changed(); }; static LLMenuParcelObserver* gMenuParcelObserver = NULL; LLMenuParcelObserver::LLMenuParcelObserver() { - LLViewerParcelMgr::getInstance()->addObserver(this); + LLViewerParcelMgr::getInstance()->addObserver(this); } LLMenuParcelObserver::~LLMenuParcelObserver() { - LLViewerParcelMgr::getInstance()->removeObserver(this); + LLViewerParcelMgr::getInstance()->removeObserver(this); } void LLMenuParcelObserver::changed() { - LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); if (gMenuLand && parcel) { LLView* child = gMenuLand->findChild<LLView>("Land Buy Pass"); @@ -438,131 +438,131 @@ void check_merchant_status(bool force) void init_menus() { - // Initialize actions - initialize_menus(); - - /// - /// Popup menu - /// - /// The popup menu is now populated by the show_context_menu() - /// method. - - LLMenuGL::Params menu_params; - menu_params.name = "Popup"; - menu_params.visible = false; - gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params); - gMenuHolder->addChild( gPopupMenuView ); - - /// - /// Context menus - /// - - const widget_registry_t& registry = - LLViewerMenuHolderGL::child_registry_t::instance(); - gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry); - gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_avatar_self.xml", gMenuHolder, registry); - gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_avatar_other.xml", gMenuHolder, registry); - - gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true); - gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true); - - gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_object.xml", gMenuHolder, registry); - - gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD"); - gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach"); - - gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_attachment_self.xml", gMenuHolder, registry); - gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_attachment_other.xml", gMenuHolder, registry); - - gDetachHUDAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self HUD", true); - gDetachAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self", true); - - gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_land.xml", gMenuHolder, registry); - - gMenuMuteParticle = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_mute_particle.xml", gMenuHolder, registry); - - /// - /// set up the colors - /// - LLColor4 color; - - LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); - - gMenuAvatarSelf->setBackgroundColor( context_menu_color ); - gMenuAvatarOther->setBackgroundColor( context_menu_color ); - gMenuObject->setBackgroundColor( context_menu_color ); - gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); - gMenuAttachmentOther->setBackgroundColor( context_menu_color ); - - gMenuLand->setBackgroundColor( context_menu_color ); - - color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); - gPopupMenuView->setBackgroundColor( color ); - - // If we are not in production, use a different color to make it apparent. - if (LLGridManager::getInstance()->isInProductionGrid()) - { - color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); - } - else - { - color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); - } - - LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); - - gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); - gMenuBarView->setBackgroundColor( color ); - - menu_bar_holder->addChild(gMenuBarView); - - gViewerWindow->setMenuBackgroundColor(false, + // Initialize actions + initialize_menus(); + + /// + /// Popup menu + /// + /// The popup menu is now populated by the show_context_menu() + /// method. + + LLMenuGL::Params menu_params; + menu_params.name = "Popup"; + menu_params.visible = false; + gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params); + gMenuHolder->addChild( gPopupMenuView ); + + /// + /// Context menus + /// + + const widget_registry_t& registry = + LLViewerMenuHolderGL::child_registry_t::instance(); + gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry); + gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_avatar_self.xml", gMenuHolder, registry); + gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_avatar_other.xml", gMenuHolder, registry); + + gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true); + gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true); + + gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_object.xml", gMenuHolder, registry); + + gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD"); + gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach"); + + gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_attachment_self.xml", gMenuHolder, registry); + gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_attachment_other.xml", gMenuHolder, registry); + + gDetachHUDAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self HUD", true); + gDetachAttSelfMenu = gMenuHolder->getChild<LLContextMenu>("Detach Self", true); + + gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_land.xml", gMenuHolder, registry); + + gMenuMuteParticle = LLUICtrlFactory::createFromFile<LLContextMenu>( + "menu_mute_particle.xml", gMenuHolder, registry); + + /// + /// set up the colors + /// + LLColor4 color; + + LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); + + gMenuAvatarSelf->setBackgroundColor( context_menu_color ); + gMenuAvatarOther->setBackgroundColor( context_menu_color ); + gMenuObject->setBackgroundColor( context_menu_color ); + gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); + gMenuAttachmentOther->setBackgroundColor( context_menu_color ); + + gMenuLand->setBackgroundColor( context_menu_color ); + + color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); + gPopupMenuView->setBackgroundColor( color ); + + // If we are not in production, use a different color to make it apparent. + if (LLGridManager::getInstance()->isInProductionGrid()) + { + color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); + } + else + { + color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); + } + + LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); + + gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); + gMenuBarView->setBackgroundColor( color ); + + menu_bar_holder->addChild(gMenuBarView); + + gViewerWindow->setMenuBackgroundColor(false, LLGridManager::getInstance()->isInProductionGrid()); - // *TODO:Also fix cost in llfolderview.cpp for Inventory menus - const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); - const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); - const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); - - gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); - gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); - - gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true); - gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true); - - // Don't display the Memory console menu if the feature is turned off - LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); - if (memoryMenu) - { - memoryMenu->setVisible(FALSE); - } - - gMenuBarView->createJumpKeys(); - - // Let land based option enable when parcel changes - gMenuParcelObserver = new LLMenuParcelObserver(); - - gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gLoginMenuBarView->arrangeAndClear(); - LLRect menuBarRect = gLoginMenuBarView->getRect(); - menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); - gLoginMenuBarView->setRect(menuBarRect); - gLoginMenuBarView->setBackgroundColor( color ); - menu_bar_holder->addChild(gLoginMenuBarView); - - // tooltips are on top of EVERYTHING, including menus - gViewerWindow->getRootView()->sendChildToFront(gToolTipView); + // *TODO:Also fix cost in llfolderview.cpp for Inventory menus + const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); + const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); + const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); + gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); + + gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); + gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); + + gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true); + gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true); + + // Don't display the Memory console menu if the feature is turned off + LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); + if (memoryMenu) + { + memoryMenu->setVisible(FALSE); + } + + gMenuBarView->createJumpKeys(); + + // Let land based option enable when parcel changes + gMenuParcelObserver = new LLMenuParcelObserver(); + + gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gLoginMenuBarView->arrangeAndClear(); + LLRect menuBarRect = gLoginMenuBarView->getRect(); + menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); + gLoginMenuBarView->setRect(menuBarRect); + gLoginMenuBarView->setBackgroundColor( color ); + menu_bar_holder->addChild(gLoginMenuBarView); + + // tooltips are on top of EVERYTHING, including menus + gViewerWindow->getRootView()->sendChildToFront(gToolTipView); } /////////////////// @@ -572,62 +572,62 @@ void init_menus() class LLAdvancedToggleConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - if ("texture" == console_type) - { - toggle_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep)); - } - else if ("fast timers" == console_type) - { - LLFloaterReg::toggleInstance("block_timers"); - } - else if ("scene view" == console_type) - { - toggle_visibility( (void*)gSceneView); - } - else if ("scene monitor" == console_type) - { - toggle_visibility( (void*)gSceneMonitorView); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string console_type = userdata.asString(); + if ("texture" == console_type) + { + toggle_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep)); + } + else if ("fast timers" == console_type) + { + LLFloaterReg::toggleInstance("block_timers"); + } + else if ("scene view" == console_type) + { + toggle_visibility( (void*)gSceneView); + } + else if ("scene monitor" == console_type) + { + toggle_visibility( (void*)gSceneMonitorView); + } + + return true; + } }; class LLAdvancedCheckConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - bool new_value = false; - if ("texture" == console_type) - { - new_value = get_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); - } - else if ("fast timers" == console_type) - { - new_value = LLFloaterReg::instanceVisible("block_timers"); - } - else if ("scene view" == console_type) - { - new_value = get_visibility( (void*) gSceneView); - } - else if ("scene monitor" == console_type) - { - new_value = get_visibility( (void*) gSceneMonitorView); - } - - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string console_type = userdata.asString(); + bool new_value = false; + if ("texture" == console_type) + { + new_value = get_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); + } + else if ("fast timers" == console_type) + { + new_value = LLFloaterReg::instanceVisible("block_timers"); + } + else if ("scene view" == console_type) + { + new_value = get_visibility( (void*) gSceneView); + } + else if ("scene monitor" == console_type) + { + new_value = get_visibility( (void*) gSceneMonitorView); + } + + return new_value; + } }; @@ -638,24 +638,24 @@ class LLAdvancedCheckConsole : public view_listener_t class LLAdvancedDumpInfoToConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugView->mDebugConsolep->setVisible(TRUE); - std::string info_type = userdata.asString(); - if ("region" == info_type) - { - handle_region_dump_settings(NULL); - } - else if ("group" == info_type) - { - handle_dump_group_info(NULL); - } - else if ("capabilities" == info_type) - { - handle_dump_capabilities_info(NULL); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugView->mDebugConsolep->setVisible(TRUE); + std::string info_type = userdata.asString(); + if ("region" == info_type) + { + handle_region_dump_settings(NULL); + } + else if ("group" == info_type) + { + handle_dump_group_info(NULL); + } + else if ("capabilities" == info_type) + { + handle_dump_capabilities_info(NULL); + } + return true; + } }; @@ -666,54 +666,54 @@ class LLAdvancedDumpInfoToConsole : public view_listener_t class LLAdvancedToggleHUDInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - - if ("camera" == info_type) - { - gDisplayCameraPos = !(gDisplayCameraPos); - } - else if ("wind" == info_type) - { - gDisplayWindInfo = !(gDisplayWindInfo); - } - else if ("fov" == info_type) - { - gDisplayFOV = !(gDisplayFOV); - } - else if ("badge" == info_type) - { - gDisplayBadge = !(gDisplayBadge); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + + if ("camera" == info_type) + { + gDisplayCameraPos = !(gDisplayCameraPos); + } + else if ("wind" == info_type) + { + gDisplayWindInfo = !(gDisplayWindInfo); + } + else if ("fov" == info_type) + { + gDisplayFOV = !(gDisplayFOV); + } + else if ("badge" == info_type) + { + gDisplayBadge = !(gDisplayBadge); + } + return true; + } }; class LLAdvancedCheckHUDInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - bool new_value = false; - if ("camera" == info_type) - { - new_value = gDisplayCameraPos; - } - else if ("wind" == info_type) - { - new_value = gDisplayWindInfo; - } - else if ("fov" == info_type) - { - new_value = gDisplayFOV; - } - else if ("badge" == info_type) - { - new_value = gDisplayBadge; - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + bool new_value = false; + if ("camera" == info_type) + { + new_value = gDisplayCameraPos; + } + else if ("wind" == info_type) + { + new_value = gDisplayWindInfo; + } + else if ("fov" == info_type) + { + new_value = gDisplayFOV; + } + else if ("badge" == info_type) + { + new_value = gDisplayBadge; + } + return new_value; + } }; @@ -723,11 +723,11 @@ class LLAdvancedCheckHUDInfo : public view_listener_t class LLAdvancedClearGroupCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLGroupMgr::debugClearAllGroups(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLGroupMgr::debugClearAllGroups(NULL); + return true; + } }; @@ -738,97 +738,97 @@ class LLAdvancedClearGroupCache : public view_listener_t ///////////////// U32 render_type_from_string(std::string render_type) { - if ("simple" == render_type) - { - return LLPipeline::RENDER_TYPE_SIMPLE; - } - else if ("alpha" == render_type) - { - return LLPipeline::RENDER_TYPE_ALPHA; - } - else if ("tree" == render_type) - { - return LLPipeline::RENDER_TYPE_TREE; - } - else if ("character" == render_type) - { - return LLPipeline::RENDER_TYPE_AVATAR; - } - else if ("controlAV" == render_type) // Animesh - { - return LLPipeline::RENDER_TYPE_CONTROL_AV; - } - else if ("surfacePatch" == render_type) - { - return LLPipeline::RENDER_TYPE_TERRAIN; - } - else if ("sky" == render_type) - { - return LLPipeline::RENDER_TYPE_SKY; - } - else if ("water" == render_type) - { - return LLPipeline::RENDER_TYPE_WATER; - } - else if ("volume" == render_type) - { - return LLPipeline::RENDER_TYPE_VOLUME; - } - else if ("grass" == render_type) - { - return LLPipeline::RENDER_TYPE_GRASS; - } - else if ("clouds" == render_type) - { - return LLPipeline::RENDER_TYPE_CLOUDS; - } - else if ("particles" == render_type) - { - return LLPipeline::RENDER_TYPE_PARTICLES; - } - else if ("bump" == render_type) - { - return LLPipeline::RENDER_TYPE_BUMP; - } - else if ("pbr" == render_type) + if ("simple" == render_type) + { + return LLPipeline::RENDER_TYPE_SIMPLE; + } + else if ("alpha" == render_type) + { + return LLPipeline::RENDER_TYPE_ALPHA; + } + else if ("tree" == render_type) + { + return LLPipeline::RENDER_TYPE_TREE; + } + else if ("character" == render_type) + { + return LLPipeline::RENDER_TYPE_AVATAR; + } + else if ("controlAV" == render_type) // Animesh + { + return LLPipeline::RENDER_TYPE_CONTROL_AV; + } + else if ("surfacePatch" == render_type) + { + return LLPipeline::RENDER_TYPE_TERRAIN; + } + else if ("sky" == render_type) + { + return LLPipeline::RENDER_TYPE_SKY; + } + else if ("water" == render_type) + { + return LLPipeline::RENDER_TYPE_WATER; + } + else if ("volume" == render_type) + { + return LLPipeline::RENDER_TYPE_VOLUME; + } + else if ("grass" == render_type) + { + return LLPipeline::RENDER_TYPE_GRASS; + } + else if ("clouds" == render_type) + { + return LLPipeline::RENDER_TYPE_CLOUDS; + } + else if ("particles" == render_type) + { + return LLPipeline::RENDER_TYPE_PARTICLES; + } + else if ("bump" == render_type) + { + return LLPipeline::RENDER_TYPE_BUMP; + } + else if ("pbr" == render_type) { return LLPipeline::RENDER_TYPE_GLTF_PBR; } - else - { - return 0; - } + else + { + return 0; + } } class LLAdvancedToggleRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - if ( render_type != 0 ) - { - LLPipeline::toggleRenderTypeControl( render_type ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + if ( render_type != 0 ) + { + LLPipeline::toggleRenderTypeControl( render_type ); + } + return true; + } }; class LLAdvancedCheckRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - bool new_value = false; + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + bool new_value = false; - if ( render_type != 0 ) - { - new_value = LLPipeline::hasRenderTypeControl( render_type ); - } + if ( render_type != 0 ) + { + new_value = LLPipeline::hasRenderTypeControl( render_type ); + } - return new_value; - } + return new_value; + } }; @@ -836,140 +836,140 @@ class LLAdvancedCheckRenderType : public view_listener_t // FEATURE // ///////////// U32 feature_from_string(std::string feature) -{ - if ("ui" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_UI; - } - else if ("selected" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; - } - else if ("highlighted" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; - } - else if ("dynamic textures" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; - } - else if ("foot shadows" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; - } - else if ("fog" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOG; - } - else if ("fr info" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; - } - else if ("flexible" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; - } - else - { - return 0; - } +{ + if ("ui" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_UI; + } + else if ("selected" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; + } + else if ("highlighted" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; + } + else if ("dynamic textures" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; + } + else if ("foot shadows" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; + } + else if ("fog" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOG; + } + else if ("fr info" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; + } + else if ("flexible" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; + } + else + { + return 0; + } }; class LLAdvancedToggleFeature : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 feature = feature_from_string( userdata.asString() ); - if ( feature != 0 ) - { - LLPipeline::toggleRenderDebugFeature( feature ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 feature = feature_from_string( userdata.asString() ); + if ( feature != 0 ) + { + LLPipeline::toggleRenderDebugFeature( feature ); + } + return true; + } }; class LLAdvancedCheckFeature : public view_listener_t { - bool handleEvent(const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - U32 feature = feature_from_string( userdata.asString() ); - bool new_value = false; + U32 feature = feature_from_string( userdata.asString() ); + bool new_value = false; - if ( feature != 0 ) - { - new_value = LLPipeline::toggleRenderDebugFeatureControl( feature ); - } + if ( feature != 0 ) + { + new_value = LLPipeline::toggleRenderDebugFeatureControl( feature ); + } - return new_value; + return new_value; } }; class LLAdvancedCheckDisplayTextureDensity : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string mode = userdata.asString(); - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) - { - return mode == "none"; - } - if (mode == "current") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_CURRENT; - } - else if (mode == "desired") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_DESIRED; - } - else if (mode == "full") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_FULL; - } - return false; - } + bool handleEvent(const LLSD& userdata) + { + std::string mode = userdata.asString(); + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) + { + return mode == "none"; + } + if (mode == "current") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_CURRENT; + } + else if (mode == "desired") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_DESIRED; + } + else if (mode == "full") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_FULL; + } + return false; + } }; class LLAdvancedSetDisplayTextureDensity : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string mode = userdata.asString(); - if (mode == "none") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == TRUE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; - } - else if (mode == "current") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_CURRENT; - } - else if (mode == "desired") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY, true); - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_DESIRED; - } - else if (mode == "full") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_FULL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string mode = userdata.asString(); + if (mode == "none") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == TRUE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; + } + else if (mode == "current") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_CURRENT; + } + else if (mode == "desired") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY, true); + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_DESIRED; + } + else if (mode == "full") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_FULL; + } + return true; + } }; @@ -978,232 +978,232 @@ class LLAdvancedSetDisplayTextureDensity : public view_listener_t ////////////////// U64 info_display_from_string(std::string info_display) { - if ("verify" == info_display) - { - return LLPipeline::RENDER_DEBUG_VERIFY; - } - else if ("bboxes" == info_display) - { - return LLPipeline::RENDER_DEBUG_BBOXES; - } - else if ("normals" == info_display) - { - return LLPipeline::RENDER_DEBUG_NORMALS; - } - else if ("points" == info_display) - { - return LLPipeline::RENDER_DEBUG_POINTS; - } - else if ("octree" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCTREE; - } - else if ("shadow frusta" == info_display) - { - return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; - } - else if ("physics shapes" == info_display) - { - return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; - } - else if ("occlusion" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCCLUSION; - } - else if ("render batches" == info_display) - { - return LLPipeline::RENDER_DEBUG_BATCH_SIZE; - } - else if ("update type" == info_display) - { - return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; - } - else if ("texture anim" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; - } - else if ("texture priority" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; - } - else if ("texture area" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; - } - else if ("face area" == info_display) - { - return LLPipeline::RENDER_DEBUG_FACE_AREA; - } - else if ("lod info" == info_display) - { - return LLPipeline::RENDER_DEBUG_LOD_INFO; - } - else if ("lights" == info_display) - { - return LLPipeline::RENDER_DEBUG_LIGHTS; - } - else if ("particles" == info_display) - { - return LLPipeline::RENDER_DEBUG_PARTICLES; - } - else if ("composition" == info_display) - { - return LLPipeline::RENDER_DEBUG_COMPOSITION; - } - else if ("avatardrawinfo" == info_display) - { - return (LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO); - } - else if ("glow" == info_display) - { - return LLPipeline::RENDER_DEBUG_GLOW; - } - else if ("collision skeleton" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; - } - else if ("joints" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS; - } - else if ("raycast" == info_display) - { - return LLPipeline::RENDER_DEBUG_RAYCAST; - } - else if ("agent target" == info_display) - { - return LLPipeline::RENDER_DEBUG_AGENT_TARGET; - } - else if ("sculpt" == info_display) - { - return LLPipeline::RENDER_DEBUG_SCULPTED; - } - else if ("wind vectors" == info_display) - { - return LLPipeline::RENDER_DEBUG_WIND_VECTORS; - } - else if ("texel density" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY; - } - else if ("triangle count" == info_display) - { - return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; - } - else if ("impostors" == info_display) - { - return LLPipeline::RENDER_DEBUG_IMPOSTORS; - } - else if ("reflection probes" == info_display) + if ("verify" == info_display) { - return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + return LLPipeline::RENDER_DEBUG_VERIFY; } - else if ("probe updates" == info_display) + else if ("bboxes" == info_display) { - return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; + return LLPipeline::RENDER_DEBUG_BBOXES; } - else - { - LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; - return 0; - } -}; - -class LLAdvancedToggleInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U64 info_display = info_display_from_string( userdata.asString() ); - - LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; - - if ( info_display != 0 ) - { - LLPipeline::toggleRenderDebug( info_display ); - } - - return true; - } -}; - - -class LLAdvancedCheckInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U64 info_display = info_display_from_string( userdata.asString() ); - bool new_value = false; - - if ( info_display != 0 ) - { - new_value = LLPipeline::toggleRenderDebugControl( info_display ); - } - - return new_value; - } -}; - - -/////////////////////////// -//// RANDOMIZE FRAMERATE // -/////////////////////////// - - -class LLAdvancedToggleRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gRandomizeFramerate = !(gRandomizeFramerate); - return true; - } -}; - -class LLAdvancedCheckRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gRandomizeFramerate; - return new_value; - } -}; - -/////////////////////////// -//// PERIODIC SLOW FRAME // -/////////////////////////// - - -class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gPeriodicSlowFrame = !(gPeriodicSlowFrame); - return true; - } -}; - -class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gPeriodicSlowFrame; - return new_value; - } -}; - - -/////////////////////////// -// SELECTED TEXTURE INFO // -// + else if ("normals" == info_display) + { + return LLPipeline::RENDER_DEBUG_NORMALS; + } + else if ("points" == info_display) + { + return LLPipeline::RENDER_DEBUG_POINTS; + } + else if ("octree" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCTREE; + } + else if ("shadow frusta" == info_display) + { + return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; + } + else if ("physics shapes" == info_display) + { + return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; + } + else if ("occlusion" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCCLUSION; + } + else if ("render batches" == info_display) + { + return LLPipeline::RENDER_DEBUG_BATCH_SIZE; + } + else if ("update type" == info_display) + { + return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; + } + else if ("texture anim" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; + } + else if ("texture priority" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; + } + else if ("texture area" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; + } + else if ("face area" == info_display) + { + return LLPipeline::RENDER_DEBUG_FACE_AREA; + } + else if ("lod info" == info_display) + { + return LLPipeline::RENDER_DEBUG_LOD_INFO; + } + else if ("lights" == info_display) + { + return LLPipeline::RENDER_DEBUG_LIGHTS; + } + else if ("particles" == info_display) + { + return LLPipeline::RENDER_DEBUG_PARTICLES; + } + else if ("composition" == info_display) + { + return LLPipeline::RENDER_DEBUG_COMPOSITION; + } + else if ("avatardrawinfo" == info_display) + { + return (LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO); + } + else if ("glow" == info_display) + { + return LLPipeline::RENDER_DEBUG_GLOW; + } + else if ("collision skeleton" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; + } + else if ("joints" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS; + } + else if ("raycast" == info_display) + { + return LLPipeline::RENDER_DEBUG_RAYCAST; + } + else if ("agent target" == info_display) + { + return LLPipeline::RENDER_DEBUG_AGENT_TARGET; + } + else if ("sculpt" == info_display) + { + return LLPipeline::RENDER_DEBUG_SCULPTED; + } + else if ("wind vectors" == info_display) + { + return LLPipeline::RENDER_DEBUG_WIND_VECTORS; + } + else if ("texel density" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY; + } + else if ("triangle count" == info_display) + { + return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; + } + else if ("impostors" == info_display) + { + return LLPipeline::RENDER_DEBUG_IMPOSTORS; + } + else if ("reflection probes" == info_display) + { + return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + } + else if ("probe updates" == info_display) + { + return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; + } + else + { + LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; + return 0; + } +}; + +class LLAdvancedToggleInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); + + LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; + + if ( info_display != 0 ) + { + LLPipeline::toggleRenderDebug( info_display ); + } + + return true; + } +}; + + +class LLAdvancedCheckInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); + bool new_value = false; + + if ( info_display != 0 ) + { + new_value = LLPipeline::toggleRenderDebugControl( info_display ); + } + + return new_value; + } +}; + + +/////////////////////////// +//// RANDOMIZE FRAMERATE // +/////////////////////////// + + +class LLAdvancedToggleRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gRandomizeFramerate = !(gRandomizeFramerate); + return true; + } +}; + +class LLAdvancedCheckRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gRandomizeFramerate; + return new_value; + } +}; + +/////////////////////////// +//// PERIODIC SLOW FRAME // +/////////////////////////// + + +class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gPeriodicSlowFrame = !(gPeriodicSlowFrame); + return true; + } +}; + +class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gPeriodicSlowFrame; + return new_value; + } +}; + + +/////////////////////////// +// SELECTED TEXTURE INFO // +// /////////////////////////// class LLAdvancedSelectedTextureInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_selected_texture_info(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_selected_texture_info(NULL); + return true; + } }; ////////////////////// @@ -1212,33 +1212,33 @@ class LLAdvancedSelectedTextureInfo : public view_listener_t class LLAdvancedToggleWireframe : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gUseWireframe = !(gUseWireframe); + bool handleEvent(const LLSD& userdata) + { + gUseWireframe = !(gUseWireframe); - return true; - } + return true; + } }; class LLAdvancedCheckWireframe : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gUseWireframe; - } + bool handleEvent(const LLSD& userdata) + { + return gUseWireframe; + } }; - + ////////////////////////// // DUMP SCRIPTED CAMERA // ////////////////////////// - + class LLAdvancedDumpScriptedCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_followcam(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_dump_followcam(NULL); + return true; } }; @@ -1251,11 +1251,11 @@ class LLAdvancedDumpScriptedCamera : public view_listener_t class LLAdvancedDumpRegionObjectCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_region_object_cache(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_dump_region_object_cache(NULL); + return true; + } }; class LLAdvancedToggleInterestList360Mode : public view_listener_t @@ -1266,22 +1266,22 @@ public: // Toggle the mode - regions will get updated if (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360) { - gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); - } - else - { - gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); - } + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); + } + else + { + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); + } return true; } }; class LLAdvancedCheckInterestList360Mode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); + } }; class LLAdvancedToggleStatsRecorder : public view_listener_t @@ -1289,13 +1289,13 @@ class LLAdvancedToggleStatsRecorder : public view_listener_t bool handleEvent(const LLSD &userdata) { if (LLViewerStatsRecorder::instance().isEnabled()) - { // Turn off both recording and logging - LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); - } - else - { // Turn on both recording and logging - LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); - } + { // Turn off both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); + } + else + { // Turn on both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); + } return true; } }; @@ -1303,7 +1303,7 @@ class LLAdvancedToggleStatsRecorder : public view_listener_t class LLAdvancedCheckStatsRecorder : public view_listener_t { bool handleEvent(const LLSD &userdata) - { // Use the logging state as the indicator of whether the stats recorder is on + { // Use the logging state as the indicator of whether the stats recorder is on return LLViewerStatsRecorder::instance().isLogging(); } }; @@ -1311,7 +1311,7 @@ class LLAdvancedCheckStatsRecorder : public view_listener_t class LLAdvancedResetInterestLists : public view_listener_t { bool handleEvent(const LLSD &userdata) - { // Reset all region interest lists + { // Reset all region interest lists handle_reset_interest_lists(NULL); return true; } @@ -1319,12 +1319,12 @@ class LLAdvancedResetInterestLists : public view_listener_t class LLAdvancedBuyCurrencyTest : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - handle_buy_currency_test(NULL); - return true; - } + { + bool handleEvent(const LLSD& userdata) + { + handle_buy_currency_test(NULL); + return true; + } }; @@ -1335,11 +1335,11 @@ class LLAdvancedBuyCurrencyTest : public view_listener_t class LLAdvancedDumpSelectMgr : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - dump_select_mgr(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + dump_select_mgr(NULL); + return true; + } }; @@ -1351,11 +1351,11 @@ class LLAdvancedDumpSelectMgr : public view_listener_t class LLAdvancedDumpInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - dump_inventory(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + dump_inventory(NULL); + return true; + } }; @@ -1367,11 +1367,11 @@ class LLAdvancedDumpInventory : public view_listener_t class LLAdvancedPrintSelectedObjectInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - print_object_info(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + print_object_info(NULL); + return true; + } }; @@ -1383,11 +1383,11 @@ class LLAdvancedPrintSelectedObjectInfo : public view_listener_t class LLAdvancedPrintAgentInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - print_agent_nvpairs(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + print_agent_nvpairs(NULL); + return true; + } }; ////////////////// @@ -1397,20 +1397,20 @@ class LLAdvancedPrintAgentInfo : public view_listener_t class LLAdvancedToggleDebugClicks : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugClicks = !(gDebugClicks); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugClicks = !(gDebugClicks); + return true; + } }; class LLAdvancedCheckDebugClicks : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugClicks; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugClicks; + return new_value; + } }; @@ -1422,20 +1422,20 @@ class LLAdvancedCheckDebugClicks : public view_listener_t class LLAdvancedToggleDebugViews : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugRects = !(LLView::sDebugRects); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugRects = !(LLView::sDebugRects); + return true; + } }; class LLAdvancedCheckDebugViews : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugRects; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugRects; + return new_value; + } }; @@ -1447,19 +1447,19 @@ class LLAdvancedCheckDebugViews : public view_listener_t class LLAdvancedToggleDebugUnicode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugUnicode = !(LLView::sDebugUnicode); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugUnicode = !(LLView::sDebugUnicode); + return true; + } }; class LLAdvancedCheckDebugUnicode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return LLView::sDebugUnicode; - } + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugUnicode; + } }; @@ -1471,20 +1471,20 @@ class LLAdvancedCheckDebugUnicode : public view_listener_t class LLAdvancedToggleDebugCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugCamera = !(LLView::sDebugCamera); - LLFloaterCamera::onDebugCameraToggled(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugCamera = !(LLView::sDebugCamera); + LLFloaterCamera::onDebugCameraToggled(); + return true; + } }; class LLAdvancedCheckDebugCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return LLView::sDebugCamera; - } + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugCamera; + } }; @@ -1496,20 +1496,20 @@ class LLAdvancedCheckDebugCamera : public view_listener_t class LLAdvancedToggleXUINameTooltips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } }; class LLAdvancedCheckXUINameTooltips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } }; @@ -1521,20 +1521,20 @@ class LLAdvancedCheckXUINameTooltips : public view_listener_t class LLAdvancedToggleDebugMouseEvents : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); + return true; + } }; class LLAdvancedCheckDebugMouseEvents : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugMouseHandling; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugMouseHandling; + return new_value; + } }; @@ -1546,22 +1546,22 @@ class LLAdvancedCheckDebugMouseEvents : public view_listener_t class LLAdvancedToggleDebugKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugKeys = !(LLView::sDebugKeys); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugKeys = !(LLView::sDebugKeys); + return true; + } }; - + class LLAdvancedCheckDebugKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugKeys; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugKeys; + return new_value; + } }; - + /////////////////////// @@ -1571,30 +1571,30 @@ class LLAdvancedCheckDebugKeys : public view_listener_t class LLAdvancedToggleDebugWindowProc : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugWindowProc = !(gDebugWindowProc); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugWindowProc = !(gDebugWindowProc); + return true; + } }; class LLAdvancedCheckDebugWindowProc : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugWindowProc; - return new_value; - } + { + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugWindowProc; + return new_value; + } }; // ------------------------------XUI MENU --------------------------- class LLAdvancedSendTestIms : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLIMModel::instance().testMessages(); - return true; + bool handleEvent(const LLSD& userdata) + { + LLIMModel::instance().testMessages(); + return true; } }; @@ -1606,22 +1606,22 @@ class LLAdvancedSendTestIms : public view_listener_t class LLAdvancedToggleXUINames : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } }; class LLAdvancedCheckXUINames : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } -}; - + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } +}; + //////////////////////// // GRAB BAKED TEXTURE // @@ -1630,71 +1630,71 @@ class LLAdvancedCheckXUINames : public view_listener_t class LLAdvancedGrabBakedTexture : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string texture_type = userdata.asString(); - if ("iris" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string texture_type = userdata.asString(); + if ("iris" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_EYES ); + } + else if ("head" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_HEAD ); + } + else if ("upper" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_UPPER ); + } + else if ("lower" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_LOWER ); + } + else if ("skirt" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_SKIRT ); + } + else if ("hair" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_HAIR ); + } + + return true; + } }; class LLAdvancedEnableGrabBakedTexture : public view_listener_t { - bool handleEvent(const LLSD& userdata) -{ - std::string texture_type = userdata.asString(); - bool new_value = false; - - if ("iris" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return new_value; + bool handleEvent(const LLSD& userdata) +{ + std::string texture_type = userdata.asString(); + bool new_value = false; + + if ("iris" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); + } + else if ("head" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); + } + else if ("upper" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); + } + else if ("lower" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); + } + else if ("skirt" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); + } + else if ("hair" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); + } + + return new_value; } }; @@ -1705,8 +1705,8 @@ class LLAdvancedEnableGrabBakedTexture : public view_listener_t class LLAdvancedEnableAppearanceToXML : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (obj && obj->isAnimatedObject() && obj->getControlAvatar()) { @@ -1721,18 +1721,18 @@ class LLAdvancedEnableAppearanceToXML : public view_listener_t // This has to be a non-control avatar, because control avs are invisible and unclickable. return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); } - else - { - return false; - } - } + else + { + return false; + } + } }; class LLAdvancedAppearanceToXML : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string emptyname; + bool handleEvent(const LLSD& userdata) + { + std::string emptyname; LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar *avatar = NULL; if (obj) @@ -1755,14 +1755,14 @@ class LLAdvancedAppearanceToXML : public view_listener_t else { // If no selection, use the self avatar. - avatar = gAgentAvatarp; + avatar = gAgentAvatarp; } if (avatar) { avatar->dumpArchetypeXML(emptyname); } - return true; - } + return true; + } }; @@ -1774,44 +1774,44 @@ class LLAdvancedAppearanceToXML : public view_listener_t class LLAdvancedToggleCharacterGeometry : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_god_request_avatar_geometry(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_god_request_avatar_geometry(NULL); + return true; } }; - ///////////////////////////// + ///////////////////////////// // TEST MALE / TEST FEMALE // ///////////////////////////// class LLAdvancedTestMale : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_test_male(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_test_male(NULL); + return true; + } }; class LLAdvancedTestFemale : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_test_female(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_test_female(NULL); + return true; + } }; class LLAdvancedForceParamsToDefault : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAgent::clearVisualParams(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAgent::clearVisualParams(NULL); + return true; + } }; @@ -1820,47 +1820,47 @@ class LLAdvancedForceParamsToDefault : public view_listener_t ////////////////////////// // Utility function to set all AV time factors to the same global value -static void set_all_animation_time_factors(F32 time_factor) +static void set_all_animation_time_factors(F32 time_factor) { - LLMotionController::setCurrentTimeFactor(time_factor); - for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - (*iter)->setAnimTimeFactor(time_factor); - } + LLMotionController::setCurrentTimeFactor(time_factor); + for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + (*iter)->setAnimTimeFactor(time_factor); + } } class LLAdvancedAnimTenFaster : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //LL_INFOS() << "LLAdvancedAnimTenFaster" << LL_ENDL; - F32 time_factor = LLMotionController::getCurrentTimeFactor(); - time_factor = llmin(time_factor + 0.1f, 2.f); // Upper limit is 200% speed - set_all_animation_time_factors(time_factor); - return true; - } + bool handleEvent(const LLSD& userdata) + { + //LL_INFOS() << "LLAdvancedAnimTenFaster" << LL_ENDL; + F32 time_factor = LLMotionController::getCurrentTimeFactor(); + time_factor = llmin(time_factor + 0.1f, 2.f); // Upper limit is 200% speed + set_all_animation_time_factors(time_factor); + return true; + } }; class LLAdvancedAnimTenSlower : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //LL_INFOS() << "LLAdvancedAnimTenSlower" << LL_ENDL; - F32 time_factor = LLMotionController::getCurrentTimeFactor(); - time_factor = llmax(time_factor - 0.1f, 0.1f); // Lower limit is at 10% of normal speed - set_all_animation_time_factors(time_factor); - return true; - } + bool handleEvent(const LLSD& userdata) + { + //LL_INFOS() << "LLAdvancedAnimTenSlower" << LL_ENDL; + F32 time_factor = LLMotionController::getCurrentTimeFactor(); + time_factor = llmax(time_factor - 0.1f, 0.1f); // Lower limit is at 10% of normal speed + set_all_animation_time_factors(time_factor); + return true; + } }; class LLAdvancedAnimResetAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - set_all_animation_time_factors(1.f); - return true; - } + bool handleEvent(const LLSD& userdata) + { + set_all_animation_time_factors(1.f); + return true; + } }; @@ -1871,11 +1871,11 @@ class LLAdvancedAnimResetAll : public view_listener_t class LLAdvancedReloadVertexShader : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - reload_vertex_shader(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + reload_vertex_shader(NULL); + return true; + } }; @@ -1887,20 +1887,20 @@ class LLAdvancedReloadVertexShader : public view_listener_t class LLAdvancedToggleAnimationInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); + return true; + } }; class LLAdvancedCheckAnimationInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sShowAnimationDebug; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sShowAnimationDebug; + return new_value; + } }; @@ -1911,20 +1911,20 @@ class LLAdvancedCheckAnimationInfo : public view_listener_t class LLAdvancedToggleShowLookAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); + return true; + } }; class LLAdvancedCheckShowLookAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectLookAt::sDebugLookAt; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectLookAt::sDebugLookAt; + return new_value; + } }; @@ -1936,20 +1936,20 @@ class LLAdvancedCheckShowLookAt : public view_listener_t class LLAdvancedToggleShowPointAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); + return true; + } }; class LLAdvancedCheckShowPointAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectPointAt::sDebugPointAt; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectPointAt::sDebugPointAt; + return new_value; + } }; @@ -1961,20 +1961,20 @@ class LLAdvancedCheckShowPointAt : public view_listener_t class LLAdvancedToggleDebugJointUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); + return true; + } }; class LLAdvancedCheckDebugJointUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sJointDebug; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sJointDebug; + return new_value; + } }; @@ -1986,20 +1986,20 @@ class LLAdvancedCheckDebugJointUpdates : public view_listener_t class LLAdvancedToggleDisableLOD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); + return true; + } }; - + class LLAdvancedCheckDisableLOD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoint::sDisableLOD; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoint::sDisableLOD; + return new_value; + } }; @@ -2011,20 +2011,20 @@ class LLAdvancedCheckDisableLOD : public view_listener_t class LLAdvancedToggleDebugCharacterVis : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); + return true; + } }; class LLAdvancedCheckDebugCharacterVis : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sDebugInvisible; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sDebugInvisible; + return new_value; + } }; @@ -2032,33 +2032,33 @@ class LLAdvancedCheckDebugCharacterVis : public view_listener_t // DUMP ATTACHMENTS // ////////////////////// - + class LLAdvancedDumpAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_attachments(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_dump_attachments(NULL); + return true; + } }; - + ///////////////////// // REBAKE TEXTURES // ///////////////////// - - + + class LLAdvancedRebakeTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_rebake_textures(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_rebake_textures(NULL); + return true; + } }; - - + + #if 1 //ndef LL_RELEASE_FOR_DOWNLOAD /////////////////////////// // DEBUG AVATAR TEXTURES // @@ -2067,14 +2067,14 @@ class LLAdvancedRebakeTextures : public view_listener_t class LLAdvancedDebugAvatarTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isGodlike()) - { - handle_debug_avatar_textures(NULL); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.isGodlike()) + { + handle_debug_avatar_textures(NULL); + } + return true; + } }; //////////////////////////////// @@ -2084,17 +2084,17 @@ class LLAdvancedDebugAvatarTextures : public view_listener_t class LLAdvancedDumpAvatarLocalTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { #ifndef LL_RELEASE_FOR_DOWNLOAD - handle_dump_avatar_local_textures(NULL); + handle_dump_avatar_local_textures(NULL); #endif - return true; - } + return true; + } }; #endif - + ///////////////// // MESSAGE LOG // ///////////////// @@ -2102,20 +2102,20 @@ class LLAdvancedDumpAvatarLocalTextures : public view_listener_t class LLAdvancedEnableMessageLog : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_viewer_enable_message_log(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_viewer_enable_message_log(NULL); + return true; + } }; class LLAdvancedDisableMessageLog : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_viewer_disable_message_log(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_viewer_disable_message_log(NULL); + return true; + } }; ///////////////// @@ -2125,11 +2125,11 @@ class LLAdvancedDisableMessageLog : public view_listener_t class LLAdvancedDropPacket : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gMessageSystem->mPacketRing.dropPackets(1); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gMessageSystem->mPacketRing.dropPackets(1); + return true; + } }; ////////////////////// @@ -2139,8 +2139,8 @@ class LLAdvancedDropPacket : public view_listener_t class LLAdvancedPurgeDiskCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General"); llassert_always(main_queue); @@ -2154,8 +2154,8 @@ class LLAdvancedPurgeDiskCache : public view_listener_t }, [](){}); // Callback to main thread is empty as there is nothing left to do - return true; - } + return true; + } }; @@ -2166,12 +2166,12 @@ class LLAdvancedPurgeDiskCache : public view_listener_t class LLAdvancedPurgeShaderCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerShaderMgr::instance()->clearShaderCache(); - LLViewerShaderMgr::instance()->setShaders(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerShaderMgr::instance()->clearShaderCache(); + LLViewerShaderMgr::instance()->setShaders(); + return true; + } }; //////////////////// @@ -2181,32 +2181,32 @@ class LLAdvancedPurgeShaderCache : public view_listener_t class LLAdvancedViewerEventRecorder : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - LL_INFOS() << "Event Playback starting" << LL_ENDL; - LLViewerEventRecorder::instance().playbackRecording(); - LL_INFOS() << "Event Playback completed" << LL_ENDL; - } - else if ("stop playback" == command) - { - // Future - } - else if ("start recording" == command) - { - LLViewerEventRecorder::instance().setEventLoggingOn(); - LL_INFOS() << "Event recording started" << LL_ENDL; - } - else if ("stop recording" == command) - { - LLViewerEventRecorder::instance().setEventLoggingOff(); - LL_INFOS() << "Event recording stopped" << LL_ENDL; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + LL_INFOS() << "Event Playback starting" << LL_ENDL; + LLViewerEventRecorder::instance().playbackRecording(); + LL_INFOS() << "Event Playback completed" << LL_ENDL; + } + else if ("stop playback" == command) + { + // Future + } + else if ("start recording" == command) + { + LLViewerEventRecorder::instance().setEventLoggingOn(); + LL_INFOS() << "Event recording started" << LL_ENDL; + } + else if ("stop recording" == command) + { + LLViewerEventRecorder::instance().setEventLoggingOff(); + LL_INFOS() << "Event recording stopped" << LL_ENDL; + } + + return true; + } }; @@ -2219,29 +2219,29 @@ class LLAdvancedViewerEventRecorder : public view_listener_t class LLAdvancedAgentPilot : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - gAgentPilot.setNumRuns(-1); - gAgentPilot.startPlayback(); - } - else if ("stop playback" == command) - { - gAgentPilot.stopPlayback(); - } - else if ("start record" == command) - { - gAgentPilot.startRecord(); - } - else if ("stop record" == command) - { - gAgentPilot.stopRecord(); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + gAgentPilot.setNumRuns(-1); + gAgentPilot.startPlayback(); + } + else if ("stop playback" == command) + { + gAgentPilot.stopPlayback(); + } + else if ("start record" == command) + { + gAgentPilot.startRecord(); + } + else if ("stop record" == command) + { + gAgentPilot.stopRecord(); + } + + return true; + } }; @@ -2253,20 +2253,20 @@ class LLAdvancedAgentPilot : public view_listener_t class LLAdvancedToggleAgentPilotLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgentPilot.setLoop(!gAgentPilot.getLoop()); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgentPilot.setLoop(!gAgentPilot.getLoop()); + return true; + } }; class LLAdvancedCheckAgentPilotLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentPilot.getLoop(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgentPilot.getLoop(); + return new_value; + } }; @@ -2277,20 +2277,20 @@ class LLAdvancedCheckAgentPilotLoop : public view_listener_t class LLAdvancedToggleShowObjectUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gShowObjectUpdates = !(gShowObjectUpdates); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gShowObjectUpdates = !(gShowObjectUpdates); + return true; + } }; class LLAdvancedCheckShowObjectUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gShowObjectUpdates; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gShowObjectUpdates; + return new_value; + } }; @@ -2302,11 +2302,11 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t class LLAdvancedCompressImage : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_compress_image(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_compress_image(NULL); + return true; + } }; @@ -2332,11 +2332,11 @@ class LLAdvancedCompressFileTest : public view_listener_t class LLAdvancedShowDebugSettings : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("settings_debug",userdata); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("settings_debug",userdata); + return true; + } }; @@ -2347,40 +2347,40 @@ class LLAdvancedShowDebugSettings : public view_listener_t class LLAdvancedEnableViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // Don't enable in god mode since the admin menu is shown anyway. - // Only enable if the user has set the appropriate debug setting. - bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // Don't enable in god mode since the admin menu is shown anyway. + // Only enable if the user has set the appropriate debug setting. + bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); + return new_value; + } }; class LLAdvancedToggleViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_admin_override_toggle(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_admin_override_toggle(NULL); + return true; + } }; class LLAdvancedToggleVisualLeakDetector : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_visual_leak_detector_toggle(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_visual_leak_detector_toggle(NULL); + return true; + } }; class LLAdvancedCheckViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); + return new_value; + } }; ////////////////// @@ -2390,20 +2390,20 @@ class LLAdvancedCheckViewAdminOptions : public view_listener_t class LLAdvancedRequestAdminStatus : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_god_mode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_god_mode(NULL); + return true; + } }; class LLAdvancedLeaveAdminStatus : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_leave_god_mode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_leave_god_mode(NULL); + return true; + } }; ////////////////////////// @@ -2412,20 +2412,20 @@ class LLAdvancedLeaveAdminStatus : public view_listener_t class LLAdvancedForceErrorBreakpoint : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_breakpoint(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_breakpoint(NULL); + return true; + } }; class LLAdvancedForceErrorLlerror : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_llerror(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_llerror(NULL); + return true; + } }; class LLAdvancedForceErrorLlerrorMsg: public view_listener_t @@ -2439,11 +2439,11 @@ class LLAdvancedForceErrorLlerrorMsg: public view_listener_t class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_bad_memory_access(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_bad_memory_access(NULL); + return true; + } }; class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t @@ -2464,20 +2464,20 @@ class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t class LLAdvancedForceErrorInfiniteLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_infinite_loop(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_infinite_loop(NULL); + return true; + } }; class LLAdvancedForceErrorSoftwareException : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_software_exception(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_software_exception(NULL); + return true; + } }; class LLAdvancedForceOSException: public view_listener_t @@ -2507,11 +2507,11 @@ class LLAdvancedForceErrorSoftwareExceptionCoro : public view_listener_t class LLAdvancedForceErrorDriverCrash : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_driver_crash(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_driver_crash(NULL); + return true; + } }; class LLAdvancedForceErrorCoroutineCrash : public view_listener_t @@ -2534,10 +2534,10 @@ class LLAdvancedForceErrorThreadCrash : public view_listener_t class LLAdvancedForceErrorDisconnectViewer : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_disconnect_viewer(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_disconnect_viewer(NULL); + return true; } }; @@ -2546,29 +2546,29 @@ class LLAdvancedForceErrorDisconnectViewer : public view_listener_t class LLAdvancedHandleToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_toggle_hacked_godmode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_toggle_hacked_godmode(NULL); + return true; + } }; class LLAdvancedCheckToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - check_toggle_hacked_godmode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + check_toggle_hacked_godmode(NULL); + return true; + } }; class LLAdvancedEnableToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_toggle_hacked_godmode(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_toggle_hacked_godmode(NULL); + return new_value; + } }; #endif @@ -2585,21 +2585,21 @@ class LLAdvancedEnableToggleHackedGodmode : public view_listener_t class LLDevelopCheckLoggingLevel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 level = userdata.asInteger(); - return (static_cast<LLError::ELevel>(level) == LLError::getDefaultLevel()); - } + bool handleEvent(const LLSD& userdata) + { + U32 level = userdata.asInteger(); + return (static_cast<LLError::ELevel>(level) == LLError::getDefaultLevel()); + } }; class LLDevelopSetLoggingLevel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 level = userdata.asInteger(); - LLError::setDefaultLevel(static_cast<LLError::ELevel>(level)); - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 level = userdata.asInteger(); + LLError::setDefaultLevel(static_cast<LLError::ELevel>(level)); + return true; + } }; ////////////////// @@ -2609,100 +2609,100 @@ class LLDevelopSetLoggingLevel : public view_listener_t // Admin > Object class LLAdminForceTakeCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_take_copy(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_take_copy(NULL); + return true; + } }; class LLAdminHandleObjectOwnerSelf : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_self(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_owner_self(NULL); + return true; + } }; class LLAdminHandleObjectOwnerPermissive : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_permissive(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_owner_permissive(NULL); + return true; + } }; class LLAdminHandleForceDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_delete(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_delete(NULL); + return true; + } }; class LLAdminHandleObjectLock : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_lock(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_lock(NULL); + return true; + } }; class LLAdminHandleObjectAssetIDs: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_asset_ids(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_asset_ids(NULL); + return true; + } }; //Admin >Parcel class LLAdminHandleForceParcelOwnerToMe: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_owner_to_me(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_owner_to_me(NULL); + return true; + } }; class LLAdminHandleForceParcelToContent: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_to_content(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_to_content(NULL); + return true; + } }; class LLAdminHandleClaimPublicLand: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_claim_public_land(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_claim_public_land(NULL); + return true; + } }; // Admin > Region class LLAdminHandleRegionDumpTempAssetData: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_region_dump_temp_asset_data(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_region_dump_temp_asset_data(NULL); + return true; + } }; //Admin (Top Level) class LLAdminOnSaveState: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPanelRegionTools::onSaveState(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + LLPanelRegionTools::onSaveState(NULL); + return true; } }; @@ -2712,38 +2712,38 @@ class LLAdminOnSaveState: public view_listener_t //----------------------------------------------------------------------------- void cleanup_menus() { - delete gMenuParcelObserver; - gMenuParcelObserver = NULL; + delete gMenuParcelObserver; + gMenuParcelObserver = NULL; - delete gMenuAvatarSelf; - gMenuAvatarSelf = NULL; + delete gMenuAvatarSelf; + gMenuAvatarSelf = NULL; - delete gMenuAvatarOther; - gMenuAvatarOther = NULL; + delete gMenuAvatarOther; + gMenuAvatarOther = NULL; - delete gMenuObject; - gMenuObject = NULL; + delete gMenuObject; + gMenuObject = NULL; - delete gMenuAttachmentSelf; - gMenuAttachmentSelf = NULL; + delete gMenuAttachmentSelf; + gMenuAttachmentSelf = NULL; - delete gMenuAttachmentOther; - gMenuAttachmentSelf = NULL; + delete gMenuAttachmentOther; + gMenuAttachmentSelf = NULL; - delete gMenuLand; - gMenuLand = NULL; + delete gMenuLand; + gMenuLand = NULL; - delete gMenuMuteParticle; - gMenuMuteParticle = NULL; + delete gMenuMuteParticle; + gMenuMuteParticle = NULL; - delete gMenuBarView; - gMenuBarView = NULL; + delete gMenuBarView; + gMenuBarView = NULL; - delete gPopupMenuView; - gPopupMenuView = NULL; + delete gPopupMenuView; + gPopupMenuView = NULL; - delete gMenuHolder; - gMenuHolder = NULL; + delete gMenuHolder; + gMenuHolder = NULL; } //----------------------------------------------------------------------------- @@ -2752,40 +2752,40 @@ void cleanup_menus() class LLObjectReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReporter::showFromObject(objectp->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReporter::showFromObject(objectp->getID()); + } + return true; + } }; // Enabled it you clicked an object class LLObjectEnableReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; + return new_value; + } }; void handle_object_touch() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return; - LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLPickInfo pick = LLToolPie::getInstance()->getPick(); - // *NOTE: Hope the packets arrive safely and in order or else - // there will be some problems. - // *TODO: Just fix this bad assumption. - send_ObjectGrab_message(object, pick, LLVector3::zero); - send_ObjectDeGrab_message(object, pick); + // *NOTE: Hope the packets arrive safely and in order or else + // there will be some problems. + // *TODO: Just fix this bad assumption. + send_ObjectGrab_message(object, pick, LLVector3::zero); + send_ObjectDeGrab_message(object, pick); } void handle_object_show_original() @@ -2818,75 +2818,75 @@ void handle_object_show_original() static void init_default_item_label(LLUICtrl* ctrl) { - const std::string& item_name = ctrl->getName(); - boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); - if (it == sDefaultItemLabels.end()) - { - // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value - // (doesn't seem to matter much ATM). - LLStringExplicit default_label = ctrl->getValue().asString(); - if (!default_label.empty()) - { - sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); - } - } + const std::string& item_name = ctrl->getName(); + boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); + if (it == sDefaultItemLabels.end()) + { + // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value + // (doesn't seem to matter much ATM). + LLStringExplicit default_label = ctrl->getValue().asString(); + if (!default_label.empty()) + { + sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); + } + } } static LLStringExplicit get_default_item_label(const std::string& item_name) { - LLStringExplicit res(""); - boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); - if (it != sDefaultItemLabels.end()) - { - res = it->second; - } + LLStringExplicit res(""); + boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); + if (it != sDefaultItemLabels.end()) + { + res = it->second; + } - return res; + return res; } bool enable_object_touch(LLUICtrl* ctrl) { - bool new_value = false; - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (obj) - { - LLViewerObject* parent = (LLViewerObject*)obj->getParent(); - new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); - } + bool new_value = false; + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + LLViewerObject* parent = (LLViewerObject*)obj->getParent(); + new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); + } - init_default_item_label(ctrl); + init_default_item_label(ctrl); - // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mTouchName.empty()) - { - ctrl->setValue(node->mTouchName); - } - else - { - ctrl->setValue(get_default_item_label(ctrl->getName())); - } + // Update label based on the node touch name if available. + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mTouchName.empty()) + { + ctrl->setValue(node->mTouchName); + } + else + { + ctrl->setValue(get_default_item_label(ctrl->getName())); + } - return new_value; + return new_value; }; //void label_touch(std::string& label, void*) //{ -// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); -// if (node && node->mValid && !node->mTouchName.empty()) -// { -// label.assign(node->mTouchName); -// } -// else -// { -// label.assign("Touch"); -// } +// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); +// if (node && node->mValid && !node->mTouchName.empty()) +// { +// label.assign(node->mTouchName); +// } +// else +// { +// label.assign("Touch"); +// } //} void handle_object_open() { - LLFloaterReg::showInstance("openobject"); + LLFloaterReg::showInstance("openobject"); } bool enable_object_inspect() @@ -2941,67 +2941,67 @@ bool enable_object_edit_gltf_material() bool enable_object_open() { - // Look for contents in root object, which is all the LLFloaterOpenObject - // understands. - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!obj) return false; + // Look for contents in root object, which is all the LLFloaterOpenObject + // understands. + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!obj) return false; - LLViewerObject* root = obj->getRootEdit(); - if (!root) return false; + LLViewerObject* root = obj->getRootEdit(); + if (!root) return false; - return root->allowOpen(); + return root->allowOpen(); } class LLViewJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_toggle_flycam(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_toggle_flycam(); + return true; + } }; class LLViewCheckJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); + return new_value; + } }; void handle_toggle_flycam() { - LLViewerJoystick::getInstance()->toggleFlycam(); + LLViewerJoystick::getInstance()->toggleFlycam(); } class LLObjectBuild : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - - // Could be first use - //LLFirstUse::useBuild(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gAgentCamera.cameraZoomIn(0.666f); + gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } + + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + + // Could be first use + //LLFirstUse::useBuild(); + return true; + } }; void update_camera() @@ -3040,17 +3040,17 @@ void handle_object_edit() { update_camera(); - LLFloaterReg::showInstance("build"); - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); - - LLViewerJoystick::getInstance()->moveObjects(true); - LLViewerJoystick::getInstance()->setNeedsReset(true); - - // Could be first use - //LLFirstUse::useBuild(); - return; + LLFloaterReg::showInstance("build"); + + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); + + LLViewerJoystick::getInstance()->moveObjects(true); + LLViewerJoystick::getInstance()->setNeedsReset(true); + + // Could be first use + //LLFirstUse::useBuild(); + return; } void handle_object_edit_gltf_material() @@ -3072,68 +3072,68 @@ void handle_object_edit_gltf_material() void handle_attachment_edit(const LLUUID& inv_item_id) { - if (isAgentAvatarValid()) - { - if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) - { - LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); + if (isAgentAvatarValid()) + { + if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); - handle_object_edit(); - } - } + handle_object_edit(); + } + } } void handle_attachment_touch(const LLUUID& inv_item_id) { - if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) - { - if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) - { - LLSelectMgr::getInstance()->deselectAll(); - - LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); - if (!LLToolMgr::getInstance()->inBuildMode()) - { - struct SetTransient : public LLSelectedNodeFunctor - { - bool apply(LLSelectNode* node) - { - node->setTransient(TRUE); - return true; - } - } f; - sel->applyToNodes(&f); - } - - handle_object_touch(); - } - } + if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) + { + if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) + { + LLSelectMgr::getInstance()->deselectAll(); + + LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); + if (!LLToolMgr::getInstance()->inBuildMode()) + { + struct SetTransient : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + node->setTransient(TRUE); + return true; + } + } f; + sel->applyToNodes(&f); + } + + handle_object_touch(); + } + } } bool enable_attachment_touch(const LLUUID& inv_item_id) { - if (isAgentAvatarValid()) - { - const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); - return (attach_obj) && (attach_obj->flagHandleTouch()); - } - return false; + if (isAgentAvatarValid()) + { + const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); + return (attach_obj) && (attach_obj->flagHandleTouch()); + } + return false; } void handle_object_inspect() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* selected_objectp = selection->getFirstRootObject(); - if (selected_objectp) - { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* selected_objectp = selection->getFirstRootObject(); + if (selected_objectp) + { LLFloaterReg::showInstance("task_properties"); - } - - /* - // Old floater properties - LLFloaterReg::showInstance("inspect", LLSD()); - */ + } + + /* + // Old floater properties + LLFloaterReg::showInstance("inspect", LLSD()); + */ } //--------------------------------------------------------------------------- @@ -3141,133 +3141,133 @@ void handle_object_inspect() //--------------------------------------------------------------------------- class LLLandBuild : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerParcelMgr::getInstance()->deselectLand(); + bool handleEvent(const LLSD& userdata) + { + LLViewerParcelMgr::getInstance()->deselectLand(); - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - // otherwise just move focus - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } + if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gAgentCamera.cameraZoomIn(0.666f); + gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + // otherwise just move focus + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - // Could be first use - //LLFirstUse::useBuild(); - return true; - } + // Could be first use + //LLFirstUse::useBuild(); + return true; + } }; class LLLandBuyPass : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPanelLandGeneral::onClickBuyPass((void *)FALSE); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLPanelLandGeneral::onClickBuyPass((void *)FALSE); + return true; + } }; class LLLandEnableBuyPass : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); + return new_value; + } }; // BUG: Should really check if CLICK POINT is in a parcel where you can build. BOOL enable_land_build(void*) { - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; + if (gAgent.isGodlike()) return TRUE; + if (gAgent.inPrelude()) return FALSE; - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; + BOOL can_build = FALSE; + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel) + { + can_build = agent_parcel->getAllowModify(); + } + return can_build; } // BUG: Should really check if OBJECT is in a parcel where you can build. BOOL enable_object_build(void*) { - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; + if (gAgent.isGodlike()) return TRUE; + if (gAgent.inPrelude()) return FALSE; - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; + BOOL can_build = FALSE; + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel) + { + can_build = agent_parcel->getAllowModify(); + } + return can_build; } bool enable_object_edit() { - if (!isAgentAvatarValid()) return false; - - // *HACK: The new "prelude" Help Islands have a build sandbox area, - // so users need the Edit and Create pie menu options when they are - // there. Eventually this needs to be replaced with code that only - // lets you edit objects if you have permission to do so (edit perms, - // group edit, god). See also lltoolbar.cpp. JC - bool enable = false; - if (gAgent.inPrelude()) - { - enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() - || LLSelectMgr::getInstance()->getSelection()->isAttachment(); - } - else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) - { - enable = true; - } - - return enable; + if (!isAgentAvatarValid()) return false; + + // *HACK: The new "prelude" Help Islands have a build sandbox area, + // so users need the Edit and Create pie menu options when they are + // there. Eventually this needs to be replaced with code that only + // lets you edit objects if you have permission to do so (edit perms, + // group edit, god). See also lltoolbar.cpp. JC + bool enable = false; + if (gAgent.inPrelude()) + { + enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() + || LLSelectMgr::getInstance()->getSelection()->isAttachment(); + } + else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) + { + enable = true; + } + + return enable; } bool enable_mute_particle() { - const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); - return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID(); + return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID(); } // mutually exclusive - show either edit option or build in menu bool enable_object_build() { - return !enable_object_edit(); + return !enable_object_edit(); } bool enable_object_select_in_pathfinding_linksets() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); } bool visible_object_select_in_pathfinding_linksets() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); } bool enable_object_select_in_pathfinding_characters() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } bool enable_os_exception() @@ -3281,40 +3281,40 @@ bool enable_os_exception() class LLSelfRemoveAllAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); + return true; + } }; class LLSelfEnableRemoveAllAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - if (isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getNumObjects() > 0) - { - new_value = true; - break; - } - } - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = false; + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getNumObjects() > 0) + { + new_value = true; + break; + } + } + } + return new_value; + } }; BOOL enable_has_attachments(void*) { - return FALSE; + return FALSE; } //--------------------------------------------------------------------------- @@ -3322,229 +3322,229 @@ BOOL enable_has_attachments(void*) //--------------------------------------------------------------------------- //void handle_follow(void *userdata) //{ -// // follow a given avatar by ID -// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if (objectp) -// { -// gAgent.startFollowPilot(objectp->getID()); -// } +// // follow a given avatar by ID +// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +// if (objectp) +// { +// gAgent.startFollowPilot(objectp->getID()); +// } //} bool enable_object_mute() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && - !LLMuteList::getInstance()->isMuted(object->getID()); - } + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + // It's an avatar + LLNameValue *lastname = avatar->getNVPair("LastName"); + bool is_linden = + lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); + bool is_self = avatar->isSelf(); + return !is_linden && !is_self; + } + else + { + // Just a regular object + return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && + !LLMuteList::getInstance()->isMuted(object->getID()); + } } bool enable_object_unmute() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && - LLMuteList::getInstance()->isMuted(object->getID());; - } + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + // It's an avatar + LLNameValue *lastname = avatar->getNVPair("LastName"); + bool is_linden = + lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); + bool is_self = avatar->isSelf(); + return !is_linden && !is_self; + } + else + { + // Just a regular object + return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && + LLMuteList::getInstance()->isMuted(object->getID());; + } } // 0 = normal, 1 = always, 2 = never class LLAvatarCheckImpostorMode : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (!avatar) return false; - - U32 mode = userdata.asInteger(); - switch (mode) - { - case 0: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); - case 1: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); - case 2: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (!avatar) return false; + + U32 mode = userdata.asInteger(); + switch (mode) + { + case 0: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); + case 1: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); + case 2: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); case 4: return (avatar->getVisualMuteSettings() != LLVOAvatar::AV_RENDER_NORMALLY); - default: - return false; - } - } // handleEvent() + default: + return false; + } + } // handleEvent() }; // 0 = normal, 1 = always, 2 = never class LLAvatarSetImpostorMode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (!avatar) return false; - - U32 mode = userdata.asInteger(); - switch (mode) - { - case 0: - avatar->setVisualMuteSettings(LLVOAvatar::AV_RENDER_NORMALLY); - break; - case 1: - avatar->setVisualMuteSettings(LLVOAvatar::AV_DO_NOT_RENDER); - break; - case 2: - avatar->setVisualMuteSettings(LLVOAvatar::AV_ALWAYS_RENDER); - break; - default: - return false; - } - - LLVOAvatar::cullAvatarsByPixelArea(); - return true; - } // handleEvent() + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (!avatar) return false; + + U32 mode = userdata.asInteger(); + switch (mode) + { + case 0: + avatar->setVisualMuteSettings(LLVOAvatar::AV_RENDER_NORMALLY); + break; + case 1: + avatar->setVisualMuteSettings(LLVOAvatar::AV_DO_NOT_RENDER); + break; + case 2: + avatar->setVisualMuteSettings(LLVOAvatar::AV_ALWAYS_RENDER); + break; + default: + return false; + } + + LLVOAvatar::cullAvatarsByPixelArea(); + return true; + } // handleEvent() }; class LLObjectMute : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return true; - - LLUUID id; - std::string name; - LLMute::EType type; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - avatar->mNeedsImpostorUpdate = TRUE; - avatar->mLastImpostorUpdateReason = 9; - - id = avatar->getID(); - - LLNameValue *firstname = avatar->getNVPair("FirstName"); - LLNameValue *lastname = avatar->getNVPair("LastName"); - if (firstname && lastname) - { - name = LLCacheName::buildFullName( - firstname->getString(), lastname->getString()); - } - - type = LLMute::AGENT; - } - else - { - // it's an object - id = object->getID(); - - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node) - { - name = node->mName; - } - - type = LLMute::OBJECT; - } - - LLMute mute(id, name, type); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return true; + + LLUUID id; + std::string name; + LLMute::EType type; + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + avatar->mNeedsImpostorUpdate = TRUE; + avatar->mLastImpostorUpdateReason = 9; + + id = avatar->getID(); + + LLNameValue *firstname = avatar->getNVPair("FirstName"); + LLNameValue *lastname = avatar->getNVPair("LastName"); + if (firstname && lastname) + { + name = LLCacheName::buildFullName( + firstname->getString(), lastname->getString()); + } + + type = LLMute::AGENT; + } + else + { + // it's an object + id = object->getID(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node) + { + name = node->mName; + } + + type = LLMute::OBJECT; + } + + LLMute mute(id, name, type); + if (LLMuteList::getInstance()->isMuted(mute.mID)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + + return true; + } }; bool handle_go_to() { - // try simulator autopilot - std::vector<std::string> strings; - std::string val; - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - val = llformat("%g", pos.mdV[VX]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); - strings.push_back(val); - send_generic_message("autopilot", strings); - - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else - { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); - } - - // Could be first use - //LLFirstUse::useGoTo(); - return true; + // try simulator autopilot + std::vector<std::string> strings; + std::string val; + LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; + val = llformat("%g", pos.mdV[VX]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VY]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VZ]); + strings.push_back(val); + send_generic_message("autopilot", strings); + + LLViewerParcelMgr::getInstance()->deselectLand(); + + if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) + { + gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); + } + else + { + // Snap camera back to behind avatar + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); + } + + // Could be first use + //LLFirstUse::useGoTo(); + return true; } class LLGoToObject : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return handle_go_to(); - } + bool handleEvent(const LLSD& userdata) + { + return handle_go_to(); + } }; class LLAvatarReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLFloaterReporter::showFromObject(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLFloaterReporter::showFromObject(avatar->getID()); + } + return true; + } }; @@ -3553,230 +3553,230 @@ class LLAvatarReportAbuse : public view_listener_t //--------------------------------------------------------------------------- bool callback_freeze(const LLSD& notification, const LLSD& response) { - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option || 1 == option) - { - U32 flags = 0x0; - if (1 == option) - { - // unfreeze - flags |= 0x1; - } - - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - msg->newMessage("FreezeUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; -} + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option || 1 == option) + { + U32 flags = 0x0; + if (1 == option) + { + // unfreeze + flags |= 0x1; + } + + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + msg->newMessage("FreezeUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + return false; +} void handle_avatar_freeze(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - std::string fullname = avatar->getFullname(); - LLSD payload; - payload["avatar_id"] = avatar->getID(); - - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("FreezeAvatarFullname", - args, - payload, - callback_freeze); - } - else - { - LLNotificationsUtil::add("FreezeAvatar", - LLSD(), - payload, - callback_freeze); - } - } + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + + if( avatar ) + { + std::string fullname = avatar->getFullname(); + LLSD payload; + payload["avatar_id"] = avatar->getID(); + + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("FreezeAvatarFullname", + args, + payload, + callback_freeze); + } + else + { + LLNotificationsUtil::add("FreezeAvatar", + LLSD(), + payload, + callback_freeze); + } + } } class LLAvatarVisibleDebug : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.isGodlike(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.isGodlike(); + } }; class LLAvatarDebug : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if( avatar ) - { - if (avatar->isSelf()) - { - ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); - } - LL_INFOS() << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << LL_ENDL; - std::vector<std::string> strings; - strings.push_back(avatar->getID().asString()); - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); - LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if( avatar ) + { + if (avatar->isSelf()) + { + ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); + } + LL_INFOS() << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << LL_ENDL; + std::vector<std::string> strings; + strings.push_back(avatar->getID().asString()); + LLUUID invoice; + send_generic_message("dumptempassetdata", strings, invoice); + LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); + } + return true; + } }; bool callback_eject(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (2 == option) - { - // Cancel button. - return false; - } - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); - - if (0 == option) - { - // Eject button - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x0; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - else if (ban_enabled) - { - // This is tricky. It is similar to say if it is not an 'Eject' button, - // and it is also not an 'Cancle' button, and ban_enabled==ture, - // it should be the 'Eject and Ban' button. - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x1; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (2 == option) + { + // Cancel button. + return false; + } + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); + + if (0 == option) + { + // Eject button + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + U32 flags = 0x0; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID() ); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + else if (ban_enabled) + { + // This is tricky. It is similar to say if it is not an 'Eject' button, + // and it is also not an 'Cancle' button, and ban_enabled==ture, + // it should be the 'Eject and Ban' button. + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + U32 flags = 0x1; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID() ); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + return false; } void handle_avatar_eject(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - LLSD payload; - payload["avatar_id"] = avatar->getID(); - std::string fullname = avatar->getFullname(); - - const LLVector3d& pos = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); - - if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) - { + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + + if( avatar ) + { + LLSD payload; + payload["avatar_id"] = avatar->getID(); + std::string fullname = avatar->getFullname(); + + const LLVector3d& pos = avatar->getPositionGlobal(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); + + if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) + { payload["ban_enabled"] = true; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullname", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarFullname", - LLSD(), - payload, - callback_eject); - } - } - else - { + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("EjectAvatarFullname", + args, + payload, + callback_eject); + } + else + { + LLNotificationsUtil::add("EjectAvatarFullname", + LLSD(), + payload, + callback_eject); + } + } + else + { payload["ban_enabled"] = false; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullnameNoBan", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarNoBan", - LLSD(), - payload, - callback_eject); - } - } - } + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("EjectAvatarFullnameNoBan", + args, + payload, + callback_eject); + } + else + { + LLNotificationsUtil::add("EjectAvatarNoBan", + LLSD(), + payload, + callback_eject); + } + } + } } bool my_profile_visible() { - LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); - return floaterp && floaterp->isInVisibleChain(); + LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); + return floaterp && floaterp->isInVisibleChain(); } bool picks_tab_visible() @@ -3786,192 +3786,192 @@ bool picks_tab_visible() bool enable_freeze_eject(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - if (!avatar) return false; - - // Gods can always freeze - if (gAgent.isGodlike()) return true; - - // Estate owners / managers can freeze - // Parcel owners can also freeze - const LLVector3& pos = avatar->getPositionRegion(); - const LLVector3d& pos_global = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); - LLViewerRegion* region = avatar->getRegion(); - if (!region) return false; - - bool new_value = region->isOwnedSelf(pos); - if (!new_value || region->isOwnedGroup(pos)) - { - new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); - } - return new_value; + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + if (!avatar) return false; + + // Gods can always freeze + if (gAgent.isGodlike()) return true; + + // Estate owners / managers can freeze + // Parcel owners can also freeze + const LLVector3& pos = avatar->getPositionRegion(); + const LLVector3d& pos_global = avatar->getPositionGlobal(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); + LLViewerRegion* region = avatar->getRegion(); + if (!region) return false; + + bool new_value = region->isOwnedSelf(pos); + if (!new_value || region->isOwnedGroup(pos)) + { + new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); + } + return new_value; } bool callback_leave_group(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_LeaveGroupRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); - gAgent.sendReliableMessage(); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_LeaveGroupRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_GroupData); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); + gAgent.sendReliableMessage(); + } + return false; } void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt) { - LLAggregatePermissions::EValue val = ag_perm.getValue(bit); - std::string buffer; - switch(val) - { - case LLAggregatePermissions::AP_NONE: - buffer = llformat( "* %s None\n", txt); - break; - case LLAggregatePermissions::AP_SOME: - buffer = llformat( "* %s Some\n", txt); - break; - case LLAggregatePermissions::AP_ALL: - buffer = llformat( "* %s All\n", txt); - break; - case LLAggregatePermissions::AP_EMPTY: - default: - break; - } - string.append(buffer); + LLAggregatePermissions::EValue val = ag_perm.getValue(bit); + std::string buffer; + switch(val) + { + case LLAggregatePermissions::AP_NONE: + buffer = llformat( "* %s None\n", txt); + break; + case LLAggregatePermissions::AP_SOME: + buffer = llformat( "* %s Some\n", txt); + break; + case LLAggregatePermissions::AP_ALL: + buffer = llformat( "* %s All\n", txt); + break; + case LLAggregatePermissions::AP_EMPTY: + default: + break; + } + string.append(buffer); } bool enable_buy_object() { // In order to buy, there must only be 1 purchaseable object in // the selection manager. - if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; + if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; LLViewerObject* obj = NULL; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node) + if(node) { obj = node->getObject(); if(!obj) return false; - if( for_sale_selection(node) ) - { - // *NOTE: Is this needed? This checks to see if anyone owns the - // object, dating back to when we had "public" objects owned by - // no one. JC - if(obj->permAnyOwner()) return true; - } + if( for_sale_selection(node) ) + { + // *NOTE: Is this needed? This checks to see if anyone owns the + // object, dating back to when we had "public" objects owned by + // no one. JC + if(obj->permAnyOwner()) return true; + } } - return false; + return false; } // Note: This will only work if the selected object's data has been // received by the viewer and cached in the selection manager. void handle_buy_object(LLSaleInfo sale_info) { - if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) - { - LLNotificationsUtil::add("UnableToBuyWhileDownloading"); - return; - } + if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) + { + LLNotificationsUtil::add("UnableToBuyWhileDownloading"); + return; + } - LLUUID owner_id; - std::string owner_name; - BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); - if (!owners_identical) - { - LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); - return; - } + LLUUID owner_id; + std::string owner_name; + BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + if (!owners_identical) + { + LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); + return; + } - LLPermissions perm; - BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); - LLAggregatePermissions ag_perm; - valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); - if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) - { - LLNotificationsUtil::add("ObjectNotForSale"); - return; - } + LLPermissions perm; + BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); + LLAggregatePermissions ag_perm; + valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); + if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) + { + LLNotificationsUtil::add("ObjectNotForSale"); + return; + } - LLFloaterBuy::show(sale_info); + LLFloaterBuy::show(sale_info); } void handle_buy_contents(LLSaleInfo sale_info) { - LLFloaterBuyContents::show(sale_info); + LLFloaterBuyContents::show(sale_info); } void handle_region_dump_temp_asset_data(void*) { - LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; - std::vector<std::string> strings; - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); + LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; + std::vector<std::string> strings; + LLUUID invoice; + send_generic_message("dumptempassetdata", strings, invoice); } void handle_region_clear_temp_asset_data(void*) { - LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; - std::vector<std::string> strings; - LLUUID invoice; - send_generic_message("cleartempassetdata", strings, invoice); + LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; + std::vector<std::string> strings; + LLUUID invoice; + send_generic_message("cleartempassetdata", strings, invoice); } void handle_region_dump_settings(void*) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; + } } void handle_dump_group_info(void *) { - gAgent.dumpGroupInfo(); + gAgent.dumpGroupInfo(); } void handle_dump_capabilities_info(void *) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->logActiveCapabilities(); - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + regionp->logActiveCapabilities(); + } } void handle_dump_region_object_cache(void*) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->dumpCache(); - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + regionp->dumpCache(); + } } void handle_reset_interest_lists(void *) @@ -3992,18 +3992,18 @@ void handle_reset_interest_lists(void *) void handle_dump_focus() { - LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; + LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; } class LLSelfStandUp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.standUp(); + return true; + } }; bool enable_standup_self() @@ -4024,202 +4024,202 @@ class LLSelfSitDown : public view_listener_t bool show_sitdown_self() { - return isAgentAvatarValid() && !gAgentAvatarp->isSitting(); + return isAgentAvatarValid() && !gAgentAvatarp->isSitting(); } bool enable_sitdown_self() { - return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); + return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } class LLSelfToggleSitStand : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (isAgentAvatarValid()) - { - if (gAgentAvatarp->isSitting()) - { - gAgent.standUp(); - } - else - { - gAgent.sitDown(); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (isAgentAvatarValid()) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + } + else + { + gAgent.sitDown(); + } + } + return true; + } }; bool enable_sit_stand() { - return enable_sitdown_self() || enable_standup_self(); + return enable_sitdown_self() || enable_standup_self(); } bool enable_fly_land() { - return gAgent.getFlying() || LLAgent::enableFlying(); + return gAgent.getFlying() || LLAgent::enableFlying(); } class LLCheckPanelPeopleTab : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string panel_name = userdata.asString(); - LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); - if(panel && panel->isInVisibleChain()) - { - return true; - } - return false; - } + LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); + if(panel && panel->isInVisibleChain()) + { + return true; + } + return false; + } }; // Toggle one of "People" panel tabs in side tray. class LLTogglePanelPeopleTab : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); - - LLSD param; - param["people_panel_tab_name"] = panel_name; - - if ( panel_name == "friends_panel" - || panel_name == "groups_panel" - || panel_name == "nearby_panel" - || panel_name == "blocked_panel") - { - return togglePeoplePanel(panel_name, param); - } - else - { - return false; - } - } - - static bool togglePeoplePanel(const std::string& panel_name, const LLSD& param) - { - LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); - if(!panel) - return false; - - if (panel->isInVisibleChain()) - { - LLFloaterReg::hideInstance("people"); - } - else - { - LLFloaterSidePanelContainer::showPanel("people", "panel_people", param) ; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string panel_name = userdata.asString(); + + LLSD param; + param["people_panel_tab_name"] = panel_name; + + if ( panel_name == "friends_panel" + || panel_name == "groups_panel" + || panel_name == "nearby_panel" + || panel_name == "blocked_panel") + { + return togglePeoplePanel(panel_name, param); + } + else + { + return false; + } + } + + static bool togglePeoplePanel(const std::string& panel_name, const LLSD& param) + { + LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); + if(!panel) + return false; + + if (panel->isInVisibleChain()) + { + LLFloaterReg::hideInstance("people"); + } + else + { + LLFloaterSidePanelContainer::showPanel("people", "panel_people", param) ; + } + + return true; + } }; BOOL check_admin_override(void*) { - return gAgent.getAdminOverride(); + return gAgent.getAdminOverride(); } void handle_admin_override_toggle(void*) { - gAgent.setAdminOverride(!gAgent.getAdminOverride()); + gAgent.setAdminOverride(!gAgent.getAdminOverride()); - // The above may have affected which debug menus are visible - show_debug_menus(); + // The above may have affected which debug menus are visible + show_debug_menus(); } void handle_visual_leak_detector_toggle(void*) { - static bool vld_enabled = false; + static bool vld_enabled = false; - if ( vld_enabled ) - { + if ( vld_enabled ) + { #ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) + // only works for debug builds (hard coded into vld.h) #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDDisable(); + // start with Visual Leak Detector turned off + VLDDisable(); #endif // _DEBUG #endif // INCLUDE_VLD - vld_enabled = false; - } - else - { + vld_enabled = false; + } + else + { #ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) - #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDEnable(); - #endif // _DEBUG + // only works for debug builds (hard coded into vld.h) + #ifdef _DEBUG + // start with Visual Leak Detector turned off + VLDEnable(); + #endif // _DEBUG #endif // INCLUDE_VLD - vld_enabled = true; - }; + vld_enabled = true; + }; } void handle_god_mode(void*) { - gAgent.requestEnterGodMode(); + gAgent.requestEnterGodMode(); } void handle_leave_god_mode(void*) { - gAgent.requestLeaveGodMode(); + gAgent.requestLeaveGodMode(); } void set_god_level(U8 god_level) { - U8 old_god_level = gAgent.getGodLevel(); - gAgent.setGodLevel( god_level ); - LLViewerParcelMgr::getInstance()->notifyObservers(); + U8 old_god_level = gAgent.getGodLevel(); + gAgent.setGodLevel( god_level ); + LLViewerParcelMgr::getInstance()->notifyObservers(); - // God mode changes region visibility - LLWorldMap::getInstance()->reloadItems(true); + // God mode changes region visibility + LLWorldMap::getInstance()->reloadItems(true); - // inventory in items may change in god mode - gObjectList.dirtyAllObjectInventory(); + // inventory in items may change in god mode + gObjectList.dirtyAllObjectInventory(); if(gViewerWindow) { gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, LLGridManager::getInstance()->isInProductionGrid()); } - + LLSD args; - if(god_level > GOD_NOT) - { - args["LEVEL"] = llformat("%d",(S32)god_level); - LLNotificationsUtil::add("EnteringGodMode", args); - } - else - { - args["LEVEL"] = llformat("%d",(S32)old_god_level); - LLNotificationsUtil::add("LeavingGodMode", args); - } - - // changing god-level can affect which menus we see - show_debug_menus(); - - // changing god-level can invalidate search results - LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search")); - if (search) - { - search->godLevelChanged(god_level); - } + if(god_level > GOD_NOT) + { + args["LEVEL"] = llformat("%d",(S32)god_level); + LLNotificationsUtil::add("EnteringGodMode", args); + } + else + { + args["LEVEL"] = llformat("%d",(S32)old_god_level); + LLNotificationsUtil::add("LeavingGodMode", args); + } + + // changing god-level can affect which menus we see + show_debug_menus(); + + // changing god-level can invalidate search results + LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search")); + if (search) + { + search->godLevelChanged(god_level); + } } #ifdef TOGGLE_HACKED_GODLIKE_VIEWER void handle_toggle_hacked_godmode(void*) { - gHackGodmode = !gHackGodmode; - set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); + gHackGodmode = !gHackGodmode; + set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); } BOOL check_toggle_hacked_godmode(void*) { - return gHackGodmode; + return gHackGodmode; } bool enable_toggle_hacked_godmode(void*) @@ -4230,174 +4230,174 @@ bool enable_toggle_hacked_godmode(void*) void process_grant_godlike_powers(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) - { - U8 god_level; - msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); - set_god_level(god_level); - } - else - { - LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; - } + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) + { + U8 god_level; + msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); + set_god_level(god_level); + } + else + { + LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; + } } /* class LLHaveCallingcard : public LLInventoryCollectFunctor { public: - LLHaveCallingcard(const LLUUID& agent_id); - virtual ~LLHaveCallingcard() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL isThere() const { return mIsThere;} + LLHaveCallingcard(const LLUUID& agent_id); + virtual ~LLHaveCallingcard() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + BOOL isThere() const { return mIsThere;} protected: - LLUUID mID; - BOOL mIsThere; + LLUUID mID; + BOOL mIsThere; }; LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) : - mID(agent_id), - mIsThere(FALSE) + mID(agent_id), + mIsThere(FALSE) { } bool LLHaveCallingcard::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item) - { - if((item->getType() == LLAssetType::AT_CALLINGCARD) - && (item->getCreatorUUID() == mID)) - { - mIsThere = TRUE; - } - } - return FALSE; + LLInventoryItem* item) +{ + if(item) + { + if((item->getType() == LLAssetType::AT_CALLINGCARD) + && (item->getCreatorUUID() == mID)) + { + mIsThere = TRUE; + } + } + return FALSE; } */ BOOL is_agent_mappable(const LLUUID& agent_id) { - const LLRelationship* buddy_info = NULL; - bool is_friend = LLAvatarActions::isFriend(agent_id); + const LLRelationship* buddy_info = NULL; + bool is_friend = LLAvatarActions::isFriend(agent_id); - if (is_friend) - buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); + if (is_friend) + buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); - return (buddy_info && - buddy_info->isOnline() && - buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) - ); + return (buddy_info && + buddy_info->isOnline() && + buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) + ); } // Enable a menu item when you don't have someone's card. class LLAvatarEnableAddFriend : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); + return new_value; + } }; void request_friendship(const LLUUID& dest_id) { - LLViewerObject* dest = gObjectList.findObject(dest_id); - if(dest && dest->isAvatar()) - { - std::string full_name; - LLNameValue* nvfirst = dest->getNVPair("FirstName"); - LLNameValue* nvlast = dest->getNVPair("LastName"); - if(nvfirst && nvlast) - { - full_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - if (!full_name.empty()) - { - LLAvatarActions::requestFriendshipDialog(dest_id, full_name); - } - else - { - LLNotificationsUtil::add("CantOfferFriendship"); - } - } + LLViewerObject* dest = gObjectList.findObject(dest_id); + if(dest && dest->isAvatar()) + { + std::string full_name; + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if(nvfirst && nvlast) + { + full_name = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + } + if (!full_name.empty()) + { + LLAvatarActions::requestFriendshipDialog(dest_id, full_name); + } + else + { + LLNotificationsUtil::add("CantOfferFriendship"); + } + } } class LLEditEnableCustomizeAvatar : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentWearables.areWearablesLoaded(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgentWearables.areWearablesLoaded(); + return new_value; + } }; class LLEnableEditShape : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - } + bool handleEvent(const LLSD& userdata) + { + return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + } }; class LLEnableHoverHeight : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.getRegion() && gAgent.getRegion()->avatarHoverHeightEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.getRegion() && gAgent.getRegion()->avatarHoverHeightEnabled(); + } }; class LLEnableEditPhysics : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - return TRUE; - } + bool handleEvent(const LLSD& userdata) + { + //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + return TRUE; + } }; bool is_object_sittable() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (object && object->getPCode() == LL_PCODE_VOLUME) - { - return true; - } - else - { - return false; - } + if (object && object->getPCode() == LL_PCODE_VOLUME) + { + return true; + } + else + { + return false; + } } // only works on pie menu void handle_object_sit(LLViewerObject *object, const LLVector3 &offset) { - // get object selection offset + // get object selection offset - if (object && object->getPCode() == LL_PCODE_VOLUME) - { + if (object && object->getPCode() == LL_PCODE_VOLUME) + { - gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_TargetObject); - gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_TargetObject); + gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); + gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); - object->getRegion()->sendReliableMessage(); - } + object->getRegion()->sendReliableMessage(); + } } void handle_object_sit_or_stand() @@ -4432,12 +4432,12 @@ void handle_object_sit(const LLUUID& object_id) void near_sit_down_point(BOOL success, void *) { - if (success) - { - gAgent.setFlying(FALSE); - gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP); // might have been set by autopilot - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - } + if (success) + { + gAgent.setFlying(FALSE); + gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP); // might have been set by autopilot + gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + } } class LLLandSit : public view_listener_t @@ -4484,120 +4484,120 @@ void reset_view_final( BOOL proceed ); void handle_reset_view() { - if (gAgentCamera.cameraCustomizeAvatar()) - { - // switching to outfit selector should automagically save any currently edited wearable - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); - } - gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); - reset_view_final( TRUE ); - LLFloaterCamera::resetCameraMode(); + if (gAgentCamera.cameraCustomizeAvatar()) + { + // switching to outfit selector should automagically save any currently edited wearable + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); + } + gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); + reset_view_final( TRUE ); + LLFloaterCamera::resetCameraMode(); } class LLViewResetView : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_reset_view(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_reset_view(); + return true; + } }; // Note: extra parameters allow this function to be called from dialog. -void reset_view_final( BOOL proceed ) +void reset_view_final( BOOL proceed ) { - if( !proceed ) - { - return; - } + if( !proceed ) + { + return; + } - gAgentCamera.resetView(TRUE, TRUE); - gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + gAgentCamera.resetView(TRUE, TRUE); + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); } class LLViewLookAtLastChatter : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgentCamera.lookAtLastChat(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgentCamera.lookAtLastChat(); + return true; + } }; class LLViewMouselook : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (!gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToMouselook(); - } - else - { - gAgentCamera.changeCameraToDefault(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (!gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToMouselook(); + } + else + { + gAgentCamera.changeCameraToDefault(); + } + return true; + } }; class LLViewDefaultUISize : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setF32("UIScaleFactor", 1.0f); - gSavedSettings.setBOOL("UIAutoScale", FALSE); - gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gSavedSettings.setF32("UIScaleFactor", 1.0f); + gSavedSettings.setBOOL("UIAutoScale", FALSE); + gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); + return true; + } }; class LLViewToggleUI : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - LLNotification::Params params("ConfirmHideUI"); - params.functor.function(boost::bind(&LLViewToggleUI::confirm, this, _1, _2)); - LLSD substitutions; + bool handleEvent(const LLSD& userdata) + { + if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) + { + LLNotification::Params params("ConfirmHideUI"); + params.functor.function(boost::bind(&LLViewToggleUI::confirm, this, _1, _2)); + LLSD substitutions; #if LL_DARWIN - substitutions["SHORTCUT"] = "Cmd+Shift+U"; + substitutions["SHORTCUT"] = "Cmd+Shift+U"; #else - substitutions["SHORTCUT"] = "Ctrl+Shift+U"; + substitutions["SHORTCUT"] = "Ctrl+Shift+U"; #endif - params.substitutions = substitutions; - if (!gSavedSettings.getBOOL("HideUIControls")) - { - // hiding, so show notification - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } - } - return true; - } - - void confirm(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (option == 0) // OK - { - gViewerWindow->setUIVisibility(gSavedSettings.getBOOL("HideUIControls")); - LLPanelStandStopFlying::getInstance()->setVisible(gSavedSettings.getBOOL("HideUIControls")); - gSavedSettings.setBOOL("HideUIControls",!gSavedSettings.getBOOL("HideUIControls")); - } - } -}; + params.substitutions = substitutions; + if (!gSavedSettings.getBOOL("HideUIControls")) + { + // hiding, so show notification + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } + } + return true; + } -void handle_duplicate_in_place(void*) + void confirm(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (option == 0) // OK + { + gViewerWindow->setUIVisibility(gSavedSettings.getBOOL("HideUIControls")); + LLPanelStandStopFlying::getInstance()->setVisible(gSavedSettings.getBOOL("HideUIControls")); + gSavedSettings.setBOOL("HideUIControls",!gSavedSettings.getBOOL("HideUIControls")); + } + } +}; + +void handle_duplicate_in_place(void*) { - LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; + LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; - LLVector3 offset(0.f, 0.f, 0.f); - LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); + LLVector3 offset(0.f, 0.f, 0.f); + LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); } @@ -4606,121 +4606,121 @@ void handle_duplicate_in_place(void*) * No longer able to support viewer side manipulations in this way * void god_force_inv_owner_permissive(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void*) -{ - typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t; - item_array_t items; - - LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); - LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); - for ( ; inv_it != inv_end; ++inv_it) - { - if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) - { - LLInventoryObject* obj = *inv_it; - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); - LLPermissions perm(new_item->getPermissions()); - perm.setMaskBase(PERM_ALL); - perm.setMaskOwner(PERM_ALL); - new_item->setPermissions(perm); - items.push_back(new_item); - } - } - item_array_t::iterator end = items.end(); - item_array_t::iterator it; - for(it = items.begin(); it != end; ++it) - { - // since we have the inventory item in the callback, it should not - // invalidate iteration through the selection manager. - object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); - } + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void*) +{ + typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t; + item_array_t items; + + LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); + LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); + for ( ; inv_it != inv_end; ++inv_it) + { + if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) + { + LLInventoryObject* obj = *inv_it; + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); + LLPermissions perm(new_item->getPermissions()); + perm.setMaskBase(PERM_ALL); + perm.setMaskOwner(PERM_ALL); + new_item->setPermissions(perm); + items.push_back(new_item); + } + } + item_array_t::iterator end = items.end(); + item_array_t::iterator it; + for(it = items.begin(); it != end; ++it) + { + // since we have the inventory item in the callback, it should not + // invalidate iteration through the selection manager. + object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); + } } */ void handle_object_owner_permissive(void*) { - // only send this if they're a god. - if(gAgent.isGodlike()) - { - // do the objects. - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); - } + // only send this if they're a god. + if(gAgent.isGodlike()) + { + // do the objects. + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); + } } void handle_object_owner_self(void*) { - // only send this if they're a god. - if(gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); - } + // only send this if they're a god. + if(gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); + } } // Shortcut to set owner permissions to not editable. void handle_object_lock(void*) { - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); } void handle_object_asset_ids(void*) { - // only send this if they're a god. - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); - } + // only send this if they're a god. + if (gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); + } } void handle_force_parcel_owner_to_me(void*) { - LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); + LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); } void handle_force_parcel_to_content(void*) { - LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); + LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); } void handle_claim_public_land(void*) { - if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) - { - LLNotificationsUtil::add("ClaimPublicLand"); - return; - } - - LLVector3d west_south_global; - LLVector3d east_north_global; - LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); - LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); - LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GodlikeMessage"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - msg->nextBlock("MethodData"); - msg->addString("Method", "claimpublicland"); - msg->addUUID("Invoice", LLUUID::null); - std::string buffer; - buffer = llformat( "%f", west_south.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", west_south.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - gAgent.sendReliableMessage(); + if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) + { + LLNotificationsUtil::add("ClaimPublicLand"); + return; + } + + LLVector3d west_south_global; + LLVector3d east_north_global; + LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); + LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); + LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("GodlikeMessage"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + msg->nextBlock("MethodData"); + msg->addString("Method", "claimpublicland"); + msg->addUUID("Invoice", LLUUID::null); + std::string buffer; + buffer = llformat( "%f", west_south.mV[VX]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", west_south.mV[VY]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", east_north.mV[VX]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", east_north.mV[VY]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + gAgent.sendReliableMessage(); } @@ -4728,286 +4728,286 @@ void handle_claim_public_land(void*) // HACK for easily testing new avatar geometry void handle_god_request_avatar_geometry(void *) { - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); - } + if (gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); + } } static bool get_derezzable_objects( - EDeRezDestination dest, - std::string& error, - LLViewerRegion*& first_region, - std::vector<LLViewerObjectPtr>* derez_objectsp, - bool only_check = false) -{ - bool found = false; - - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if (derez_objectsp) - derez_objectsp->reserve(selection->getRootObjectCount()); - - // Check conditions that we can't deal with, building a list of - // everything that we'll actually be derezzing. - for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); - iter != selection->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerRegion* region = object->getRegion(); - if (!first_region) - { - first_region = region; - } - else - { - if(region != first_region) - { - // Derez doesn't work at all if the some of the objects - // are in regions besides the first object selected. - - // ...crosses region boundaries - error = "AcquireErrorObjectSpan"; - break; - } - } - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } - - // If AssetContainers are being sent back, they will appear as - // boxes in the owner's inventory. - if (object->getNVPair("AssetContainer") - && dest != DRD_RETURN_TO_OWNER) - { - // this object is an asset container, derez its contents, not it - LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; - /* - object->requestInventory(container_inventory_arrived, - (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); - */ - continue; - } - BOOL can_derez_current = FALSE; - switch(dest) - { - case DRD_TAKE_INTO_AGENT_INVENTORY: - case DRD_TRASH: - if (!object->isPermanentEnforced() && - ((node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) - || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)))) - { - can_derez_current = TRUE; - } - break; - - case DRD_RETURN_TO_OWNER: - if(!object->isAttachment()) - { - can_derez_current = TRUE; - } - break; - - default: - if((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permCopy()) - || gAgent.isGodlike()) - { - can_derez_current = TRUE; - } - break; - } - if(can_derez_current) - { - found = true; - - if (only_check) - // one found, no need to traverse to the end - break; - - if (derez_objectsp) - derez_objectsp->push_back(object); - - } - } - - return found; + EDeRezDestination dest, + std::string& error, + LLViewerRegion*& first_region, + std::vector<LLViewerObjectPtr>* derez_objectsp, + bool only_check = false) +{ + bool found = false; + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + + if (derez_objectsp) + derez_objectsp->reserve(selection->getRootObjectCount()); + + // Check conditions that we can't deal with, building a list of + // everything that we'll actually be derezzing. + for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + iter != selection->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + LLViewerRegion* region = object->getRegion(); + if (!first_region) + { + first_region = region; + } + else + { + if(region != first_region) + { + // Derez doesn't work at all if the some of the objects + // are in regions besides the first object selected. + + // ...crosses region boundaries + error = "AcquireErrorObjectSpan"; + break; + } + } + if (object->isAvatar()) + { + // ...don't acquire avatars + continue; + } + + // If AssetContainers are being sent back, they will appear as + // boxes in the owner's inventory. + if (object->getNVPair("AssetContainer") + && dest != DRD_RETURN_TO_OWNER) + { + // this object is an asset container, derez its contents, not it + LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; + /* + object->requestInventory(container_inventory_arrived, + (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); + */ + continue; + } + BOOL can_derez_current = FALSE; + switch(dest) + { + case DRD_TAKE_INTO_AGENT_INVENTORY: + case DRD_TRASH: + if (!object->isPermanentEnforced() && + ((node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) + || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)))) + { + can_derez_current = TRUE; + } + break; + + case DRD_RETURN_TO_OWNER: + if(!object->isAttachment()) + { + can_derez_current = TRUE; + } + break; + + default: + if((node->mPermissions->allowTransferTo(gAgent.getID()) + && object->permCopy()) + || gAgent.isGodlike()) + { + can_derez_current = TRUE; + } + break; + } + if(can_derez_current) + { + found = true; + + if (only_check) + // one found, no need to traverse to the end + break; + + if (derez_objectsp) + derez_objectsp->push_back(object); + + } + } + + return found; } static bool can_derez(EDeRezDestination dest) { - LLViewerRegion* first_region = NULL; - std::string error; - return get_derezzable_objects(dest, error, first_region, NULL, true); + LLViewerRegion* first_region = NULL; + std::string error; + return get_derezzable_objects(dest, error, first_region, NULL, true); } static void derez_objects( - EDeRezDestination dest, - const LLUUID& dest_id, - LLViewerRegion*& first_region, - std::string& error, - std::vector<LLViewerObjectPtr>* objectsp) -{ - std::vector<LLViewerObjectPtr> derez_objects; - - if (!objectsp) // if objects to derez not specified - { - // get them from selection - if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) - { - LL_WARNS() << "No objects to derez" << LL_ENDL; - return; - } - - objectsp = &derez_objects; - } - - - if(gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - - // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per - // root. I lopped off a few (33) to provide a bit - // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. - // This gives us a maximum of 63500 root objects - which should - // satisfy anybody. - const S32 MAX_ROOTS_PER_PACKET = 250; - const S32 MAX_PACKET_COUNT = 254; - F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); - if(packets > (F32)MAX_PACKET_COUNT) - { - error = "AcquireErrorTooManyObjects"; - } - - if(error.empty() && objectsp->size() > 0) - { - U8 d = (U8)dest; - LLUUID tid; - tid.generate(); - U8 packet_count = (U8)packets; - S32 object_index = 0; - S32 objects_in_packet = 0; - LLMessageSystem* msg = gMessageSystem; - for(U8 packet_number = 0; - packet_number < packet_count; - ++packet_number) - { - msg->newMessageFast(_PREHASH_DeRezObject); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_AgentBlock); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->addU8Fast(_PREHASH_Destination, d); - msg->addUUIDFast(_PREHASH_DestinationID, dest_id); - msg->addUUIDFast(_PREHASH_TransactionID, tid); - msg->addU8Fast(_PREHASH_PacketCount, packet_count); - msg->addU8Fast(_PREHASH_PacketNumber, packet_number); - objects_in_packet = 0; - while((object_index < objectsp->size()) - && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) - - { - LLViewerObject* object = objectsp->at(object_index++); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - // VEFFECT: DerezObject - LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(object->getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - } - msg->sendReliable(first_region->getHost()); - } - make_ui_sound("UISndObjectRezOut"); - - // Busy count decremented by inventory update, so only increment - // if will be causing an update. - if (dest != DRD_RETURN_TO_OWNER) - { - gViewerWindow->getWindow()->incBusyCount(); - } - } - else if(!error.empty()) - { - LLNotificationsUtil::add(error); - } + EDeRezDestination dest, + const LLUUID& dest_id, + LLViewerRegion*& first_region, + std::string& error, + std::vector<LLViewerObjectPtr>* objectsp) +{ + std::vector<LLViewerObjectPtr> derez_objects; + + if (!objectsp) // if objects to derez not specified + { + // get them from selection + if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) + { + LL_WARNS() << "No objects to derez" << LL_ENDL; + return; + } + + objectsp = &derez_objects; + } + + + if(gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + + // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per + // root. I lopped off a few (33) to provide a bit + // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. + // This gives us a maximum of 63500 root objects - which should + // satisfy anybody. + const S32 MAX_ROOTS_PER_PACKET = 250; + const S32 MAX_PACKET_COUNT = 254; + F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); + if(packets > (F32)MAX_PACKET_COUNT) + { + error = "AcquireErrorTooManyObjects"; + } + + if(error.empty() && objectsp->size() > 0) + { + U8 d = (U8)dest; + LLUUID tid; + tid.generate(); + U8 packet_count = (U8)packets; + S32 object_index = 0; + S32 objects_in_packet = 0; + LLMessageSystem* msg = gMessageSystem; + for(U8 packet_number = 0; + packet_number < packet_count; + ++packet_number) + { + msg->newMessageFast(_PREHASH_DeRezObject); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_AgentBlock); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->addU8Fast(_PREHASH_Destination, d); + msg->addUUIDFast(_PREHASH_DestinationID, dest_id); + msg->addUUIDFast(_PREHASH_TransactionID, tid); + msg->addU8Fast(_PREHASH_PacketCount, packet_count); + msg->addU8Fast(_PREHASH_PacketNumber, packet_number); + objects_in_packet = 0; + while((object_index < objectsp->size()) + && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) + + { + LLViewerObject* object = objectsp->at(object_index++); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); + // VEFFECT: DerezObject + LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(object->getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + } + msg->sendReliable(first_region->getHost()); + } + make_ui_sound("UISndObjectRezOut"); + + // Busy count decremented by inventory update, so only increment + // if will be causing an update. + if (dest != DRD_RETURN_TO_OWNER) + { + gViewerWindow->getWindow()->incBusyCount(); + } + } + else if(!error.empty()) + { + LLNotificationsUtil::add(error); + } } static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) { - LLViewerRegion* first_region = NULL; - std::string error; - derez_objects(dest, dest_id, first_region, error, NULL); + LLViewerRegion* first_region = NULL; + std::string error; + derez_objects(dest, dest_id, first_region, error, NULL); } void handle_take_copy() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } void handle_link_objects() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - LLFloaterReg::toggleInstanceOrBringToFront("places"); - } - else - { - LLSelectMgr::getInstance()->linkObjects(); - } + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLFloaterReg::toggleInstanceOrBringToFront("places"); + } + else + { + LLSelectMgr::getInstance()->linkObjects(); + } } // You can return an object to its owner if it is on your land. class LLObjectReturn : public view_listener_t { public: - LLObjectReturn() : mFirstRegion(NULL) {} + LLObjectReturn() : mFirstRegion(NULL) {} private: - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; - - mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; + + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. - get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); - return true; - } + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); + return true; + } - bool onReturnToOwner(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects); - } + bool onReturnToOwner(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects); + } - mReturnableObjects.clear(); - mError.clear(); - mFirstRegion = NULL; + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; - // drop reference to current selection - mObjectSelection = NULL; - return false; - } + // drop reference to current selection + mObjectSelection = NULL; + return false; + } - LLObjectSelectionHandle mObjectSelection; + LLObjectSelectionHandle mObjectSelection; - std::vector<LLViewerObjectPtr> mReturnableObjects; - std::string mError; - LLViewerRegion* mFirstRegion; + std::vector<LLViewerObjectPtr> mReturnableObjects; + std::string mError; + LLViewerRegion* mFirstRegion; }; @@ -5015,187 +5015,187 @@ private: // over land you own. class LLObjectEnableReturn : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - // Do not enable if nothing selected - return false; - } + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + // Do not enable if nothing selected + return false; + } #ifdef HACKED_GODLIKE_VIEWER - bool new_value = true; + bool new_value = true; #else - bool new_value = false; - if (gAgent.isGodlike()) - { - new_value = true; - } - else - { - new_value = can_derez(DRD_RETURN_TO_OWNER); - } + bool new_value = false; + if (gAgent.isGodlike()) + { + new_value = true; + } + else + { + new_value = can_derez(DRD_RETURN_TO_OWNER); + } #endif - return new_value; - } + return new_value; + } }; void force_take_copy(void*) { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); } void handle_take() { - // we want to use the folder this was derezzed from if it's - // available. Otherwise, derez to the normal place. - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - BOOL you_own_everything = TRUE; - BOOL locked_but_takeable_object = FALSE; - LLUUID category_id; - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if(object) - { - if(!object->permYouOwner()) - { - you_own_everything = FALSE; - } - - if(!object->permMove()) - { - locked_but_takeable_object = TRUE; - } - } - if(node->mFolderID.notNull()) - { - if(category_id.isNull()) - { - category_id = node->mFolderID; - } - else if(category_id != node->mFolderID) - { - // we have found two potential destinations. break out - // now and send to the default location. - category_id.setNull(); - break; - } - } - } - if(category_id.notNull()) - { - // there is an unambiguous destination. See if this agent has - // such a location and it is not in the trash or library - if(!gInventory.getCategory(category_id)) - { - // nope, set to NULL. - category_id.setNull(); - } - if(category_id.notNull()) - { - // check trash - const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) - { - category_id.setNull(); - } - - // check library - if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) - { - category_id.setNull(); - } - - // check inbox - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); - if (category_id == inbox_id || gInventory.isObjectDescendentOf(category_id, inbox_id)) - { - category_id.setNull(); - } - } - } - if(category_id.isNull()) - { - category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - } - LLSD payload; - payload["folder_id"] = category_id; - - LLNotification::Params params("ConfirmObjectTakeLock"); - params.payload(payload); - // MAINT-290 - // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. - // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened - params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); - - if(locked_but_takeable_object || - !you_own_everything) - { - if(locked_but_takeable_object && you_own_everything) - { - params.name("ConfirmObjectTakeLock"); - } - else if(!locked_but_takeable_object && !you_own_everything) - { - params.name("ConfirmObjectTakeNoOwn"); - } - else - { - params.name("ConfirmObjectTakeLockNoOwn"); - } - - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } + // we want to use the folder this was derezzed from if it's + // available. Otherwise, derez to the normal place. + if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + return; + } + + BOOL you_own_everything = TRUE; + BOOL locked_but_takeable_object = FALSE; + LLUUID category_id; + + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if(object) + { + if(!object->permYouOwner()) + { + you_own_everything = FALSE; + } + + if(!object->permMove()) + { + locked_but_takeable_object = TRUE; + } + } + if(node->mFolderID.notNull()) + { + if(category_id.isNull()) + { + category_id = node->mFolderID; + } + else if(category_id != node->mFolderID) + { + // we have found two potential destinations. break out + // now and send to the default location. + category_id.setNull(); + break; + } + } + } + if(category_id.notNull()) + { + // there is an unambiguous destination. See if this agent has + // such a location and it is not in the trash or library + if(!gInventory.getCategory(category_id)) + { + // nope, set to NULL. + category_id.setNull(); + } + if(category_id.notNull()) + { + // check trash + const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) + { + category_id.setNull(); + } + + // check library + if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) + { + category_id.setNull(); + } + + // check inbox + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); + if (category_id == inbox_id || gInventory.isObjectDescendentOf(category_id, inbox_id)) + { + category_id.setNull(); + } + } + } + if(category_id.isNull()) + { + category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + } + LLSD payload; + payload["folder_id"] = category_id; + + LLNotification::Params params("ConfirmObjectTakeLock"); + params.payload(payload); + // MAINT-290 + // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. + // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened + params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); + + if(locked_but_takeable_object || + !you_own_everything) + { + if(locked_but_takeable_object && you_own_everything) + { + params.name("ConfirmObjectTakeLock"); + } + else if(!locked_but_takeable_object && !you_own_everything) + { + params.name("ConfirmObjectTakeNoOwn"); + } + else + { + params.name("ConfirmObjectTakeLockNoOwn"); + } + + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } } void handle_object_show_inspector() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* objectp = selection->getFirstRootObject(TRUE); - if (!objectp) - { - return; - } + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* objectp = selection->getFirstRootObject(TRUE); + if (!objectp) + { + return; + } - LLSD params; - params["object_id"] = objectp->getID(); - LLFloaterReg::showInstance("inspect_object", params); + LLSD params; + params["object_id"] = objectp->getID(); + LLFloaterReg::showInstance("inspect_object", params); } void handle_avatar_show_inspector() { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLSD params; - params["avatar_id"] = avatar->getID(); - LLFloaterReg::showInstance("inspect_avatar", params); - } + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLSD params; + params["avatar_id"] = avatar->getID(); + LLFloaterReg::showInstance("inspect_avatar", params); + } } bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection_handle) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(enable_take() && (option == 0)) - { - derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(enable_take() && (option == 0)) + { + derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); + } + return false; } // You can take an item when it is public and transferrable, or when @@ -5203,101 +5203,101 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect // one item selected can be copied to inventory. BOOL enable_take() { - if (sitting_on_selection()) - { - return FALSE; - } - - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } + if (sitting_on_selection()) + { + return FALSE; + } + + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (object->isAvatar()) + { + // ...don't acquire avatars + continue; + } #ifdef HACKED_GODLIKE_VIEWER - return TRUE; + return TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() + if (!LLGridManager::getInstance()->isInProductionGrid() && gAgent.isGodlike()) - { - return TRUE; - } + { + return TRUE; + } # endif - if(!object->isPermanentEnforced() && - ((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permModify()) - || (node->mPermissions->getOwner() == gAgent.getID()))) - { - return !object->isAttachment(); - } + if(!object->isPermanentEnforced() && + ((node->mPermissions->allowTransferTo(gAgent.getID()) + && object->permModify()) + || (node->mPermissions->getOwner() == gAgent.getID()))) + { + return !object->isAttachment(); + } #endif - } - return FALSE; + } + return FALSE; } void handle_buy_or_take() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - if (is_selection_buy_not_take()) - { - S32 total_price = selection_price(); - - if (total_price <= gStatusBar->getBalance() || total_price == 0) - { - handle_buy(); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", total_price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); - } - } - else - { - handle_take(); - } + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + return; + } + + if (is_selection_buy_not_take()) + { + S32 total_price = selection_price(); + + if (total_price <= gStatusBar->getBalance() || total_price == 0) + { + handle_buy(); + } + else + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", total_price); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); + } + } + else + { + handle_take(); + } } bool visible_buy_object() { - return is_selection_buy_not_take() && enable_buy_object(); + return is_selection_buy_not_take() && enable_buy_object(); } bool visible_take_object() { - return !is_selection_buy_not_take() && enable_take(); + return !is_selection_buy_not_take() && enable_take(); } bool tools_visible_buy_object() { - return is_selection_buy_not_take(); + return is_selection_buy_not_take(); } bool tools_visible_take_object() { - return !is_selection_buy_not_take(); + return !is_selection_buy_not_take(); } class LLToolsEnableBuyOrTake : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool is_buy = is_selection_buy_not_take(); - bool new_value = is_buy ? enable_buy_object() : enable_take(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool is_buy = is_selection_buy_not_take(); + bool new_value = is_buy ? enable_buy_object() : enable_take(); + return new_value; + } }; // This is a small helper function to determine if we have a buy or a @@ -5318,255 +5318,255 @@ class LLToolsEnableBuyOrTake : public view_listener_t // FALSE if selection is a 'take' BOOL is_selection_buy_not_take() { - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale, thus, - // it's a buy - return TRUE; - } - } - return FALSE; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) + { + // you do not own the object and it is for sale, thus, + // it's a buy + return TRUE; + } + } + return FALSE; } S32 selection_price() { - S32 total_price = 0; - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale. - // Add its price. - total_price += node->mSaleInfo.getSalePrice(); - } - } - - return total_price; + S32 total_price = 0; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) + { + // you do not own the object and it is for sale. + // Add its price. + total_price += node->mSaleInfo.getSalePrice(); + } + } + + return total_price; } /* bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LL_INFOS() << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << LL_ENDL; - LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_INFOS() << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << LL_ENDL; + LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); + } + return false; } */ void show_buy_currency(const char* extra) { - // Don't show currency web page for branded clients. + // Don't show currency web page for branded clients. /* - std::ostringstream mesg; - if (extra != NULL) - { - mesg << extra << "\n \n"; - } - mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; + std::ostringstream mesg; + if (extra != NULL) + { + mesg << extra << "\n \n"; + } + mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; */ - LLSD args; - if (extra != NULL) - { - args["EXTRA"] = extra; - } - LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); + LLSD args; + if (extra != NULL) + { + args["EXTRA"] = extra; + } + LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); } void handle_buy() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - LLSaleInfo sale_info; - BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); - if (!valid) return; + LLSaleInfo sale_info; + BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); + if (!valid) return; - S32 price = sale_info.getSalePrice(); - - if (price > 0 && price > gStatusBar->getBalance()) - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); - return; - } + S32 price = sale_info.getSalePrice(); - if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) - { - handle_buy_contents(sale_info); - } - else - { - handle_buy_object(sale_info); - } + if (price > 0 && price > gStatusBar->getBalance()) + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", price); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); + return; + } + + if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) + { + handle_buy_contents(sale_info); + } + else + { + handle_buy_object(sale_info); + } } bool anyone_copy_selection(LLSelectNode* nodep) { - bool perm_copy = (bool)(nodep->getObject()->permCopy()); - bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); - return perm_copy && all_copy; + bool perm_copy = (bool)(nodep->getObject()->permCopy()); + bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); + return perm_copy && all_copy; } bool for_sale_selection(LLSelectNode* nodep) { - return nodep->mSaleInfo.isForSale() - && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER - && (nodep->mPermissions->getMaskOwner() & PERM_COPY - || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); + return nodep->mSaleInfo.isForSale() + && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER + && (nodep->mPermissions->getMaskOwner() & PERM_COPY + || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); } BOOL sitting_on_selection() { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (!node) - { - return FALSE; - } + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (!node) + { + return FALSE; + } - if (!node->mValid) - { - return FALSE; - } + if (!node->mValid) + { + return FALSE; + } - LLViewerObject* root_object = node->getObject(); - if (!root_object) - { - return FALSE; - } + LLViewerObject* root_object = node->getObject(); + if (!root_object) + { + return FALSE; + } - // Need to determine if avatar is sitting on this object - if (!isAgentAvatarValid()) return FALSE; + // Need to determine if avatar is sitting on this object + if (!isAgentAvatarValid()) return FALSE; - return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); + return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); } class LLToolsSaveToObjectInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if(node && (node->mValid) && (!node->mFromTaskID.isNull())) + { + // *TODO: check to see if the fromtaskid object exists. + derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); + } + return true; + } }; class LLToolsEnablePathfinding : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); - } + bool handleEvent(const LLSD& userdata) + { + return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + } }; class LLToolsEnablePathfindingView : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); + } }; class LLToolsDoPathfindingRebakeRegion : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); - - if (hasPathfinding) - { - LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); - } + bool handleEvent(const LLSD& userdata) + { + bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); + + if (hasPathfinding) + { + LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); + } - return hasPathfinding; - } + return hasPathfinding; + } }; class LLToolsEnablePathfindingRebakeRegion : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool returnValue = false; + bool handleEvent(const LLSD& userdata) + { + bool returnValue = false; if (LLNavigationBar::instanceExists()) { returnValue = LLNavigationBar::getInstance()->isRebakeNavMeshAvailable(); } - return returnValue; - } + return returnValue; + } }; // Round the position of all root objects to the grid class LLToolsSnapObjectXY : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if (obj->permModify()) - { - LLVector3d pos_global = obj->getPositionGlobal(); - F64 round_x = fmod(pos_global.mdV[VX], snap_size); - if (round_x < snap_size * 0.5) - { - // closer to round down - pos_global.mdV[VX] -= round_x; - } - else - { - // closer to round up - pos_global.mdV[VX] -= round_x; - pos_global.mdV[VX] += snap_size; - } - - F64 round_y = fmod(pos_global.mdV[VY], snap_size); - if (round_y < snap_size * 0.5) - { - pos_global.mdV[VY] -= round_y; - } - else - { - pos_global.mdV[VY] -= round_y; - pos_global.mdV[VY] += snap_size; - } - - obj->setPositionGlobal(pos_global, FALSE); - } - } - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); - return true; - } + bool handleEvent(const LLSD& userdata) + { + F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); + + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (obj->permModify()) + { + LLVector3d pos_global = obj->getPositionGlobal(); + F64 round_x = fmod(pos_global.mdV[VX], snap_size); + if (round_x < snap_size * 0.5) + { + // closer to round down + pos_global.mdV[VX] -= round_x; + } + else + { + // closer to round up + pos_global.mdV[VX] -= round_x; + pos_global.mdV[VX] += snap_size; + } + + F64 round_y = fmod(pos_global.mdV[VY], snap_size); + if (round_y < snap_size * 0.5) + { + pos_global.mdV[VY] -= round_y; + } + else + { + pos_global.mdV[VY] -= round_y; + pos_global.mdV[VY] += snap_size; + } + + obj->setPositionGlobal(pos_global, FALSE); + } + } + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + return true; + } }; // Determine if the option to cycle between linked prims is shown class LLToolsEnableSelectNextPart : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { bool new_value = (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && (gSavedSettings.getBOOL("EditLinkedParts") || LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool())); - return new_value; - } + return new_value; + } }; // Cycle selection through linked children or/and faces in selected object. @@ -5641,61 +5641,61 @@ class LLToolsSelectNextPartFace : public view_listener_t } } - S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - if (cycle_linked && object_count && restart_face_on_part) - { - LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if (selected && selected->getRootEdit()) - { - LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); - children.push_front(selected->getRootEdit()); // need root in the list too - - for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) - { - if ((*iter)->isSelected()) - { - if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include - { - to_select = *iter; - if (fwd) - { - // stop searching if going forward; repeat to get last hit if backward - break; - } - } - else if ((object_count == 1) || (ifwd || iprev)) // single selection or include - { - if (fwd || ifwd) - { - ++iter; - while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) - { - ++iter; // skip sitting avatars and selected if include - } - } - else // backward - { - iter = (iter == children.begin() ? children.end() : iter); - --iter; - while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) - { - --iter; // skip sitting avatars and selected if include - } - } - iter = (iter == children.end() ? children.begin() : iter); - to_select = *iter; - break; - } - } - } - } - } + S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (cycle_linked && object_count && restart_face_on_part) + { + LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (selected && selected->getRootEdit()) + { + LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); + children.push_front(selected->getRootEdit()); // need root in the list too + + for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) + { + if ((*iter)->isSelected()) + { + if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include + { + to_select = *iter; + if (fwd) + { + // stop searching if going forward; repeat to get last hit if backward + break; + } + } + else if ((object_count == 1) || (ifwd || iprev)) // single selection or include + { + if (fwd || ifwd) + { + ++iter; + while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) + { + ++iter; // skip sitting avatars and selected if include + } + } + else // backward + { + iter = (iter == children.begin() ? children.end() : iter); + --iter; + while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) + { + --iter; // skip sitting avatars and selected if include + } + } + iter = (iter == children.end() ? children.begin() : iter); + to_select = *iter; + break; + } + } + } + } + } if (to_select) { if (gFocusMgr.childHasKeyboardFocus(gFloaterTools)) { - gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes + gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes } if (fwd || prev) { @@ -5723,455 +5723,455 @@ class LLToolsSelectNextPartFace : public view_listener_t } return true; } - return true; - } + return true; + } }; class LLToolsStopAllAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.stopCurrentAnimations(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.stopCurrentAnimations(); + return true; + } }; class LLToolsReleaseKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.forceReleaseControls(); + bool handleEvent(const LLSD& userdata) + { + gAgent.forceReleaseControls(); - return true; - } + return true; + } }; class LLToolsEnableReleaseKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.anyControlGrabbed(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.anyControlGrabbed(); + } }; class LLEditEnableCut : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); + return new_value; + } }; class LLEditCut : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->cut(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->cut(); + } + return true; + } }; class LLEditEnableCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); + return new_value; + } }; class LLEditCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->copy(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->copy(); + } + return true; + } }; class LLEditEnablePaste : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); + return new_value; + } }; class LLEditPaste : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->paste(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->paste(); + } + return true; + } }; class LLEditEnableDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); + return new_value; + } }; class LLEditDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // If a text field can do a deletion, it gets precedence over deleting - // an object in the world. - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) - { - LLEditMenuHandler::gEditMenuHandler->doDelete(); - } + bool handleEvent(const LLSD& userdata) + { + // If a text field can do a deletion, it gets precedence over deleting + // an object in the world. + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) + { + LLEditMenuHandler::gEditMenuHandler->doDelete(); + } - // and close any pie/context menus when done - gMenuHolder->hideMenus(); + // and close any pie/context menus when done + gMenuHolder->hideMenus(); - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return true; - } + // When deleting an object we may not actually be done + // Keep selection so we know what to delete when confirmation is needed about the delete + gMenuObject->hide(); + return true; + } }; void handle_spellcheck_replace_with_suggestion(const LLUICtrl* ctrl, const LLSD& param) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) - { - return; - } + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return; + } - U32 index = 0; - if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) - { - return; - } + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return; + } - spellcheck_handler->replaceWithSuggestion(index); + spellcheck_handler->replaceWithSuggestion(index); } bool visible_spellcheck_suggestion(LLUICtrl* ctrl, const LLSD& param) { - LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(ctrl); - const LLContextMenu* menu = (item) ? dynamic_cast<const LLContextMenu*>(item->getParent()) : NULL; - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) - { - return false; - } + LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(ctrl); + const LLContextMenu* menu = (item) ? dynamic_cast<const LLContextMenu*>(item->getParent()) : NULL; + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return false; + } - U32 index = 0; - if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) - { - return false; - } + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return false; + } - item->setLabel(spellcheck_handler->getSuggestion(index)); - return true; + item->setLabel(spellcheck_handler->getSuggestion(index)); + return true; } void handle_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) - { - spellcheck_handler->addToDictionary(); - } + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) + { + spellcheck_handler->addToDictionary(); + } } bool enable_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); } void handle_spellcheck_add_to_ignore(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) - { - spellcheck_handler->addToIgnore(); - } + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) + { + spellcheck_handler->addToIgnore(); + } } bool enable_spellcheck_add_to_ignore(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; - return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); } bool enable_object_return() { - return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && - (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); + return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && + (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); } bool enable_object_delete() { - bool new_value = + bool new_value = #ifdef HACKED_GODLIKE_VIEWER - TRUE; + TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - (!LLGridManager::getInstance()->isInProductionGrid() + (!LLGridManager::getInstance()->isInProductionGrid() && gAgent.isGodlike()) || # endif - LLSelectMgr::getInstance()->canDoDelete(); + LLSelectMgr::getInstance()->canDoDelete(); #endif - return new_value; + return new_value; } class LLObjectsReturnPackage { public: - LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; - ~LLObjectsReturnPackage() - { - mObjectSelection.clear(); - mReturnableObjects.clear(); - mError.clear(); - mFirstRegion = NULL; - }; + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + ~LLObjectsReturnPackage() + { + mObjectSelection.clear(); + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; + }; - LLObjectSelectionHandle mObjectSelection; - std::vector<LLViewerObjectPtr> mReturnableObjects; - std::string mError; - LLViewerRegion *mFirstRegion; + LLObjectSelectionHandle mObjectSelection; + std::vector<LLViewerObjectPtr> mReturnableObjects; + std::string mError; + LLViewerRegion *mFirstRegion; }; static void return_objects(LLObjectsReturnPackage *objectsReturnPackage, const LLSD& notification, const LLSD& response) { - if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); - } + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); + } - delete objectsReturnPackage; + delete objectsReturnPackage; } void handle_object_return() { - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); - objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); + objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. - get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); - } + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); + } } void handle_object_delete() { - if (LLSelectMgr::getInstance()) - { - LLSelectMgr::getInstance()->doDelete(); - } + if (LLSelectMgr::getInstance()) + { + LLSelectMgr::getInstance()->doDelete(); + } - // and close any pie/context menus when done - gMenuHolder->hideMenus(); + // and close any pie/context menus when done + gMenuHolder->hideMenus(); - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return; + // When deleting an object we may not actually be done + // Keep selection so we know what to delete when confirmation is needed about the delete + gMenuObject->hide(); + return; } void handle_force_delete(void*) { - LLSelectMgr::getInstance()->selectForceDelete(); + LLSelectMgr::getInstance()->selectForceDelete(); } class LLViewEnableJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); + return new_value; + } }; class LLViewEnableLastChatter : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // *TODO: add check that last chatter is in range - bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // *TODO: add check that last chatter is in range + bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); + return new_value; + } }; class LLEditEnableDeselect : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); + return new_value; + } }; class LLEditDeselect : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->deselect(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->deselect(); + } + return true; + } }; class LLEditEnableSelectAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); + return new_value; + } }; class LLEditSelectAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->selectAll(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->selectAll(); + } + return true; + } }; class LLEditEnableUndo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); + return new_value; + } }; class LLEditUndo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) - { - LLEditMenuHandler::gEditMenuHandler->undo(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) + { + LLEditMenuHandler::gEditMenuHandler->undo(); + } + return true; + } }; class LLEditEnableRedo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); + return new_value; + } }; class LLEditRedo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) - { - LLEditMenuHandler::gEditMenuHandler->redo(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) + { + LLEditMenuHandler::gEditMenuHandler->redo(); + } + return true; + } }; void print_object_info(void*) { - LLSelectMgr::getInstance()->selectionDump(); + LLSelectMgr::getInstance()->selectionDump(); } void print_agent_nvpairs(void*) { - LLViewerObject *objectp; + LLViewerObject *objectp; - LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; + LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; - objectp = gObjectList.findObject(gAgentID); - if (objectp) - { - objectp->printNameValuePairs(); - } - else - { - LL_INFOS() << "Can't find agent object" << LL_ENDL; - } + objectp = gObjectList.findObject(gAgentID); + if (objectp) + { + objectp->printNameValuePairs(); + } + else + { + LL_INFOS() << "Can't find agent object" << LL_ENDL; + } - LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; + LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; } void show_debug_menus() { - // this might get called at login screen where there is no menu so only toggle it if one exists - if ( gMenuBarView ) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - BOOL qamode = gSavedSettings.getBOOL("QAMode"); - - gMenuBarView->setItemVisible("Advanced", debug); -// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden - - gMenuBarView->setItemVisible("Debug", qamode); - gMenuBarView->setItemEnabled("Debug", qamode); - - gMenuBarView->setItemVisible("Develop", qamode); - gMenuBarView->setItemEnabled("Develop", qamode); - - // Server ('Admin') menu hidden when not in godmode. - const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); - gMenuBarView->setItemVisible("Admin", show_server_menu); - gMenuBarView->setItemEnabled("Admin", show_server_menu); - } - if (gLoginMenuBarView) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - gLoginMenuBarView->setItemVisible("Debug", debug); - gLoginMenuBarView->setItemEnabled("Debug", debug); - } + // this might get called at login screen where there is no menu so only toggle it if one exists + if ( gMenuBarView ) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + BOOL qamode = gSavedSettings.getBOOL("QAMode"); + + gMenuBarView->setItemVisible("Advanced", debug); +// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + + gMenuBarView->setItemVisible("Debug", qamode); + gMenuBarView->setItemEnabled("Debug", qamode); + + gMenuBarView->setItemVisible("Develop", qamode); + gMenuBarView->setItemEnabled("Develop", qamode); + + // Server ('Admin') menu hidden when not in godmode. + const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); + gMenuBarView->setItemVisible("Admin", show_server_menu); + gMenuBarView->setItemEnabled("Admin", show_server_menu); + } + if (gLoginMenuBarView) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + gLoginMenuBarView->setItemVisible("Debug", debug); + gLoginMenuBarView->setItemEnabled("Debug", debug); + } } void toggle_debug_menus(void*) { - BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); - gSavedSettings.setBOOL("UseDebugMenus", visible); - show_debug_menus(); + BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); + gSavedSettings.setBOOL("UseDebugMenus", visible); + show_debug_menus(); } @@ -6182,292 +6182,292 @@ void toggle_debug_menus(void*) // void handle_export_selected( void * ) // { -// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); -// if (selection->isEmpty()) -// { -// return; -// } -// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; - -// gExporterRequestID.generate(); -// gExportDirectory = ""; - -// LLMessageSystem* msg = gMessageSystem; -// msg->newMessageFast(_PREHASH_ObjectExportSelected); -// msg->nextBlockFast(_PREHASH_AgentData); -// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); -// msg->addS16Fast(_PREHASH_VolumeDetail, 4); - -// for (LLObjectSelection::root_iterator iter = selection->root_begin(); -// iter != selection->root_end(); iter++) -// { -// LLSelectNode* node = *iter; -// LLViewerObject* object = node->getObject(); -// msg->nextBlockFast(_PREHASH_ObjectData); -// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); -// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; -// } -// msg->sendReliable(gAgent.getRegion()->getHost()); - -// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); +// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); +// if (selection->isEmpty()) +// { +// return; +// } +// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; + +// gExporterRequestID.generate(); +// gExportDirectory = ""; + +// LLMessageSystem* msg = gMessageSystem; +// msg->newMessageFast(_PREHASH_ObjectExportSelected); +// msg->nextBlockFast(_PREHASH_AgentData); +// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); +// msg->addS16Fast(_PREHASH_VolumeDetail, 4); + +// for (LLObjectSelection::root_iterator iter = selection->root_begin(); +// iter != selection->root_end(); iter++) +// { +// LLSelectNode* node = *iter; +// LLViewerObject* object = node->getObject(); +// msg->nextBlockFast(_PREHASH_ObjectData); +// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); +// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; +// } +// msg->sendReliable(gAgent.getRegion()->getHost()); + +// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); // } // class LLCommunicateNearbyChat : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); + bool handleEvent(const LLSD& userdata) + { + LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); LLFloaterIMNearbyChat* floater_nearby = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); - if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() + if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() && im_box->getSelectedSession() == LLUUID() && im_box->getConversationListItemSize() > 1) - { - im_box->selectNextorPreviousConversation(false); - } - else - { - LLFloaterReg::toggleInstanceOrBringToFront("nearby_chat"); - } - return true; - } + { + im_box->selectNextorPreviousConversation(false); + } + else + { + LLFloaterReg::toggleInstanceOrBringToFront("nearby_chat"); + } + return true; + } }; class LLWorldSetHomeLocation : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // we just send the message and let the server check for failure cases - // server will echo back a "Home position set." alert if it succeeds - // and the home location screencapture happens when that alert is recieved - gAgent.setStartPosition(START_LOCATION_ID_HOME); - return true; - } + bool handleEvent(const LLSD& userdata) + { + // we just send the message and let the server check for failure cases + // server will echo back a "Home position set." alert if it succeeds + // and the home location screencapture happens when that alert is recieved + gAgent.setStartPosition(START_LOCATION_ID_HOME); + return true; + } }; class LLWorldLindenHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); - LLWeb::loadURL(url); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); + LLWeb::loadURL(url); + return true; + } }; class LLWorldTeleportHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.teleportHome(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.teleportHome(); + return true; + } }; class LLWorldAlwaysRun : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // as well as altering the default walk-vs-run state, - // we also change the *current* walk-vs-run state. - if (gAgent.getAlwaysRun()) - { - gAgent.clearAlwaysRun(); - gAgent.clearRunning(); - } - else - { - gAgent.setAlwaysRun(); - gAgent.setRunning(); - } + bool handleEvent(const LLSD& userdata) + { + // as well as altering the default walk-vs-run state, + // we also change the *current* walk-vs-run state. + if (gAgent.getAlwaysRun()) + { + gAgent.clearAlwaysRun(); + gAgent.clearRunning(); + } + else + { + gAgent.setAlwaysRun(); + gAgent.setRunning(); + } - // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); + // tell the simulator. + gAgent.sendWalkRun(gAgent.getAlwaysRun()); - // Update Movement Controls according to AlwaysRun mode - LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); + // Update Movement Controls according to AlwaysRun mode + LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); - return true; - } + return true; + } }; class LLWorldCheckAlwaysRun : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.getAlwaysRun(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgent.getAlwaysRun(); + return new_value; + } }; class LLWorldSetAway : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.getAFK()) - { - gAgent.clearAFK(); - } - else - { - gAgent.setAFK(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.getAFK()) + { + gAgent.clearAFK(); + } + else + { + gAgent.setAFK(); + } + return true; + } }; class LLWorldSetDoNotDisturb : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isDoNotDisturb()) - { - gAgent.setDoNotDisturb(false); - } - else - { - gAgent.setDoNotDisturb(true); - LLNotificationsUtil::add("DoNotDisturbModeSet"); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.isDoNotDisturb()) + { + gAgent.setDoNotDisturb(false); + } + else + { + gAgent.setDoNotDisturb(true); + LLNotificationsUtil::add("DoNotDisturbModeSet"); + } + return true; + } }; class LLWorldCreateLandmark : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("add_landmark"); + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("add_landmark"); - return true; - } + return true; + } }; class LLWorldPlaceProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); + bool handleEvent(const LLSD& userdata) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); - return true; - } + return true; + } }; void handle_look_at_selection(const LLSD& param) { - const F32 PADDING_FACTOR = 1.75f; - BOOL zoom = (param.asString() == "zoom"); - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - - LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); - obj_to_cam.normVec(); - - LLUUID object_id; - if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; - } - if (zoom) - { - // Make sure we are not increasing the distance between the camera and object - LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); - distance = llmin(distance, (F32) orig_distance.length()); - - gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), - LLSelectMgr::getInstance()->getSelectionCenterGlobal(), - object_id ); - - } - else - { - gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); - } - } + const F32 PADDING_FACTOR = 1.75f; + BOOL zoom = (param.asString() == "zoom"); + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + + LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); + F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); + + LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); + obj_to_cam.normVec(); + + LLUUID object_id; + if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) + { + object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; + } + if (zoom) + { + // Make sure we are not increasing the distance between the camera and object + LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); + distance = llmin(distance, (F32) orig_distance.length()); + + gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), + LLSelectMgr::getInstance()->getSelectionCenterGlobal(), + object_id ); + + } + else + { + gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); + } + } } void handle_zoom_to_object(LLUUID object_id) { - const F32 PADDING_FACTOR = 2.f; + const F32 PADDING_FACTOR = 2.f; - LLViewerObject* object = gObjectList.findObject(object_id); + LLViewerObject* object = gObjectList.findObject(object_id); - if (object) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + if (object) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - LLBBox bbox = object->getBoundingBoxAgent() ; - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); + LLBBox bbox = object->getBoundingBoxAgent() ; + F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); + F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); - obj_to_cam.normVec(); + LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); + obj_to_cam.normVec(); - LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); + LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); - gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), - object_center_global, - object_id ); - } + gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), + object_center_global, + object_id ); + } } class LLAvatarInviteToGroup : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::inviteToGroup(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::inviteToGroup(avatar->getID()); + } + return true; + } }; class LLAvatarAddFriend : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !LLAvatarActions::isFriend(avatar->getID())) - { - request_friendship(avatar->getID()); - } - return true; - } -}; - - + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar && !LLAvatarActions::isFriend(avatar->getID())) + { + request_friendship(avatar->getID()); + } + return true; + } +}; + + class LLAvatarToggleMyProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID()); - if (LLFloater::isMinimized(instance)) - { - instance->setMinimized(FALSE); - instance->setFocus(TRUE); - } - else if (!LLFloater::isShown(instance)) - { - LLAvatarActions::showProfile(gAgent.getID()); - } - else if (!instance->hasFocus() && !instance->getIsChrome()) - { - instance->setFocus(TRUE); - } - else - { - instance->closeFloater(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID()); + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + } + else if (!LLFloater::isShown(instance)) + { + LLAvatarActions::showProfile(gAgent.getID()); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } + return true; + } }; class LLAvatarTogglePicks : public view_listener_t @@ -6495,41 +6495,41 @@ class LLAvatarTogglePicks : public view_listener_t class LLAvatarToggleSearch : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* instance = LLFloaterReg::findInstance("search"); - if (LLFloater::isMinimized(instance)) - { - instance->setMinimized(FALSE); - instance->setFocus(TRUE); - } - else if (!LLFloater::isShown(instance)) - { - LLFloaterReg::showInstance("search"); - } - else if (!instance->hasFocus() && !instance->getIsChrome()) - { - instance->setFocus(TRUE); - } - else - { - instance->closeFloater(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* instance = LLFloaterReg::findInstance("search"); + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + } + else if (!LLFloater::isShown(instance)) + { + LLFloaterReg::showInstance("search"); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } + return true; + } }; class LLAvatarResetSkeleton: public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = NULL; LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (obj) { avatar = obj->getAvatar(); } - if(avatar) + if(avatar) { avatar->resetSkeleton(false); } @@ -6553,184 +6553,184 @@ class LLAvatarEnableResetSkeleton: public view_listener_t class LLAvatarResetSkeletonAndAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) - { - avatar->resetSkeleton(true); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + return true; + } }; class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) - { - avatar->resetSkeleton(true); - } - else - { - gAgentAvatarp->resetSkeleton(true); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + else + { + gAgentAvatarp->resetSkeleton(true); + } + return true; + } }; class LLAvatarAddContact : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - create_inventory_callingcard(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + create_inventory_callingcard(avatar->getID()); + } + return true; + } }; bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - gAgent.setDoNotDisturb(false); - } - - LLViewerObject* objectp = selection->getPrimaryObject(); - - // Show avatar's name if paying attachment - if (objectp && objectp->isAttachment()) - { - while (objectp && !objectp->isAvatar()) - { - objectp = (LLViewerObject*)objectp->getParent(); - } - } - - if (objectp) - { - if (objectp->isAvatar()) - { - const bool is_group = false; - LLFloaterPayUtil::payDirectly(&give_money, - objectp->getID(), - is_group); - } - else - { - LLFloaterPayUtil::payViaObject(&give_money, selection); - } - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + gAgent.setDoNotDisturb(false); + } + + LLViewerObject* objectp = selection->getPrimaryObject(); + + // Show avatar's name if paying attachment + if (objectp && objectp->isAttachment()) + { + while (objectp && !objectp->isAvatar()) + { + objectp = (LLViewerObject*)objectp->getParent(); + } + } + + if (objectp) + { + if (objectp->isAvatar()) + { + const bool is_group = false; + LLFloaterPayUtil::payDirectly(&give_money, + objectp->getID(), + is_group); + } + else + { + LLFloaterPayUtil::payViaObject(&give_money, selection); + } + } + return false; } void handle_give_money_dialog() { - LLNotification::Params params("DoNotDisturbModePay"); - params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + LLNotification::Params params("DoNotDisturbModePay"); + params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); - if (gAgent.isDoNotDisturb()) - { - // warn users of being in do not disturb mode during a transaction - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 1); - } + if (gAgent.isDoNotDisturb()) + { + // warn users of being in do not disturb mode during a transaction + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 1); + } } bool enable_pay_avatar() { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLVOAvatar* avatar = find_avatar_from_object(obj); - return (avatar != NULL); + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLVOAvatar* avatar = find_avatar_from_object(obj); + return (avatar != NULL); } bool enable_pay_object() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if( object ) - { - LLViewerObject *parent = (LLViewerObject *)object->getParent(); - if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) - { - return true; - } - } - return false; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if( object ) + { + LLViewerObject *parent = (LLViewerObject *)object->getParent(); + if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) + { + return true; + } + } + return false; } bool enable_object_stand_up() { - // 'Object Stand Up' menu item is enabled when agent is sitting on selection - return sitting_on_selection(); + // 'Object Stand Up' menu item is enabled when agent is sitting on selection + return sitting_on_selection(); } bool enable_object_sit(LLUICtrl* ctrl) { - // 'Object Sit' menu item is enabled when agent is not sitting on selection - bool sitting_on_sel = sitting_on_selection(); - if (!sitting_on_sel) - { - // init default labels - init_default_item_label(ctrl); - - // Update label - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mSitName.empty()) - { - ctrl->setValue(node->mSitName); - } - else - { - ctrl->setValue(get_default_item_label(ctrl->getName())); - } - } - return !sitting_on_sel && is_object_sittable(); + // 'Object Sit' menu item is enabled when agent is not sitting on selection + bool sitting_on_sel = sitting_on_selection(); + if (!sitting_on_sel) + { + // init default labels + init_default_item_label(ctrl); + + // Update label + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mSitName.empty()) + { + ctrl->setValue(node->mSitName); + } + else + { + ctrl->setValue(get_default_item_label(ctrl->getName())); + } + } + return !sitting_on_sel && is_object_sittable(); } void dump_select_mgr(void*) { - LLSelectMgr::getInstance()->dump(); + LLSelectMgr::getInstance()->dump(); } void dump_inventory(void*) { - gInventory.dumpInventory(); + gInventory.dumpInventory(); } void handle_dump_followcam(void*) { - LLFollowCamMgr::getInstance()->dump(); + LLFollowCamMgr::getInstance()->dump(); } void handle_viewer_enable_message_log(void*) { - gMessageSystem->startLogging(); + gMessageSystem->startLogging(); } void handle_viewer_disable_message_log(void*) { - gMessageSystem->stopLogging(); + gMessageSystem->stopLogging(); } void handle_customize_avatar() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); } void handle_edit_outfit() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); } void handle_now_wearing() @@ -6747,225 +6747,225 @@ void handle_now_wearing() void handle_edit_shape() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); } void handle_hover_height() { - LLFloaterReg::showInstance("edit_hover_height"); + LLFloaterReg::showInstance("edit_hover_height"); } void handle_edit_physics() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_physics")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_physics")); } void handle_report_abuse() { - // Prevent menu from appearing in screen shot. - gMenuHolder->hideMenus(); - LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); + // Prevent menu from appearing in screen shot. + gMenuHolder->hideMenus(); + LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); } void handle_buy_currency() { - LLBuyCurrencyHTML::openCurrencyFloater(); + LLBuyCurrencyHTML::openCurrencyFloater(); } class LLFloaterVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - bool new_value = false; - { - new_value = LLFloaterReg::instanceVisible(floater_name); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + bool new_value = false; + { + new_value = LLFloaterReg::instanceVisible(floater_name); + } + return new_value; + } }; class LLShowHelp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string help_topic = userdata.asString(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(help_topic); + return true; + } }; class LLToggleHelp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); - if (help_browser && help_browser->isInVisibleChain()) - { - help_browser->closeFloater(); - } - else - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); + if (help_browser && help_browser->isInVisibleChain()) + { + help_browser->closeFloater(); + } + else + { + std::string help_topic = userdata.asString(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(help_topic); + } + return true; + } }; class LLToggleSpeak : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVoiceClient::getInstance()->toggleUserPTTState(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVoiceClient::getInstance()->toggleUserPTTState(); + return true; + } }; class LLShowSidetrayPanel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - - LLPanel* panel = LLFloaterSidePanelContainer::getPanel(floater_name); - if (panel) - { - if (panel->isInVisibleChain()) - { - LLFloaterReg::getInstance(floater_name)->closeFloater(); - } - else - { - LLFloaterReg::getInstance(floater_name)->openFloater(); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + + LLPanel* panel = LLFloaterSidePanelContainer::getPanel(floater_name); + if (panel) + { + if (panel->isInVisibleChain()) + { + LLFloaterReg::getInstance(floater_name)->closeFloater(); + } + else + { + LLFloaterReg::getInstance(floater_name)->openFloater(); + } + } + return true; + } }; class LLSidetrayPanelVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - // Toggle the panel - if (LLFloaterReg::getInstance(floater_name)->isInVisibleChain()) - { - return true; - } - else - { - return false; - } - - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + // Toggle the panel + if (LLFloaterReg::getInstance(floater_name)->isInVisibleChain()) + { + return true; + } + else + { + return false; + } + + } }; bool callback_show_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"].asString()); + } + return false; } class LLPromptShowURL : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string url = param.substr(offset+1); - - if (LLWeb::useExternalBrowser(url)) - { - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); - } - else - { - LLWeb::loadURL(url); - } - } - else - { - LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string url = param.substr(offset+1); + + if (LLWeb::useExternalBrowser(url)) + { + LLSD payload; + payload["url"] = url; + LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); + } + else + { + LLWeb::loadURL(url); + } + } + else + { + LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; + } + return true; + } }; bool callback_show_file(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"]); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"]); + } + return false; } class LLPromptShowFile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string file = param.substr(offset+1); - - LLSD payload; - payload["url"] = file; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); - } - else - { - LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string file = param.substr(offset+1); + + LLSD payload; + payload["url"] = file; + LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); + } + else + { + LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; + } + return true; + } }; class LLShowAgentProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - LLAvatarActions::showProfile(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID agent_id; + if (userdata.asString() == "agent") + { + agent_id = gAgent.getID(); + } + else if (userdata.asString() == "hit object") + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + agent_id = objectp->getID(); + } + } + else + { + agent_id = userdata.asUUID(); + } + + LLVOAvatar* avatar = find_avatar_from_object(agent_id); + if (avatar) + { + LLAvatarActions::showProfile(avatar->getID()); + } + return true; + } }; class LLShowAgentProfilePicks : public view_listener_t @@ -6979,164 +6979,164 @@ class LLShowAgentProfilePicks : public view_listener_t class LLToggleAgentProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - if (!LLAvatarActions::profileVisible(avatar->getID())) - { - LLAvatarActions::showProfile(avatar->getID()); - } - else - { - LLAvatarActions::hideProfile(avatar->getID()); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID agent_id; + if (userdata.asString() == "agent") + { + agent_id = gAgent.getID(); + } + else if (userdata.asString() == "hit object") + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + agent_id = objectp->getID(); + } + } + else + { + agent_id = userdata.asUUID(); + } + + LLVOAvatar* avatar = find_avatar_from_object(agent_id); + if (avatar) + { + if (!LLAvatarActions::profileVisible(avatar->getID())) + { + LLAvatarActions::showProfile(avatar->getID()); + } + else + { + LLAvatarActions::hideProfile(avatar->getID()); + } + } + return true; + } }; class LLLandEdit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } + gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } - LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); + LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); - LLFloaterReg::showInstance("build"); + LLFloaterReg::showInstance("build"); - // Switch to land edit toolset - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); - return true; - } + // Switch to land edit toolset + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); + return true; + } }; class LLMuteParticle : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID; - - if (id.notNull()) - { - LLAvatarName av_name; - LLAvatarNameCache::get(id, &av_name); - - LLMute mute(id, av_name.getUserName(), LLMute::AGENT); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID; + + if (id.notNull()) + { + LLAvatarName av_name; + LLAvatarNameCache::get(id, &av_name); + + LLMute mute(id, av_name.getUserName(), LLMute::AGENT); + if (LLMuteList::getInstance()->isMuted(mute.mID)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + } + + return true; + } }; class LLWorldEnableBuyLand : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->selectionEmpty() - ? LLViewerParcelMgr::getInstance()->getAgentParcel() - : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), - false); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( + LLViewerParcelMgr::getInstance()->selectionEmpty() + ? LLViewerParcelMgr::getInstance()->getAgentParcel() + : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), + false); + return new_value; + } }; BOOL enable_buy_land(void*) { - return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); + return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( + LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); } void handle_buy_land() { - LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); - if (vpm->selectionEmpty()) - { - vpm->selectParcelAt(gAgent.getPositionGlobal()); - } - vpm->startBuyLand(); + LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); + if (vpm->selectionEmpty()) + { + vpm->selectParcelAt(gAgent.getPositionGlobal()); + } + vpm->startBuyLand(); } class LLObjectAttachToAvatar : public view_listener_t { public: - LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} - static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } + LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} + static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } private: - bool handleEvent(const LLSD& userdata) - { - setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); - if (selectedObject) - { - S32 index = userdata.asInteger(); - LLViewerJointAttachment* attachment_point = NULL; - if (index > 0) - attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); - confirmReplaceAttachment(0, attachment_point); - } - return true; - } - - static void onNearAttachObject(BOOL success, void *user_data); - void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); - class CallbackData : public LLSelectionCallbackData - { - public: - CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} - - LLViewerJointAttachment* mAttachmentPoint; - bool mReplace; - }; + bool handleEvent(const LLSD& userdata) + { + setObjectSelection(LLSelectMgr::getInstance()->getSelection()); + LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); + if (selectedObject) + { + S32 index = userdata.asInteger(); + LLViewerJointAttachment* attachment_point = NULL; + if (index > 0) + attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + confirmReplaceAttachment(0, attachment_point); + } + return true; + } + + static void onNearAttachObject(BOOL success, void *user_data); + void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); + class CallbackData : public LLSelectionCallbackData + { + public: + CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} + + LLViewerJointAttachment* mAttachmentPoint; + bool mReplace; + }; protected: - static LLObjectSelectionHandle sObjectSelection; - bool mReplace; + static LLObjectSelectionHandle sObjectSelection; + bool mReplace; }; LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; @@ -7144,238 +7144,238 @@ LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; // static void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) { - if (!user_data) return; - CallbackData* cb_data = static_cast<CallbackData*>(user_data); - - if (success) - { - const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; - - U8 attachment_id = 0; - if (attachment) - { - for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) - { - if (iter->second == attachment) - { - attachment_id = iter->first; - break; - } - } - } - else - { - // interpret 0 as "default location" - attachment_id = 0; - } - LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); - } - LLObjectAttachToAvatar::setObjectSelection(NULL); - - delete cb_data; + if (!user_data) return; + CallbackData* cb_data = static_cast<CallbackData*>(user_data); + + if (success) + { + const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; + + U8 attachment_id = 0; + if (attachment) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) + { + if (iter->second == attachment) + { + attachment_id = iter->first; + break; + } + } + } + else + { + // interpret 0 as "default location" + attachment_id = 0; + } + LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); + } + LLObjectAttachToAvatar::setObjectSelection(NULL); + + delete cb_data; } // static void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point) { - if (option == 0/*YES*/) - { - LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); - if (selectedObject) - { - const F32 MIN_STOP_DISTANCE = 1.f; // meters - const F32 ARM_LENGTH = 0.5f; // meters - const F32 SCALE_FUDGE = 1.5f; - - F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; - if (stop_distance < MIN_STOP_DISTANCE) - { - stop_distance = MIN_STOP_DISTANCE; - } - - LLVector3 walkToSpot = selectedObject->getPositionAgent(); - - // make sure we stop in front of the object - LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); - delta.normVec(); - delta = delta * 0.5f; - walkToSpot -= delta; - - // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. - CallbackData* user_data = new CallbackData(attachment_point, mReplace); - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); - gAgentCamera.clearFocusObject(); - } - } + if (option == 0/*YES*/) + { + LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); + if (selectedObject) + { + const F32 MIN_STOP_DISTANCE = 1.f; // meters + const F32 ARM_LENGTH = 0.5f; // meters + const F32 SCALE_FUDGE = 1.5f; + + F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; + if (stop_distance < MIN_STOP_DISTANCE) + { + stop_distance = MIN_STOP_DISTANCE; + } + + LLVector3 walkToSpot = selectedObject->getPositionAgent(); + + // make sure we stop in front of the object + LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); + delta.normVec(); + delta = delta * 0.5f; + walkToSpot -= delta; + + // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. + CallbackData* user_data = new CallbackData(attachment_point, mReplace); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); + gAgentCamera.clearFocusObject(); + } + } } void callback_attachment_drop(const LLSD& notification, const LLSD& response) { - // Ensure user confirmed the drop - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; - - // Called when the user clicked on an object attached to them - // and selected "Drop". - LLUUID object_id = notification["payload"]["object_id"].asUUID(); - LLViewerObject *object = gObjectList.findObject(object_id); - - if (!object) - { - LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; - return; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return; - } - - if (object->isAvatar()) - { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; - return; - } - - // reselect the object - LLSelectMgr::getInstance()->selectObjectAndFamily(object); - - LLSelectMgr::getInstance()->sendDropAttachment(); - - return; + // Ensure user confirmed the drop + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; + + // Called when the user clicked on an object attached to them + // and selected "Drop". + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLViewerObject *object = gObjectList.findObject(object_id); + + if (!object) + { + LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; + return; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return; + } + + if (object->isAvatar()) + { + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + return; + } + + // reselect the object + LLSelectMgr::getInstance()->selectObjectAndFamily(object); + + LLSelectMgr::getInstance()->sendDropAttachment(); + + return; } class LLAttachmentDrop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSD payload; - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + bool handleEvent(const LLSD& userdata) + { + LLSD payload; + LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (object) - { - payload["object_id"] = object->getID(); - } - else - { - LL_WARNS() << "Drop object not found" << LL_ENDL; - return true; - } + if (object) + { + payload["object_id"] = object->getID(); + } + else + { + LL_WARNS() << "Drop object not found" << LL_ENDL; + return true; + } - LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); - return true; - } + LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); + return true; + } }; // called from avatar pie menu class LLAttachmentDetachFromPoint : public view_listener_t { - bool handleEvent(const LLSD& user_data) - { - uuid_vec_t ids_to_remove; - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment->getNumObjects() > 0) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); - iter != attachment->mAttachedObjects.end(); - iter++) - { - LLViewerObject *attached_object = iter->get(); - ids_to_remove.push_back(attached_object->getAttachmentItemID()); - } - } - if (!ids_to_remove.empty()) - { - LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove); - } - return true; - } + bool handleEvent(const LLSD& user_data) + { + uuid_vec_t ids_to_remove; + const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); + if (attachment->getNumObjects() > 0) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); + iter != attachment->mAttachedObjects.end(); + iter++) + { + LLViewerObject *attached_object = iter->get(); + ids_to_remove.push_back(attached_object->getAttachmentItemID()); + } + } + if (!ids_to_remove.empty()) + { + LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove); + } + return true; + } }; static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { - std::string label; - LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); - if (menu) - { - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment) - { - label = data["label"].asString(); - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = attachment_iter->get(); - if (attached_object) - { - LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); - if (itemp) - { - label += std::string(" (") + itemp->getName() + std::string(")"); - break; - } - } - } - } - menu->setLabel(label); - } - return true; + std::string label; + LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); + if (menu) + { + const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); + if (attachment) + { + label = data["label"].asString(); + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object) + { + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); + if (itemp) + { + label += std::string(" (") + itemp->getName() + std::string(")"); + break; + } + } + } + } + menu->setLabel(label); + } + return true; } class LLAttachmentDetach : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // Called when the user clicked on an object attached to them - // and selected "Detach". - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return true; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return true; - } - - if (object->isAvatar()) - { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; - return true; - } - - LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); - - return true; - } + bool handleEvent(const LLSD& userdata) + { + // Called when the user clicked on an object attached to them + // and selected "Detach". + LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return true; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return true; + } + + if (object->isAvatar()) + { + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + return true; + } + + LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); + + return true; + } }; //Adding an observer for a Jira 2422 and needs to be a fetch observer @@ -7383,468 +7383,468 @@ class LLAttachmentDetach : public view_listener_t class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver { public: - LLWornItemFetchedObserver(const LLUUID& worn_item_id) : - LLInventoryFetchItemsObserver(worn_item_id) - {} - virtual ~LLWornItemFetchedObserver() {} + LLWornItemFetchedObserver(const LLUUID& worn_item_id) : + LLInventoryFetchItemsObserver(worn_item_id) + {} + virtual ~LLWornItemFetchedObserver() {} protected: - virtual void done() - { - gMenuAttachmentSelf->buildDrawLabels(); - gInventory.removeObserver(this); - delete this; - } + virtual void done() + { + gMenuAttachmentSelf->buildDrawLabels(); + gInventory.removeObserver(this); + delete this; + } }; // You can only drop items on parcels where you can build. class LLAttachmentEnableDrop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); - - //Add an inventory observer to only allow dropping the newly attached item - //once it exists in your inventory. Look at Jira 2422. - //-jwolk - - // A bug occurs when you wear/drop an item before it actively is added to your inventory - // if this is the case (you're on a slow sim, etc.) a copy of the object, - // well, a newly created object with the same properties, is placed - // in your inventory. Therefore, we disable the drop option until the - // item is in your inventory - - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLViewerJointAttachment* attachment = NULL; - LLInventoryItem* item = NULL; - - // Do not enable drop if all faces of object are not enabled - if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); - attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); - - if (attachment) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) - // so check to see if the item is in the inventory already - item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); - if (!item) - { - // Item does not exist, make an observer to enable the pie menu - // when the item finishes fetching worst case scenario - // if a fetch is already out there (being sent from a slow sim) - // we refetch and there are 2 fetches - LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); - worn_item_fetched->startFetch(); - gInventory.addObserver(worn_item_fetched); - } - } - } - } - - //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach() && can_build && item; - - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); + + //Add an inventory observer to only allow dropping the newly attached item + //once it exists in your inventory. Look at Jira 2422. + //-jwolk + + // A bug occurs when you wear/drop an item before it actively is added to your inventory + // if this is the case (you're on a slow sim, etc.) a copy of the object, + // well, a newly created object with the same properties, is placed + // in your inventory. Therefore, we disable the drop option until the + // item is in your inventory + + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLViewerJointAttachment* attachment = NULL; + LLInventoryItem* item = NULL; + + // Do not enable drop if all faces of object are not enabled + if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); + attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); + + if (attachment) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) + // so check to see if the item is in the inventory already + item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); + if (!item) + { + // Item does not exist, make an observer to enable the pie menu + // when the item finishes fetching worst case scenario + // if a fetch is already out there (being sent from a slow sim) + // we refetch and there are 2 fetches + LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); + worn_item_fetched->startFetch(); + gInventory.addObserver(worn_item_fetched); + } + } + } + } + + //now check to make sure that the item is actually in the inventory before we enable dropping it + bool new_value = enable_detach() && can_build && item; + + return new_value; + } }; BOOL enable_detach(const LLSD&) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - // Only enable detach if all faces of object are selected - if (!object || - !object->isAttachment() || - !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - return FALSE; - } + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - // Find the avatar who owns this attachment - LLViewerObject* avatar = object; - while (avatar) - { - // ...if it's you, good to detach - if (avatar->getID() == gAgent.getID()) - { - return TRUE; - } + // Only enable detach if all faces of object are selected + if (!object || + !object->isAttachment() || + !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + return FALSE; + } - avatar = (LLViewerObject*)avatar->getParent(); - } + // Find the avatar who owns this attachment + LLViewerObject* avatar = object; + while (avatar) + { + // ...if it's you, good to detach + if (avatar->getID() == gAgent.getID()) + { + return TRUE; + } + + avatar = (LLViewerObject*)avatar->getParent(); + } - return FALSE; + return FALSE; } class LLAttachmentEnableDetach : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_detach(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_detach(); + return new_value; + } }; // Used to tell if the selected object can be attached to your avatar. BOOL object_selected_and_point_valid() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::root_iterator iter = selection->root_begin(); - iter != selection->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerObject::const_child_list_t& child_list = object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - if (child->isAvatar()) - { - return FALSE; - } - } - } - - return (selection->getRootObjectCount() == 1) && - (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && - selection->getFirstRootObject()->permYouOwner() && - selection->getFirstRootObject()->flagObjectMove() && - !selection->getFirstRootObject()->flagObjectPermanent() && - !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && - (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::root_iterator iter = selection->root_begin(); + iter != selection->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + LLViewerObject::const_child_list_t& child_list = object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + if (child->isAvatar()) + { + return FALSE; + } + } + } + + return (selection->getRootObjectCount() == 1) && + (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && + selection->getFirstRootObject()->permYouOwner() && + selection->getFirstRootObject()->flagObjectMove() && + !selection->getFirstRootObject()->flagObjectPermanent() && + !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && + (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); } BOOL object_is_wearable() { - if (!isAgentAvatarValid()) - { - return FALSE; - } - if (!object_selected_and_point_valid()) - { - return FALSE; - } - if (sitting_on_selection()) - { - return FALSE; - } + if (!isAgentAvatarValid()) + { + return FALSE; + } + if (!object_selected_and_point_valid()) + { + return FALSE; + } + if (sitting_on_selection()) + { + return FALSE; + } if (!gAgentAvatarp->canAttachMoreObjects()) { return FALSE; } - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - if (node->mPermissions->getOwner() == gAgent.getID()) - { - return TRUE; - } - } - return FALSE; + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + if (node->mPermissions->getOwner() == gAgent.getID()) + { + return TRUE; + } + } + return FALSE; } class LLAttachmentPointFilled : public view_listener_t { - bool handleEvent(const LLSD& user_data) - { - bool enable = false; - LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); - if (found_it != gAgentAvatarp->mAttachmentPoints.end()) - { - enable = found_it->second->getNumObjects() > 0; - } - return enable; - } + bool handleEvent(const LLSD& user_data) + { + bool enable = false; + LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); + if (found_it != gAgentAvatarp->mAttachmentPoints.end()) + { + enable = found_it->second->getNumObjects() > 0; + } + return enable; + } }; class LLAvatarSendIM : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startIM(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::startIM(avatar->getID()); + } + return true; + } }; class LLAvatarCall : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startCall(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::startCall(avatar->getID()); + } + return true; + } }; namespace { - struct QueueObjects : public LLSelectedNodeFunctor - { - BOOL scripted; - BOOL modifiable; - LLFloaterScriptQueue* mQueue; - QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLSelectNode* node) - { - LLViewerObject* obj = node->getObject(); - if (!obj) - { - return true; - } - scripted = obj->flagScripted(); - modifiable = obj->permModify(); - - if( scripted && modifiable ) - { - mQueue->addObject(obj->getID(), node->mName); - return false; - } - else - { - return true; // fail: stop applying - } - } - }; + struct QueueObjects : public LLSelectedNodeFunctor + { + BOOL scripted; + BOOL modifiable; + LLFloaterScriptQueue* mQueue; + QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} + virtual bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + if (!obj) + { + return true; + } + scripted = obj->flagScripted(); + modifiable = obj->permModify(); + + if( scripted && modifiable ) + { + mQueue->addObject(obj->getID(), node->mName); + return false; + } + else + { + return true; // fail: stop applying + } + } + }; } bool queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { - QueueObjects func(q); - LLSelectMgr *mgr = LLSelectMgr::getInstance(); - LLObjectSelectionHandle selectHandle = mgr->getSelection(); - bool fail = selectHandle->applyToNodes(&func); - if(fail) - { - if ( !func.scripted ) - { - std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; - LLNotificationsUtil::add(noscriptmsg); - } - else if ( !func.modifiable ) - { - std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; - LLNotificationsUtil::add(nomodmsg); - } - else - { - LL_ERRS() << "Bad logic." << LL_ENDL; - } - q->closeFloater(); - } - else - { - if (!q->start()) - { - LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; - } - } - return !fail; + QueueObjects func(q); + LLSelectMgr *mgr = LLSelectMgr::getInstance(); + LLObjectSelectionHandle selectHandle = mgr->getSelection(); + bool fail = selectHandle->applyToNodes(&func); + if(fail) + { + if ( !func.scripted ) + { + std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; + LLNotificationsUtil::add(noscriptmsg); + } + else if ( !func.modifiable ) + { + std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; + LLNotificationsUtil::add(nomodmsg); + } + else + { + LL_ERRS() << "Bad logic." << LL_ENDL; + } + q->closeFloater(); + } + else + { + if (!q->start()) + { + LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; + } + } + return !fail; } class LLToolsSelectedScriptAction : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string action = userdata.asString(); - bool mono = false; - std::string msg, name; - std::string title; - if (action == "compile mono") - { - name = "compile_queue"; - mono = true; - msg = "Recompile"; - title = LLTrans::getString("CompileQueueTitle"); - } - if (action == "compile lsl") - { - name = "compile_queue"; - msg = "Recompile"; - title = LLTrans::getString("CompileQueueTitle"); - } - else if (action == "reset") - { - name = "reset_queue"; - msg = "Reset"; - title = LLTrans::getString("ResetQueueTitle"); - } - else if (action == "start") - { - name = "start_queue"; - msg = "SetRunning"; - title = LLTrans::getString("RunQueueTitle"); - } - else if (action == "stop") - { - name = "stop_queue"; - msg = "SetRunningNot"; - title = LLTrans::getString("NotRunQueueTitle"); - } - LLUUID id; id.generate(); - - LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id)); - if (queue) - { - queue->setMono(mono); - if (queue_actions(queue, msg)) - { - queue->setTitle(title); - } - } - else - { - LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string action = userdata.asString(); + bool mono = false; + std::string msg, name; + std::string title; + if (action == "compile mono") + { + name = "compile_queue"; + mono = true; + msg = "Recompile"; + title = LLTrans::getString("CompileQueueTitle"); + } + if (action == "compile lsl") + { + name = "compile_queue"; + msg = "Recompile"; + title = LLTrans::getString("CompileQueueTitle"); + } + else if (action == "reset") + { + name = "reset_queue"; + msg = "Reset"; + title = LLTrans::getString("ResetQueueTitle"); + } + else if (action == "start") + { + name = "start_queue"; + msg = "SetRunning"; + title = LLTrans::getString("RunQueueTitle"); + } + else if (action == "stop") + { + name = "stop_queue"; + msg = "SetRunningNot"; + title = LLTrans::getString("NotRunQueueTitle"); + } + LLUUID id; id.generate(); + + LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id)); + if (queue) + { + queue->setMono(mono); + if (queue_actions(queue, msg)) + { + queue->setTitle(title); + } + } + else + { + LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; + } + return true; + } }; void handle_selected_texture_info(void*) { - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Texture info for: "); - msg.append(node->mName); - - U8 te_count = node->getObject()->getNumTEs(); - // map from texture ID to list of faces using it - typedef std::map< LLUUID, std::vector<U8> > map_t; - map_t faces_per_texture; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - LLViewerTexture* img = node->getObject()->getTEImage(i); - LLUUID image_id = img->getID(); - faces_per_texture[image_id].push_back(i); - } - // Per-texture, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) - { - U8 te = it->second[0]; - LLViewerTexture* img = node->getObject()->getTEImage(te); - S32 height = img->getHeight(); - S32 width = img->getWidth(); - S32 components = img->getComponents(); - msg.append(llformat("\n%dx%d %s on face ", - width, - height, - (components == 4 ? "alpha" : "opaque"))); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - } - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } + for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + LLSelectNode* node = *iter; + + std::string msg; + msg.assign("Texture info for: "); + msg.append(node->mName); + + U8 te_count = node->getObject()->getNumTEs(); + // map from texture ID to list of faces using it + typedef std::map< LLUUID, std::vector<U8> > map_t; + map_t faces_per_texture; + for (U8 i = 0; i < te_count; i++) + { + if (!node->isTESelected(i)) continue; + + LLViewerTexture* img = node->getObject()->getTEImage(i); + LLUUID image_id = img->getID(); + faces_per_texture[image_id].push_back(i); + } + // Per-texture, dump which faces are using it. + map_t::iterator it; + for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) + { + U8 te = it->second[0]; + LLViewerTexture* img = node->getObject()->getTEImage(te); + S32 height = img->getHeight(); + S32 width = img->getWidth(); + S32 components = img->getComponents(); + msg.append(llformat("\n%dx%d %s on face ", + width, + height, + (components == 4 ? "alpha" : "opaque"))); + for (U8 i = 0; i < it->second.size(); ++i) + { + msg.append( llformat("%d ", (S32)(it->second[i]))); + } + } + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); + } } void handle_selected_material_info() { - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Material info for: \n"); - msg.append(node->mName); - - U8 te_count = node->getObject()->getNumTEs(); - // map from material ID to list of faces using it - typedef std::map<LLMaterialID, std::vector<U8> > map_t; - map_t faces_per_material; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID(); - faces_per_material[material_id].push_back(i); - } - // Per-material, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it) - { - const LLMaterialID& material_id = it->first; - msg += llformat("%s on face ", material_id.asString().c_str()); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - msg.append("\n"); - } - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } + for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + LLSelectNode* node = *iter; + + std::string msg; + msg.assign("Material info for: \n"); + msg.append(node->mName); + + U8 te_count = node->getObject()->getNumTEs(); + // map from material ID to list of faces using it + typedef std::map<LLMaterialID, std::vector<U8> > map_t; + map_t faces_per_material; + for (U8 i = 0; i < te_count; i++) + { + if (!node->isTESelected(i)) continue; + + const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID(); + faces_per_material[material_id].push_back(i); + } + // Per-material, dump which faces are using it. + map_t::iterator it; + for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it) + { + const LLMaterialID& material_id = it->first; + msg += llformat("%s on face ", material_id.asString().c_str()); + for (U8 i = 0; i < it->second.size(); ++i) + { + msg.append( llformat("%d ", (S32)(it->second[i]))); + } + msg.append("\n"); + } + + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); + } } void handle_test_male(void*) { - LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); - //gGestureList.requestResetFromServer( TRUE ); + LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); + //gGestureList.requestResetFromServer( TRUE ); } void handle_test_female(void*) { - LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); - //gGestureList.requestResetFromServer( FALSE ); + LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); + //gGestureList.requestResetFromServer( FALSE ); } void handle_dump_attachments(void*) { - if(!isAgentAvatarValid()) return; - - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - S32 key = curiter->first; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = attachment_iter->get(); - BOOL visible = (attached_object != NULL && - attached_object->mDrawable.notNull() && - !attached_object->mDrawable->isRenderType(0)); - LLVector3 pos; - if (visible) pos = attached_object->mDrawable->getPosition(); - LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() - << (attached_object ? " present " : " absent ") - << (visible ? "visible " : "invisible ") - << " at " << pos - << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) - << LL_ENDL; - } - } + if(!isAgentAvatarValid()) return; + + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + S32 key = curiter->first; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = attachment_iter->get(); + BOOL visible = (attached_object != NULL && + attached_object->mDrawable.notNull() && + !attached_object->mDrawable->isRenderType(0)); + LLVector3 pos; + if (visible) pos = attached_object->mDrawable->getPosition(); + LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() + << (attached_object ? " present " : " absent ") + << (visible ? "visible " : "invisible ") + << " at " << pos + << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) + << LL_ENDL; + } + } } @@ -7853,369 +7853,369 @@ class LLToggleControl : public view_listener_t { protected: - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); + return true; + } }; class LLCheckControl : public view_listener_t { - bool handleEvent( const LLSD& userdata) - { - std::string callback_data = userdata.asString(); - bool new_value = gSavedSettings.getBOOL(callback_data); - return new_value; - } + bool handleEvent( const LLSD& userdata) + { + std::string callback_data = userdata.asString(); + bool new_value = gSavedSettings.getBOOL(callback_data); + return new_value; + } }; // not so generic class LLAdvancedCheckRenderShadowOption: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // is off - { - return false; - } - else // is on - { - return true; - } - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + S32 current_shadow_level = gSavedSettings.getS32(control_name); + if (current_shadow_level == 0) // is off + { + return false; + } + else // is on + { + return true; + } + } }; class LLAdvancedClickRenderShadowOption: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // upgrade to level 2 - { - gSavedSettings.setS32(control_name, 2); - } - else // downgrade to level 0 - { - gSavedSettings.setS32(control_name, 0); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + S32 current_shadow_level = gSavedSettings.getS32(control_name); + if (current_shadow_level == 0) // upgrade to level 2 + { + gSavedSettings.setS32(control_name, 2); + } + else // downgrade to level 0 + { + gSavedSettings.setS32(control_name, 0); + } + return true; + } }; class LLAdvancedClickRenderProfile: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gShaderProfileFrame = TRUE; - return true; - } + bool handleEvent(const LLSD& userdata) + { + gShaderProfileFrame = TRUE; + return true; + } }; F32 gpu_benchmark(); class LLAdvancedClickRenderBenchmark: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gpu_benchmark(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gpu_benchmark(); + return true; + } }; // these are used in the gl menus to set control values that require shader recompilation class LLToggleShaderControl : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); LLPipeline::refreshCachedSettings(); LLViewerShaderMgr::instance()->setShaders(); - return !checked; - } + return !checked; + } }; void menu_toggle_attached_lights(void* user_data) { - LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); + LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); } void menu_toggle_attached_particles(void* user_data) { - LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } class LLAdvancedHandleAttachedLightParticles: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); - // toggle the control - gSavedSettings.setBOOL(control_name, - !gSavedSettings.getBOOL(control_name)); + // toggle the control + gSavedSettings.setBOOL(control_name, + !gSavedSettings.getBOOL(control_name)); - // update internal flags - if (control_name == "RenderAttachedLights") - { - menu_toggle_attached_lights(NULL); - } - else if (control_name == "RenderAttachedParticles") - { - menu_toggle_attached_particles(NULL); - } - return true; - } + // update internal flags + if (control_name == "RenderAttachedLights") + { + menu_toggle_attached_lights(NULL); + } + else if (control_name == "RenderAttachedParticles") + { + menu_toggle_attached_particles(NULL); + } + return true; + } }; class LLSomethingSelected : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); + return new_value; + } }; class LLSomethingSelectedNoHUD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); + return new_value; + } }; static bool is_editable_selected() { - return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); } class LLEditableSelected : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return is_editable_selected(); - } + bool handleEvent(const LLSD& userdata) + { + return is_editable_selected(); + } }; class LLEditableSelectedMono : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - LLViewerRegion* region = gAgent.getRegion(); - if(region && gMenuHolder) - { - bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); - new_value = is_editable_selected() && have_cap; - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = false; + LLViewerRegion* region = gAgent.getRegion(); + if(region && gMenuHolder) + { + bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); + new_value = is_editable_selected() && have_cap; + } + return new_value; + } }; bool enable_object_take_copy() { - bool all_valid = false; - if (LLSelectMgr::getInstance()) - { - if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 0) - { - all_valid = true; + bool all_valid = false; + if (LLSelectMgr::getInstance()) + { + if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 0) + { + all_valid = true; #ifndef HACKED_GODLIKE_VIEWER # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (LLGridManager::getInstance()->isInProductionGrid() + if (LLGridManager::getInstance()->isInProductionGrid() || !gAgent.isGodlike()) # endif - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return (!obj->permCopy() || obj->isAttachment()); - } - } func; - const bool firstonly = true; - bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - all_valid = !any_invalid; - } + { + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* obj) + { + return (!obj->permCopy() || obj->isAttachment()); + } + } func; + const bool firstonly = true; + bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); + all_valid = !any_invalid; + } #endif // HACKED_GODLIKE_VIEWER - } - } + } + } - return all_valid; + return all_valid; } class LLHasAsset : public LLInventoryCollectFunctor { public: - LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} - virtual ~LLHasAsset() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL hasAsset() const { return mHasAsset; } + LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} + virtual ~LLHasAsset() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + BOOL hasAsset() const { return mHasAsset; } protected: - LLUUID mAssetID; - BOOL mHasAsset; + LLUUID mAssetID; + BOOL mHasAsset; }; bool LLHasAsset::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item && item->getAssetUUID() == mAssetID) - { - mHasAsset = TRUE; - } - return FALSE; + if(item && item->getAssetUUID() == mAssetID) + { + mHasAsset = TRUE; + } + return FALSE; } BOOL enable_save_into_task_inventory(void*) { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - LLViewerObject* obj = node->getObject(); - if( obj && !obj->isAttachment() ) - { - return TRUE; - } - } - return FALSE; + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if(node && (node->mValid) && (!node->mFromTaskID.isNull())) + { + // *TODO: check to see if the fromtaskid object exists. + LLViewerObject* obj = node->getObject(); + if( obj && !obj->isAttachment() ) + { + return TRUE; + } + } + return FALSE; } class LLToolsEnableSaveToObjectInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_save_into_task_inventory(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_save_into_task_inventory(NULL); + return new_value; + } }; class LLToggleHowTo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); + return true; + } }; class LLViewEnableMouselook : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // You can't go directly from customize avatar to mouselook. - // TODO: write code with appropriate dialogs to handle this transition. - bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // You can't go directly from customize avatar to mouselook. + // TODO: write code with appropriate dialogs to handle this transition. + bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); + return new_value; + } }; class LLToolsEnableToolNotPie : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); + return new_value; + } }; class LLWorldEnableCreateLandmark : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return !LLLandmarkActions::landmarkAlreadyExists(); - } + bool handleEvent(const LLSD& userdata) + { + return !LLLandmarkActions::landmarkAlreadyExists(); + } }; class LLWorldEnableSetHomeLocation : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.isGodlike() || - (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgent.isGodlike() || + (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); + return new_value; + } }; class LLWorldEnableTeleportHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerRegion* regionp = gAgent.getRegion(); - bool agent_on_prelude = (regionp && regionp->isPrelude()); - bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; - return enable_teleport_home; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerRegion* regionp = gAgent.getRegion(); + bool agent_on_prelude = (regionp && regionp->isPrelude()); + bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; + return enable_teleport_home; + } }; BOOL enable_god_full(void*) { - return gAgent.getGodLevel() >= GOD_FULL; + return gAgent.getGodLevel() >= GOD_FULL; } BOOL enable_god_liaison(void*) { - return gAgent.getGodLevel() >= GOD_LIAISON; + return gAgent.getGodLevel() >= GOD_LIAISON; } bool is_god_customer_service() { - return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; + return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; } BOOL enable_god_basic(void*) { - return gAgent.getGodLevel() > GOD_NOT; + return gAgent.getGodLevel() > GOD_NOT; } void toggle_show_xui_names(void *) { - gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); + gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); } BOOL check_show_xui_names(void *) { - return gSavedSettings.getBOOL("DebugShowXUINames"); + return gSavedSettings.getBOOL("DebugShowXUINames"); } class LLToolsSelectOnlyMyObjects : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); - gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); + gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); - return true; - } + return true; + } }; class LLToolsSelectOnlyMovableObjects : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); - gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); + gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); - return true; - } + return true; + } }; class LLToolsSelectInvisibleObjects : public view_listener_t @@ -8244,178 +8244,178 @@ class LLToolsSelectReflectionProbes: public view_listener_t class LLToolsSelectBySurrounding : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; + bool handleEvent(const LLSD& userdata) + { + LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; - gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); - return true; - } + gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); + return true; + } }; class LLToolsShowHiddenSelection : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // TomY TODO Merge these - LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; + bool handleEvent(const LLSD& userdata) + { + // TomY TODO Merge these + LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; - gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); - return true; - } + gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); + return true; + } }; class LLToolsShowSelectionLightRadius : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // TomY TODO merge these - LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; + bool handleEvent(const LLSD& userdata) + { + // TomY TODO merge these + LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; - gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); - return true; - } + gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); + return true; + } }; class LLToolsEditLinkedParts : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); - gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); - if (select_individuals) - { - LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); - } - else - { - LLSelectMgr::getInstance()->promoteSelectionToRoot(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); + gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); + if (select_individuals) + { + LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); + } + else + { + LLSelectMgr::getInstance()->promoteSelectionToRoot(); + } + return true; + } }; void reload_vertex_shader(void *) { - //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP + //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP } void handle_dump_avatar_local_textures(void*) { - gAgentAvatarp->dumpLocalTextures(); + gAgentAvatarp->dumpLocalTextures(); } void handle_dump_timers() { - LLTrace::BlockTimer::dumpCurTimes(); + LLTrace::BlockTimer::dumpCurTimes(); } void handle_debug_avatar_textures(void*) { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); - } + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); + } } void handle_grab_baked_texture(void* data) { - EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); - if (!isAgentAvatarValid()) return; - - const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); - LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << LL_ENDL; - LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; - LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - if(folder_id.notNull()) - { - std::string name; - name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; - - LLUUID item_id; - item_id.generate(); - LLPermissions perm; - perm.init(gAgentID, - gAgentID, - LLUUID::null, - LLUUID::null); - U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; - perm.initMasks(PERM_ALL, - PERM_ALL, - PERM_NONE, - PERM_NONE, - next_owner_perm); - time_t creation_date_now = time_corrected(); - LLPointer<LLViewerInventoryItem> item - = new LLViewerInventoryItem(item_id, - folder_id, - perm, - asset_id, - asset_type, - inv_type, - name, - LLStringUtil::null, - LLSaleInfo::DEFAULT, - LLInventoryItemFlags::II_FLAGS_NONE, - creation_date_now); - - item->updateServer(TRUE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - // Show the preview panel for textures to let - // user know that the image is now in inventory. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if(active_panel) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - active_panel->openSelected(); - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); - } - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } + EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); + if (!isAgentAvatarValid()) return; + + const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); + LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << LL_ENDL; + LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; + LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); + if(folder_id.notNull()) + { + std::string name; + name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; + + LLUUID item_id; + item_id.generate(); + LLPermissions perm; + perm.init(gAgentID, + gAgentID, + LLUUID::null, + LLUUID::null); + U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; + perm.initMasks(PERM_ALL, + PERM_ALL, + PERM_NONE, + PERM_NONE, + next_owner_perm); + time_t creation_date_now = time_corrected(); + LLPointer<LLViewerInventoryItem> item + = new LLViewerInventoryItem(item_id, + folder_id, + perm, + asset_id, + asset_type, + inv_type, + name, + LLStringUtil::null, + LLSaleInfo::DEFAULT, + LLInventoryItemFlags::II_FLAGS_NONE, + creation_date_now); + + item->updateServer(TRUE); + gInventory.updateItem(item); + gInventory.notifyObservers(); + + // Show the preview panel for textures to let + // user know that the image is now in inventory. + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if(active_panel) + { + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); + + active_panel->setSelection(item_id, TAKE_FOCUS_NO); + active_panel->openSelected(); + //LLFloaterInventory::dumpSelectionInformation((void*)view); + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus_ctrl); + } + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } } BOOL enable_grab_baked_texture(void* data) { - EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); - if (isAgentAvatarValid()) - { - return gAgentAvatarp->canGrabBakedTexture(index); - } - return FALSE; + EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); + if (isAgentAvatarValid()) + { + return gAgentAvatarp->canGrabBakedTexture(index); + } + return FALSE; } // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) { - if (object) - { - if( object->isAttachment() ) - { - do - { - object = (LLViewerObject*) object->getParent(); - } - while( object && !object->isAvatar() ); - } - else if( !object->isAvatar() ) - { - object = NULL; - } - } + if (object) + { + if( object->isAttachment() ) + { + do + { + object = (LLViewerObject*) object->getParent(); + } + while( object && !object->isAvatar() ); + } + else if( !object->isAvatar() ) + { + object = NULL; + } + } - return (LLVOAvatar*) object; + return (LLVOAvatar*) object; } @@ -8423,13 +8423,13 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ) { - return find_avatar_from_object( gObjectList.findObject(object_id) ); + return find_avatar_from_object( gObjectList.findObject(object_id) ); } void handle_disconnect_viewer(void *) { - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); } void force_error_breakpoint(void *) @@ -8484,30 +8484,30 @@ void force_error_thread_crash(void *) class LLToolsUseSelectionForGrid : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::getInstance()->clearGridObjects(); - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* objectp) - { - LLSelectMgr::getInstance()->addGridObject(objectp); - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); - LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); - LLFloaterTools::setGridMode((S32)GRID_MODE_REF_OBJECT); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLSelectMgr::getInstance()->clearGridObjects(); + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* objectp) + { + LLSelectMgr::getInstance()->addGridObject(objectp); + return true; + } + } func; + LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); + LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); + LLFloaterTools::setGridMode((S32)GRID_MODE_REF_OBJECT); + return true; + } }; void handle_test_load_url(void*) { - LLWeb::loadURL(""); - LLWeb::loadURL("hacker://www.google.com/"); - LLWeb::loadURL("http"); - LLWeb::loadURL("http://www.google.com/"); + LLWeb::loadURL(""); + LLWeb::loadURL("hacker://www.google.com/"); + LLWeb::loadURL("http"); + LLWeb::loadURL("http://www.google.com/"); } // @@ -8521,86 +8521,86 @@ LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p BOOL LLViewerMenuHolderGL::hideMenus() { - BOOL handled = FALSE; - - if (LLMenuHolderGL::hideMenus()) - { - handled = TRUE; - } + BOOL handled = FALSE; + + if (LLMenuHolderGL::hideMenus()) + { + handled = TRUE; + } - // drop pie menu selection - mParcelSelection = NULL; - mObjectSelection = NULL; + // drop pie menu selection + mParcelSelection = NULL; + mObjectSelection = NULL; - if (gMenuBarView) - { - gMenuBarView->clearHoverItem(); - gMenuBarView->resetMenuTrigger(); - } + if (gMenuBarView) + { + gMenuBarView->clearHoverItem(); + gMenuBarView->resetMenuTrigger(); + } - return handled; + return handled; } -void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection) -{ - mParcelSelection = selection; +void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection) +{ + mParcelSelection = selection; } -void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection) -{ - mObjectSelection = selection; +void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection) +{ + mObjectSelection = selection; } const LLRect LLViewerMenuHolderGL::getMenuRect() const { - return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); + return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); } void handle_web_browser_test(const LLSD& param) { - std::string url = param.asString(); - if (url.empty()) - { - url = "about:blank"; - } - LLWeb::loadURLInternal(url); + std::string url = param.asString(); + if (url.empty()) + { + url = "about:blank"; + } + LLWeb::loadURLInternal(url); } bool callback_clear_cache_immediately(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - //clear cache - LLAppViewer::instance()->purgeCacheImmediate(); - } + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + //clear cache + LLAppViewer::instance()->purgeCacheImmediate(); + } - return false; + return false; } void handle_cache_clear_immediately() { - LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); + LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); } void handle_web_content_test(const LLSD& param) { - std::string url = param.asString(); - LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); + std::string url = param.asString(); + LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); } void handle_show_url(const LLSD& param) { - std::string url = param.asString(); - if (LLWeb::useExternalBrowser(url)) - { - LLWeb::loadURLExternal(url); - } - else - { - LLWeb::loadURLInternal(url); - } + std::string url = param.asString(); + if (LLWeb::useExternalBrowser(url)) + { + LLWeb::loadURLExternal(url); + } + else + { + LLWeb::loadURLInternal(url); + } } @@ -8612,378 +8612,378 @@ void handle_report_bug(const LLSD& param) void handle_buy_currency_test(void*) { - std::string url = - "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; + std::string url = + "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; - LLStringUtil::format_map_t replace; - replace["[AGENT_ID]"] = gAgent.getID().asString(); - replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); - replace["[LANGUAGE]"] = LLUI::getLanguage(); - LLStringUtil::format(url, replace); + LLStringUtil::format_map_t replace; + replace["[AGENT_ID]"] = gAgent.getID().asString(); + replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); + replace["[LANGUAGE]"] = LLUI::getLanguage(); + LLStringUtil::format(url, replace); - LL_INFOS() << "buy currency url " << url << LL_ENDL; + LL_INFOS() << "buy currency url " << url << LL_ENDL; - LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); + LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); } // SUNSHINE CLEANUP - is only the request update at the end needed now? void handle_rebake_textures(void*) { - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) return; - // Slam pending upload count to "unstick" things - bool slam_for_debug = true; - gAgentAvatarp->forceBakeAllTextures(slam_for_debug); - if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) - { - LLAppearanceMgr::instance().requestServerAppearanceUpdate(); - } + // Slam pending upload count to "unstick" things + bool slam_for_debug = true; + gAgentAvatarp->forceBakeAllTextures(slam_for_debug); + if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) + { + LLAppearanceMgr::instance().requestServerAppearanceUpdate(); + } } void toggle_visibility(void* user_data) { - LLView* viewp = (LLView*)user_data; - viewp->setVisible(!viewp->getVisible()); + LLView* viewp = (LLView*)user_data; + viewp->setVisible(!viewp->getVisible()); } BOOL get_visibility(void* user_data) { - LLView* viewp = (LLView*)user_data; - return viewp->getVisible(); + LLView* viewp = (LLView*)user_data; + return viewp->getVisible(); } class LLViewShowHoverTips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); + return true; + } }; class LLViewCheckShowHoverTips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); + return new_value; + } }; class LLViewHighlightTransparent : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; + bool handleEvent(const LLSD& userdata) + { + LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; // invisible objects skip building their render batches unless sShowDebugAlpha is true, so rebuild batches whenever toggling this flag - gPipeline.rebuildDrawInfo(); - return true; - } + gPipeline.rebuildDrawInfo(); + return true; + } }; class LLViewCheckHighlightTransparent : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; + return new_value; + } }; class LLViewBeaconWidth : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string width = userdata.asString(); - if(width == "1") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 1); - } - else if(width == "4") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 4); - } - else if(width == "16") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 16); - } - else if(width == "32") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 32); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string width = userdata.asString(); + if(width == "1") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 1); + } + else if(width == "4") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 4); + } + else if(width == "16") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 16); + } + else if(width == "32") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 32); + } + + return true; + } }; class LLViewToggleBeacon : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - if (beacon == "scriptsbeacon") - { - LLPipeline::toggleRenderScriptedBeacons(); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) - { - LLPipeline::toggleRenderScriptedTouchBeacons(); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); - } - } - else if (beacon == "physicalbeacon") - { - LLPipeline::toggleRenderPhysicalBeacons(); - gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons() ); - } - else if (beacon == "moapbeacon") - { - LLPipeline::toggleRenderMOAPBeacons(); - gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons() ); - } - else if (beacon == "soundsbeacon") - { - LLPipeline::toggleRenderSoundBeacons(); - gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons() ); - } - else if (beacon == "particlesbeacon") - { - LLPipeline::toggleRenderParticleBeacons(); - gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons() ); - } - else if (beacon == "scripttouchbeacon") - { - LLPipeline::toggleRenderScriptedTouchBeacons(); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) - { - LLPipeline::toggleRenderScriptedBeacons(); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); - } - } - else if (beacon == "sunbeacon") - { - gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); - } - else if (beacon == "moonbeacon") - { - gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); - } - else if (beacon == "renderbeacons") - { - LLPipeline::toggleRenderBeacons(); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) - { - LLPipeline::toggleRenderHighlights(); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); - } - } - else if (beacon == "renderhighlights") - { - LLPipeline::toggleRenderHighlights(); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) - { - LLPipeline::toggleRenderBeacons(); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); - } - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + if (beacon == "scriptsbeacon") + { + LLPipeline::toggleRenderScriptedBeacons(); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) + { + LLPipeline::toggleRenderScriptedTouchBeacons(); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); + } + } + else if (beacon == "physicalbeacon") + { + LLPipeline::toggleRenderPhysicalBeacons(); + gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons() ); + } + else if (beacon == "moapbeacon") + { + LLPipeline::toggleRenderMOAPBeacons(); + gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons() ); + } + else if (beacon == "soundsbeacon") + { + LLPipeline::toggleRenderSoundBeacons(); + gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons() ); + } + else if (beacon == "particlesbeacon") + { + LLPipeline::toggleRenderParticleBeacons(); + gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons() ); + } + else if (beacon == "scripttouchbeacon") + { + LLPipeline::toggleRenderScriptedTouchBeacons(); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) + { + LLPipeline::toggleRenderScriptedBeacons(); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); + } + } + else if (beacon == "sunbeacon") + { + gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); + } + else if (beacon == "moonbeacon") + { + gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); + } + else if (beacon == "renderbeacons") + { + LLPipeline::toggleRenderBeacons(); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) + { + LLPipeline::toggleRenderHighlights(); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); + } + } + else if (beacon == "renderhighlights") + { + LLPipeline::toggleRenderHighlights(); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) + { + LLPipeline::toggleRenderBeacons(); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); + } + } + + return true; + } }; class LLViewCheckBeaconEnabled : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - bool new_value = false; - if (beacon == "scriptsbeacon") - { - new_value = gSavedSettings.getBOOL( "scriptsbeacon"); - LLPipeline::setRenderScriptedBeacons(new_value); - } - else if (beacon == "moapbeacon") - { - new_value = gSavedSettings.getBOOL( "moapbeacon"); - LLPipeline::setRenderMOAPBeacons(new_value); - } - else if (beacon == "physicalbeacon") - { - new_value = gSavedSettings.getBOOL( "physicalbeacon"); - LLPipeline::setRenderPhysicalBeacons(new_value); - } - else if (beacon == "soundsbeacon") - { - new_value = gSavedSettings.getBOOL( "soundsbeacon"); - LLPipeline::setRenderSoundBeacons(new_value); - } - else if (beacon == "particlesbeacon") - { - new_value = gSavedSettings.getBOOL( "particlesbeacon"); - LLPipeline::setRenderParticleBeacons(new_value); - } - else if (beacon == "scripttouchbeacon") - { - new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); - LLPipeline::setRenderScriptedTouchBeacons(new_value); - } - else if (beacon == "renderbeacons") - { - new_value = gSavedSettings.getBOOL( "renderbeacons"); - LLPipeline::setRenderBeacons(new_value); - } - else if (beacon == "renderhighlights") - { - new_value = gSavedSettings.getBOOL( "renderhighlights"); - LLPipeline::setRenderHighlights(new_value); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + bool new_value = false; + if (beacon == "scriptsbeacon") + { + new_value = gSavedSettings.getBOOL( "scriptsbeacon"); + LLPipeline::setRenderScriptedBeacons(new_value); + } + else if (beacon == "moapbeacon") + { + new_value = gSavedSettings.getBOOL( "moapbeacon"); + LLPipeline::setRenderMOAPBeacons(new_value); + } + else if (beacon == "physicalbeacon") + { + new_value = gSavedSettings.getBOOL( "physicalbeacon"); + LLPipeline::setRenderPhysicalBeacons(new_value); + } + else if (beacon == "soundsbeacon") + { + new_value = gSavedSettings.getBOOL( "soundsbeacon"); + LLPipeline::setRenderSoundBeacons(new_value); + } + else if (beacon == "particlesbeacon") + { + new_value = gSavedSettings.getBOOL( "particlesbeacon"); + LLPipeline::setRenderParticleBeacons(new_value); + } + else if (beacon == "scripttouchbeacon") + { + new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); + LLPipeline::setRenderScriptedTouchBeacons(new_value); + } + else if (beacon == "renderbeacons") + { + new_value = gSavedSettings.getBOOL( "renderbeacons"); + LLPipeline::setRenderBeacons(new_value); + } + else if (beacon == "renderhighlights") + { + new_value = gSavedSettings.getBOOL( "renderhighlights"); + LLPipeline::setRenderHighlights(new_value); + } + return new_value; + } }; class LLViewToggleRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - if (type == "hideparticles") - { - LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string type = userdata.asString(); + if (type == "hideparticles") + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); + } + return true; + } }; class LLViewCheckRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - bool new_value = false; - if (type == "hideparticles") - { - new_value = LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string type = userdata.asString(); + bool new_value = false; + if (type == "hideparticles") + { + new_value = LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES); + } + return new_value; + } }; class LLViewStatusAway : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.isInitialized() && gAgent.getAFK()); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.isInitialized() && gAgent.getAFK()); + } }; class LLViewStatusDoNotDisturb : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.isInitialized() && gAgent.isDoNotDisturb()); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.isInitialized() && gAgent.isDoNotDisturb()); + } }; class LLViewShowHUDAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; + return true; + } }; class LLViewCheckHUDAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPipeline::sShowHUDAttachments; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPipeline::sShowHUDAttachments; + return new_value; + } }; class LLEditEnableTakeOff : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - return LLAgentWearables::selfHasWearable(type); - return false; - } + bool handleEvent(const LLSD& userdata) + { + std::string clothing = userdata.asString(); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); + if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) + return LLAgentWearables::selfHasWearable(type); + return false; + } }; class LLEditTakeOff : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - if (clothing == "all") - LLAppearanceMgr::instance().removeAllClothesFromAvatar(); - else - { - LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE - && type < LLWearableType::WT_COUNT - && (gAgentWearables.getWearableCount(type) > 0)) - { - // MULTI-WEARABLES: assuming user wanted to remove top shirt. - U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; - LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); - LLAppearanceMgr::instance().removeItemFromAvatar(item_id); - } - - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string clothing = userdata.asString(); + if (clothing == "all") + LLAppearanceMgr::instance().removeAllClothesFromAvatar(); + else + { + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); + if (type >= LLWearableType::WT_SHAPE + && type < LLWearableType::WT_COUNT + && (gAgentWearables.getWearableCount(type) > 0)) + { + // MULTI-WEARABLES: assuming user wanted to remove top shirt. + U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; + LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); + LLAppearanceMgr::instance().removeItemFromAvatar(item_id); + } + + } + return true; + } }; class LLToolsSelectTool : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string tool_name = userdata.asString(); - if (tool_name == "focus") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); - } - else if (tool_name == "move") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); - } - else if (tool_name == "edit") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); - } - else if (tool_name == "create") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); - } - else if (tool_name == "land") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); - } - - // Note: if floater is not visible LLViewerWindow::updateLayout() will - // attempt to open it, but it won't bring it to front or de-minimize. - if (gFloaterTools && (gFloaterTools->isMinimized() || !gFloaterTools->isShown() || !gFloaterTools->isFrontmost())) - { - gFloaterTools->setMinimized(FALSE); - gFloaterTools->openFloater(); - gFloaterTools->setVisibleAndFrontmost(TRUE); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string tool_name = userdata.asString(); + if (tool_name == "focus") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); + } + else if (tool_name == "move") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); + } + else if (tool_name == "edit") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); + } + else if (tool_name == "create") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); + } + else if (tool_name == "land") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); + } + + // Note: if floater is not visible LLViewerWindow::updateLayout() will + // attempt to open it, but it won't bring it to front or de-minimize. + if (gFloaterTools && (gFloaterTools->isMinimized() || !gFloaterTools->isShown() || !gFloaterTools->isFrontmost())) + { + gFloaterTools->setMinimized(FALSE); + gFloaterTools->openFloater(); + gFloaterTools->setVisibleAndFrontmost(TRUE); + } + return true; + } }; /// WINDLIGHT callbacks @@ -9002,7 +9002,7 @@ void defocusEnvFloaters() } } -bool handle_env_setting_event(std::string event_name) +bool handle_env_setting_event(std::string event_name) { if (event_name == "sunrise") { @@ -9066,126 +9066,126 @@ bool handle_env_setting_event(std::string event_name) } class LLWorldEnvSettings : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { +{ + bool handleEvent(const LLSD& userdata) + { handle_env_setting_event(userdata.asString()); - return true; - } + return true; + } }; class LLWorldEnableEnvSettings : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool result = false; - std::string event_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + bool result = false; + std::string event_name = userdata.asString(); if (event_name == "pause_clouds") - { + { return LLEnvironment::instance().isCloudScrollPaused(); - } + } LLSettingsSky::ptr_t sky = LLEnvironment::instance().getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL); - if (!sky) - { - return (event_name == "region"); - } + if (!sky) + { + return (event_name == "region"); + } std::string skyname = (sky) ? sky->getName() : ""; LLUUID skyid = (sky) ? sky->getAssetId() : LLUUID::null; - if (event_name == "sunrise") - { + if (event_name == "sunrise") + { result = (skyid == LLEnvironment::KNOWN_SKY_SUNRISE); - } - else if (event_name == "noon") - { + } + else if (event_name == "noon") + { result = (skyid == LLEnvironment::KNOWN_SKY_MIDDAY); - } + } else if (event_name == "legacy noon") { result = (skyid == LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY); } - else if (event_name == "sunset") - { + else if (event_name == "sunset") + { result = (skyid == LLEnvironment::KNOWN_SKY_SUNSET); - } - else if (event_name == "midnight") - { + } + else if (event_name == "midnight") + { result = (skyid == LLEnvironment::KNOWN_SKY_MIDNIGHT); - } - else if (event_name == "region") - { - return false; - } - else - { - LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; - } - return result; - } + } + else if (event_name == "region") + { + return false; + } + else + { + LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; + } + return result; + } }; class LLWorldEnvPreset : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string item = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string item = userdata.asString(); - if (item == "new_water") - { + if (item == "new_water") + { LLFloaterReg::showInstance("env_fixed_environmentent_water", "new"); - } - else if (item == "edit_water") - { + } + else if (item == "edit_water") + { LLFloaterReg::showInstance("env_fixed_environmentent_water", "edit"); - } - else if (item == "new_sky") - { + } + else if (item == "new_sky") + { LLFloaterReg::showInstance("env_fixed_environmentent_sky", "new"); - } - else if (item == "edit_sky") - { + } + else if (item == "edit_sky") + { LLFloaterReg::showInstance("env_fixed_environmentent_sky", "edit"); - } - else if (item == "new_day_cycle") - { + } + else if (item == "new_day_cycle") + { LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); - } - else if (item == "edit_day_cycle") - { - LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); - } - else - { - LL_WARNS() << "Unknown item selected" << LL_ENDL; - } + } + else if (item == "edit_day_cycle") + { + LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); + } + else + { + LL_WARNS() << "Unknown item selected" << LL_ENDL; + } - return true; - } + return true; + } }; class LLWorldEnableEnvPreset : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { - return false; - } + return false; + } }; /// Post-Process callbacks class LLWorldPostProcess : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_post_process"); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("env_post_process"); + return true; + } }; class LLWorldCheckBanLines : public view_listener_t @@ -9209,684 +9209,684 @@ class LLWorldShowBanLines : public view_listener_t void handle_flush_name_caches() { - if (gCacheName) gCacheName->clear(); + if (gCacheName) gCacheName->clear(); } class LLUploadCostCalculator : public view_listener_t { - std::string mCostStr; - - bool handleEvent(const LLSD& userdata) - { - std::vector<std::string> fields; - std::string str = userdata.asString(); - boost::split(fields, str, boost::is_any_of(",")); - if (fields.size()<1) - { - return false; - } - std::string menu_name = fields[0]; - std::string asset_type_str = "texture"; - if (fields.size()>1) - { - asset_type_str = fields[1]; - } - LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; - calculateCost(asset_type_str); - gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); - - return true; - } - - void calculateCost(const std::string& asset_type_str); + std::string mCostStr; + + bool handleEvent(const LLSD& userdata) + { + std::vector<std::string> fields; + std::string str = userdata.asString(); + boost::split(fields, str, boost::is_any_of(",")); + if (fields.size()<1) + { + return false; + } + std::string menu_name = fields[0]; + std::string asset_type_str = "texture"; + if (fields.size()>1) + { + asset_type_str = fields[1]; + } + LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; + calculateCost(asset_type_str); + gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); + + return true; + } + + void calculateCost(const std::string& asset_type_str); public: - LLUploadCostCalculator() - { - } + LLUploadCostCalculator() + { + } }; class LLUpdateMembershipLabel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); - gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); + bool handleEvent(const LLSD& userdata) + { + const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); + gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); - return true; - } + return true; + } }; void handle_voice_morphing_subscribe() { - LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); + LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); } void handle_premium_voice_morphing_subscribe() { - LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); + LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); } class LLToggleUIHints : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); - // toggle - ui_hints_enabled = !ui_hints_enabled; - gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); - return true; - } + bool handleEvent(const LLSD& userdata) + { + bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); + // toggle + ui_hints_enabled = !ui_hints_enabled; + gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); + return true; + } }; void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str) { - S32 upload_cost = -1; - - if (asset_type_str == "texture") - { - upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - } - else if (asset_type_str == "animation") - { - upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); - } - else if (asset_type_str == "sound") - { - upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); - } - if (upload_cost < 0) - { - LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; - } - mCostStr = std::to_string(upload_cost); + S32 upload_cost = -1; + + if (asset_type_str == "texture") + { + upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); + } + else if (asset_type_str == "animation") + { + upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); + } + else if (asset_type_str == "sound") + { + upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); + } + if (upload_cost < 0) + { + LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; + } + mCostStr = std::to_string(upload_cost); } void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) { - static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } - show_navbar_context_menu->buildDrawLabels(); - show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); + static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } + show_navbar_context_menu->buildDrawLabels(); + show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); } void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y) { - static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark"); - if (!LLLandmarkActions::landmarkAlreadyExists()) - { - landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); - } - else - { - landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); - } + LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark"); + if (!LLLandmarkActions::landmarkAlreadyExists()) + { + landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); + } + else + { + landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); + } - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } - show_topbarinfo_context_menu->buildDrawLabels(); - show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); + show_topbarinfo_context_menu->buildDrawLabels(); + show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); } void initialize_edit_menu() { - view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); - view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); - view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); - view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); - view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); - view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); - view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); - view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); - view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); - view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); - view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); - view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); - view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); - view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); - view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); - view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); - view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); + view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); + view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); + view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); + view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); + view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); + view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); + view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); + view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); + view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); + view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); + view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); + view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); + view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); + view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); + view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); + view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); + view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); } void initialize_spellcheck_menu() { - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); - enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); - commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); - enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); - commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); - enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); + commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); + commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); + commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); } void initialize_menus() { - // A parameterized event handler used as ctrl-8/9/0 zoom controls below. - class LLZoomer : public view_listener_t - { - public: - // The "mult" parameter says whether "val" is a multiplier or used to set the value. - LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(const LLSD& userdata) - { - F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; - LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); - gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. - return true; - } - private: - F32 mVal; - bool mMult; - }; - - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - - // Generic enable and visible - // Don't prepend MenuName.Foo because these can be used in any menu. - enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service)); - - enable.add("displayViewerEventRecorderMenuItems",boost::bind(&LLViewerEventRecorder::displayViewerEventRecorderMenuItems,&LLViewerEventRecorder::instance())); - - view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts"); - - view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); - - enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); - - // Agent - commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); - enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); - commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); - commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); - commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); - enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); - enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); - - // File menu - init_menu_file(); - - view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); - view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); - view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); - view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); - view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); - commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); + // A parameterized event handler used as ctrl-8/9/0 zoom controls below. + class LLZoomer : public view_listener_t + { + public: + // The "mult" parameter says whether "val" is a multiplier or used to set the value. + LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} + bool handleEvent(const LLSD& userdata) + { + F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; + LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); + gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. + return true; + } + private: + F32 mVal; + bool mMult; + }; + + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // Generic enable and visible + // Don't prepend MenuName.Foo because these can be used in any menu. + enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service)); + + enable.add("displayViewerEventRecorderMenuItems",boost::bind(&LLViewerEventRecorder::displayViewerEventRecorderMenuItems,&LLViewerEventRecorder::instance())); + + view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts"); + + view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); + + enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); + + // Agent + commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); + enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); + commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); + commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); + commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); + enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); + enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); + + // File menu + init_menu_file(); + + view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); + view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); + view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); + view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); + view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); + commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); commit.add("NowWearing", boost::bind(&handle_now_wearing)); - commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); - commit.add("EditShape", boost::bind(&handle_edit_shape)); - commit.add("HoverHeight", boost::bind(&handle_hover_height)); - commit.add("EditPhysics", boost::bind(&handle_edit_physics)); - - // View menu - view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); - view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); - view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); - view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); - view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); - view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); - view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); - view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); - view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); - view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); - view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); - view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); - view_listener_t::addMenu(new LLViewToggleUI(), "View.ToggleUI"); - - view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); - view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); - view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); - - view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); - view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); - view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); - view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); - view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway"); - view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); - view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); - - //Communicate Nearby chat - view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); - - // Communicate > Voice morphing > Subscribe... - commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); - // Communicate > Voice morphing > Premium perk... - commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); - LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); - enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" - , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); - commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" - , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); - - // World menu - view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); - view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); - view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); - view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); - view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); - view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); - view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); - view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); - - view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); - view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); - view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); - view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); - - view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); - - view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); - view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); - view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); - view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); - view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); + commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); + commit.add("EditShape", boost::bind(&handle_edit_shape)); + commit.add("HoverHeight", boost::bind(&handle_hover_height)); + commit.add("EditPhysics", boost::bind(&handle_edit_physics)); + + // View menu + view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); + view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); + view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); + view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); + view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); + view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); + view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); + view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); + view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); + view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); + view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); + view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); + view_listener_t::addMenu(new LLViewToggleUI(), "View.ToggleUI"); + + view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); + view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); + view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); + + view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); + view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); + view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); + view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); + view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway"); + view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); + view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); + + //Communicate Nearby chat + view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); + + // Communicate > Voice morphing > Subscribe... + commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); + // Communicate > Voice morphing > Premium perk... + commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); + LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); + enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" + , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); + commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" + , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); + + // World menu + view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); + view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); + view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); + view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); + view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); + view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); + view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); + view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); + + view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); + view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); + view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); + view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); + + view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); + + view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); + view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); + view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); + view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); + view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines"); view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines"); - // Tools menu - view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); - view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); - view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); + // Tools menu + view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); + view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); + view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); view_listener_t::addMenu(new LLToolsSelectInvisibleObjects(), "Tools.SelectInvisibleObjects"); view_listener_t::addMenu(new LLToolsSelectReflectionProbes(), "Tools.SelectReflectionProbes"); - view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); - view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); - view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); - view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); - view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); - view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); - view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); - commit.add("Tools.Link", boost::bind(&handle_link_objects)); - commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); - view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); - view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); - view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); - view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); - - view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); - view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); - enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); - enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); - enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); - enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); - enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); - view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); - - view_listener_t::addMenu(new LLToolsEnablePathfinding(), "Tools.EnablePathfinding"); - view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView"); - view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion"); - view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion"); - - // Help menu - // most items use the ShowFloater method - view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); - - // Advanced menu - view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); - view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); - view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); - - // Advanced > HUD Info - view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); - view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); - - // Advanced Other Settings - view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); - - // Advanced > Render > Types - view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); - view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); - - //// Advanced > Render > Features - view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); - view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); - - view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity"); - view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity"); - - // Advanced > Render > Info Displays - view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); - commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); - view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); - view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); - // Develop > Render - view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); - view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); - view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); - view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); - - #ifdef TOGGLE_HACKED_GODLIKE_VIEWER - view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); - #endif - - // Advanced > World - view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); - view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); + view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); + view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); + view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); + view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); + view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); + view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); + view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); + commit.add("Tools.Link", boost::bind(&handle_link_objects)); + commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); + view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); + view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); + commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); + commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); + commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); + view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); + view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); + + view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); + view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); + enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); + enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); + enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); + enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); + enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); + view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); + + view_listener_t::addMenu(new LLToolsEnablePathfinding(), "Tools.EnablePathfinding"); + view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView"); + view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion"); + view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion"); + + // Help menu + // most items use the ShowFloater method + view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); + + // Advanced menu + view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); + view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); + view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); + + // Advanced > HUD Info + view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); + view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); + + // Advanced Other Settings + view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); + + // Advanced > Render > Types + view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); + view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); + + //// Advanced > Render > Features + view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); + view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); + + view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity"); + view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity"); + + // Advanced > Render > Info Displays + view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); + commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); + view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); + view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); + // Develop > Render + view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); + view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); + view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); + view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); + view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); + view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); + + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER + view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); + #endif + + // Advanced > World + view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); + view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); view_listener_t::addMenu(new LLAdvancedToggleStatsRecorder(), "Advanced.ToggleStatsRecorder"); view_listener_t::addMenu(new LLAdvancedCheckStatsRecorder(), "Advanced.CheckStatsRecorder"); view_listener_t::addMenu(new LLAdvancedToggleInterestList360Mode(), "Advanced.ToggleInterestList360Mode"); view_listener_t::addMenu(new LLAdvancedCheckInterestList360Mode(), "Advanced.CheckInterestList360Mode"); view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); - // Advanced > UI - commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser - commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater - commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); - commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); - view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); - view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); - view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); - commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); - view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); - view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); - view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); - view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); - view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); - view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); - view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); - view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); - view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); - view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); - - // Advanced > XUI - commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); - view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); - view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); - view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); - - // Advanced > Character > Grab Baked Texture - view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); - view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); - - // Advanced > Character > Character Tests - view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); - - view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); - view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); - - // Advanced > Character > Animation Speed - view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); - view_listener_t::addMenu(new LLAdvancedAnimTenSlower(), "Advanced.AnimTenSlower"); - view_listener_t::addMenu(new LLAdvancedAnimResetAll(), "Advanced.AnimResetAll"); - - // Advanced > Character (toplevel) - view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); - view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); - view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); - view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); - view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); - view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); - view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); - view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); - view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); - // Advanced > Network - view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); + // Advanced > UI + commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser + commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater + commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); + commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); + view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); + view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); + view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); + commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); + commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); + view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); + view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); + view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); + view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); + view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); + view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); + view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); + view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); + + // Advanced > XUI + commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); + view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); + view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); + view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); + commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); + + // Advanced > Character > Grab Baked Texture + view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); + view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); + + // Advanced > Character > Character Tests + view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); + + view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); + view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); + + // Advanced > Character > Animation Speed + view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); + view_listener_t::addMenu(new LLAdvancedAnimTenSlower(), "Advanced.AnimTenSlower"); + view_listener_t::addMenu(new LLAdvancedAnimResetAll(), "Advanced.AnimResetAll"); + + // Advanced > Character (toplevel) + view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); + view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); + view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); + view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); + view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); + view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); + view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); + view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); + view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); + // Advanced > Network + view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); // Advanced > Cache view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache"); - // Advanced > Recorder - view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); - view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop"); - view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop"); - view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); + // Advanced > Recorder + view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); + view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop"); + view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop"); + view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); - // Advanced > Debugging - view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); + // Advanced > Debugging + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); + view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); - // Advanced (toplevel) - view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); + // Advanced (toplevel) + view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest"); - view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); - view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); - - view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); - view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); - - // Develop >Set logging level - view_listener_t::addMenu(new LLDevelopCheckLoggingLevel(), "Develop.CheckLoggingLevel"); - view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); - - //Develop (clear cache immediately) - commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); - - // Develop (Fonts debugging) - commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); - commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); - - // Admin >Object - view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); - view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); - view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); - view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); - - // Admin >Parcel - view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); - view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); - view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); - - // Admin >Region - view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); - // Admin top level - view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); - - // Self context menu - view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); - enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); - view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); - - view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); - - // we don't use boost::bind directly to delay side tray construction - view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); - view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab"); - - // Avatar pie menu - view_listener_t::addMenu(new LLAvatarCheckImpostorMode(), "Avatar.CheckImpostorMode"); - view_listener_t::addMenu(new LLAvatarSetImpostorMode(), "Avatar.SetImpostorMode"); - view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); - view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); - view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); - commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); - view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); - view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); - view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); - commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); - view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); - view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); - enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); - view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); - view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); - view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); - view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); - view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); - view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); - view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); - view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); - enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); + view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); + view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); + + view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); + view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); + + // Develop >Set logging level + view_listener_t::addMenu(new LLDevelopCheckLoggingLevel(), "Develop.CheckLoggingLevel"); + view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); + + //Develop (clear cache immediately) + commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + + // Develop (Fonts debugging) + commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); + commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); + + // Admin >Object + view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); + view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); + view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); + view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); + + // Admin >Parcel + view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); + view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); + view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); + + // Admin >Region + view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); + // Admin top level + view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); + + // Self context menu + view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); + enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); + view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); + + view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); + + // we don't use boost::bind directly to delay side tray construction + view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); + view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab"); + + // Avatar pie menu + view_listener_t::addMenu(new LLAvatarCheckImpostorMode(), "Avatar.CheckImpostorMode"); + view_listener_t::addMenu(new LLAvatarSetImpostorMode(), "Avatar.SetImpostorMode"); + view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); + view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); + view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); + commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); + view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); + view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); + view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); + commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); + commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); + view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); + view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); + enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); + view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); + view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); + view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); + view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); + view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); + view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); + view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); + enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible)); - commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); - - view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); - enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); - - // Object pie menu - view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); - commit.add("Object.Touch", boost::bind(&handle_object_touch)); - commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); - commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - commit.add("Object.Delete", boost::bind(&handle_object_delete)); - view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); - view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); - view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); - commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); - view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); - - enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); - enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - - commit.add("Object.Buy", boost::bind(&handle_buy)); - commit.add("Object.Edit", boost::bind(&handle_object_edit)); + commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); + + view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); + enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); + + // Object pie menu + view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); + commit.add("Object.Touch", boost::bind(&handle_object_touch)); + commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); + commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); + commit.add("Object.Delete", boost::bind(&handle_object_delete)); + view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); + view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); + view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); + commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); + view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); + + enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); + enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); + + commit.add("Object.Buy", boost::bind(&handle_buy)); + commit.add("Object.Edit", boost::bind(&handle_object_edit)); commit.add("Object.Edit", boost::bind(&handle_object_edit)); commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); - commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); - commit.add("Object.Open", boost::bind(&handle_object_open)); - commit.add("Object.Take", boost::bind(&handle_take)); - commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); + commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); + commit.add("Object.Open", boost::bind(&handle_object_open)); + commit.add("Object.Take", boost::bind(&handle_take)); + commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect)); enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); - enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); - enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); - enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); - enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); - - enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); - enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); - - view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); - enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); - - enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); - enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); - commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); - - // Attachment pie menu - enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); - view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); - view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); - view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); - view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); - view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); - view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); - - // Land pie menu - view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); - view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); + enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); + enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); + enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); + enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); + + enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); + enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); + + view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); + enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); + + enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); + enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); + enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); + enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); + commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); + + // Attachment pie menu + enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); + view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); + view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); + view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); + view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); + view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); + view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); + + // Land pie menu + view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); + view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); view_listener_t::addMenu(new LLLandCanSit(), "Land.CanSit"); - view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); - view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); - - // Particle muting - view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); - - view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - commit.add("Land.Buy", boost::bind(&handle_buy_land)); - - // Generic actions - commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); - commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); - view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); - view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); - view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); - view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); - view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); + view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); + view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); + + // Particle muting + view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); + + view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); + commit.add("Land.Buy", boost::bind(&handle_buy_land)); + + // Generic actions + commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); + commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); + view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); + view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); + view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); + view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); + view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks"); - view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); - view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); + view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); + view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); - view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); - view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); - commit.add("PayObject", boost::bind(&handle_give_money_dialog)); - - commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); - - enable.add("EnablePayObject", boost::bind(&enable_pay_object)); - enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); - enable.add("EnableEdit", boost::bind(&enable_object_edit)); - enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); - enable.add("VisibleBuild", boost::bind(&enable_object_build)); - commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); - enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); - enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); - commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); - enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); + view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); + view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); + commit.add("PayObject", boost::bind(&handle_give_money_dialog)); + + commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); + + enable.add("EnablePayObject", boost::bind(&enable_pay_object)); + enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); + enable.add("EnableEdit", boost::bind(&enable_object_edit)); + enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); + enable.add("VisibleBuild", boost::bind(&enable_object_build)); + commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); + enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); + enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); + commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); + enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); - view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); - view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); - view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); - view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); - view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); - view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); - view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); - view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); + view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); + view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); + view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); + view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); + view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); + view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); + view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); + view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b43de3fe3f..6ac783fec5 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenu.h * @brief Builds menus out of objects * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -156,38 +156,38 @@ U64 info_display_from_string(std::string info_display); class LLViewerMenuHolderGL : public LLMenuHolderGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuHolderGL::Params> - {}; + struct Params : public LLInitParam::Block<Params, LLMenuHolderGL::Params> + {}; + + LLViewerMenuHolderGL(const Params& p); - LLViewerMenuHolderGL(const Params& p); + virtual BOOL hideMenus(); - virtual BOOL hideMenus(); - - void setParcelSelection(LLSafeHandle<LLParcelSelection> selection); - void setObjectSelection(LLSafeHandle<LLObjectSelection> selection); + void setParcelSelection(LLSafeHandle<LLParcelSelection> selection); + void setObjectSelection(LLSafeHandle<LLObjectSelection> selection); - virtual const LLRect getMenuRect() const; + virtual const LLRect getMenuRect() const; protected: - LLSafeHandle<LLParcelSelection> mParcelSelection; - LLSafeHandle<LLObjectSelection> mObjectSelection; + LLSafeHandle<LLParcelSelection> mParcelSelection; + LLSafeHandle<LLObjectSelection> mObjectSelection; }; -extern LLMenuBarGL* gMenuBarView; -//extern LLView* gMenuBarHolder; -extern LLMenuGL* gEditMenu; -extern LLMenuGL* gPopupMenuView; -extern LLViewerMenuHolderGL* gMenuHolder; -extern LLMenuBarGL* gLoginMenuBarView; +extern LLMenuBarGL* gMenuBarView; +//extern LLView* gMenuBarHolder; +extern LLMenuGL* gEditMenu; +extern LLMenuGL* gPopupMenuView; +extern LLViewerMenuHolderGL* gMenuHolder; +extern LLMenuBarGL* gLoginMenuBarView; // Context menus in 3D scene -extern LLContextMenu *gMenuAvatarSelf; -extern LLContextMenu *gMenuAvatarOther; -extern LLContextMenu *gMenuObject; -extern LLContextMenu *gMenuAttachmentSelf; -extern LLContextMenu *gMenuAttachmentOther; -extern LLContextMenu *gMenuLand; -extern LLContextMenu *gMenuMuteParticle; +extern LLContextMenu *gMenuAvatarSelf; +extern LLContextMenu *gMenuAvatarOther; +extern LLContextMenu *gMenuObject; +extern LLContextMenu *gMenuAttachmentSelf; +extern LLContextMenu *gMenuAttachmentOther; +extern LLContextMenu *gMenuLand; +extern LLContextMenu *gMenuMuteParticle; // Needed to build menus when attachment site list available extern LLMenuGL* gAttachSubMenu; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a1dc7119ce..243c3aeff8 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenufile.cpp * @brief "File" menu in the main menu bar. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,17 +47,17 @@ #include "llimagej2c.h" #include "llimagejpeg.h" #include "llimagetga.h" -#include "llinventorymodel.h" // gInventory +#include "llinventorymodel.h" // gInventory #include "llpluginclassmedia.h" #include "llresourcedata.h" #include "llstatusbar.h" #include "lltinygltfhelper.h" #include "lltoast.h" -#include "llviewercontrol.h" // gSavedSettings +#include "llviewercontrol.h" // gSavedSettings #include "llviewertexturelist.h" #include "lluictrlfactory.h" #include "llviewerinventory.h" -#include "llviewermenu.h" // gMenuHolder +#include "llviewermenu.h" // gMenuHolder #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" @@ -83,24 +83,24 @@ class LLFileEnableUpload : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { return true; - } + } }; class LLFileEnableUploadModel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model"); - if (fmp && fmp->isModelLoading()) - { - return false; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model"); + if (fmp && fmp->isModelLoading()) + { + return false; + } + + return true; + } }; class LLFileEnableUploadMaterial : public view_listener_t @@ -118,18 +118,18 @@ class LLFileEnableUploadMaterial : public view_listener_t class LLMeshEnabled : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gSavedSettings.getBOOL("MeshEnabled"); - } + bool handleEvent(const LLSD& userdata) + { + return gSavedSettings.getBOOL("MeshEnabled"); + } }; class LLMeshUploadVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gMeshRepo.meshUploadEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return gMeshRepo.meshUploadEnabled(); + } }; LLMutex* LLFilePickerThread::sMutex = NULL; @@ -139,51 +139,51 @@ void LLFilePickerThread::getFile() { #if LL_WINDOWS // Todo: get rid of LLFilePickerThread and make this modeless - start(); + start(); #elif LL_DARWIN runModeless(); #else - run(); + run(); #endif } -//virtual +//virtual void LLFilePickerThread::run() { #if LL_WINDOWS - bool blocking = false; + bool blocking = false; #else - bool blocking = true; // modal + bool blocking = true; // modal #endif - LLFilePicker picker; - - if (mIsSaveDialog) - { - if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) - { - mResponses.push_back(picker.getFirstFile()); - } - } - else - { - bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking); - if (result) - { - std::string filename = picker.getFirstFile(); // consider copying mFiles directly - do - { - mResponses.push_back(filename); - filename = picker.getNextFile(); - } - while (mIsGetMultiple && !filename.empty()); - } - } - - { - LLMutexLock lock(sMutex); - sDeadQ.push(this); - } + LLFilePicker picker; + + if (mIsSaveDialog) + { + if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) + { + mResponses.push_back(picker.getFirstFile()); + } + } + else + { + bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking); + if (result) + { + std::string filename = picker.getFirstFile(); // consider copying mFiles directly + do + { + mResponses.push_back(filename); + filename = picker.getNextFile(); + } + while (mIsGetMultiple && !filename.empty()); + } + } + + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } } void LLFilePickerThread::runModeless() @@ -206,7 +206,7 @@ void LLFilePickerThread::runModeless() { result = picker.getOpenFileModeless(mLoadFilter, modelessVectorCallback, this); } - + if (!result) { LLMutexLock lock(sMutex); @@ -223,7 +223,7 @@ void LLFilePickerThread::modelessStringCallback(bool success, { picker->mResponses.push_back(response); } - + { LLMutexLock lock(sMutex); sDeadQ.push(picker); @@ -255,7 +255,7 @@ void LLFilePickerThread::modelessVectorCallback(bool success, } } } - + { LLMutexLock lock(sMutex); sDeadQ.push(picker); @@ -265,66 +265,66 @@ void LLFilePickerThread::modelessVectorCallback(bool success, //static void LLFilePickerThread::initClass() { - sMutex = new LLMutex(); + sMutex = new LLMutex(); } //static void LLFilePickerThread::cleanupClass() { - clearDead(); - - delete sMutex; - sMutex = NULL; + clearDead(); + + delete sMutex; + sMutex = NULL; } //static void LLFilePickerThread::clearDead() { - if (!sDeadQ.empty()) - { - LLMutexLock lock(sMutex); - while (!sDeadQ.empty()) - { - LLFilePickerThread* thread = sDeadQ.front(); - thread->notify(thread->mResponses); - delete thread; - sDeadQ.pop(); - } - } + if (!sDeadQ.empty()) + { + LLMutexLock lock(sMutex); + while (!sDeadQ.empty()) + { + LLFilePickerThread* thread = sDeadQ.front(); + thread->notify(thread->mResponses); + delete thread; + sDeadQ.pop(); + } + } } 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), - mFailureSignal(NULL) + : LLFilePickerThread(filter, get_multiple), + mLoadFilter(filter), + mSaveFilter(LLFilePicker::FFSAVE_ALL), + mFilePickedSignal(NULL), + mFailureSignal(NULL) { - mFilePickedSignal = new file_picked_signal_t(); - mFilePickedSignal->connect(cb); + mFilePickedSignal = new file_picked_signal_t(); + mFilePickedSignal->connect(cb); - mFailureSignal = new file_picked_signal_t(); - mFailureSignal->connect(failure_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, const file_picked_signal_t::slot_type& failure_cb) - : LLFilePickerThread(filter, proposed_name), - mLoadFilter(LLFilePicker::FFLOAD_ALL), - mSaveFilter(filter), - mFilePickedSignal(NULL), - mFailureSignal(NULL) + : LLFilePickerThread(filter, proposed_name), + mLoadFilter(LLFilePicker::FFLOAD_ALL), + mSaveFilter(filter), + mFilePickedSignal(NULL), + mFailureSignal(NULL) { - mFilePickedSignal = new file_picked_signal_t(); - mFilePickedSignal->connect(cb); + mFilePickedSignal = new file_picked_signal_t(); + mFilePickedSignal->connect(cb); - mFailureSignal = new file_picked_signal_t(); - mFailureSignal->connect(failure_cb); + mFailureSignal = new file_picked_signal_t(); + mFailureSignal->connect(failure_cb); } LLFilePickerReplyThread::~LLFilePickerReplyThread() { - delete mFilePickedSignal; - delete mFailureSignal; + delete mFilePickedSignal; + delete mFailureSignal; } void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb) @@ -339,20 +339,20 @@ void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames) { - if (filenames.empty()) - { - if (mFailureSignal) - { - (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); - } - } - else - { - if (mFilePickedSignal) - { - (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); - } - } + if (filenames.empty()) + { + if (mFailureSignal) + { + (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); + } + } + else + { + if (mFilePickedSignal) + { + (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); + } + } } @@ -389,167 +389,167 @@ static std::string MATERIAL_EXTENSIONS = "gltf glb"; std::string build_extensions_string(LLFilePicker::ELoadFilter filter) { - switch(filter) - { + switch(filter) + { #if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: - return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: - return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: - return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: - return SLOBJECT_EXTENSIONS; - case LLFilePicker::FFLOAD_MODEL: - return MODEL_EXTENSIONS; + case LLFilePicker::FFLOAD_IMAGE: + return IMAGE_EXTENSIONS; + case LLFilePicker::FFLOAD_WAV: + return SOUND_EXTENSIONS; + case LLFilePicker::FFLOAD_ANIM: + return ANIM_EXTENSIONS; + case LLFilePicker::FFLOAD_SLOBJECT: + return SLOBJECT_EXTENSIONS; + case LLFilePicker::FFLOAD_MODEL: + return MODEL_EXTENSIONS; case LLFilePicker::FFLOAD_MATERIAL: return MATERIAL_EXTENSIONS; - case LLFilePicker::FFLOAD_XML: - return XML_EXTENSIONS; + case LLFilePicker::FFLOAD_XML: + return XML_EXTENSIONS; case LLFilePicker::FFLOAD_ALL: case LLFilePicker::FFLOAD_EXE: - return ALL_FILE_EXTENSIONS; + return ALL_FILE_EXTENSIONS; #endif default: - return ALL_FILE_EXTENSIONS; - } + return ALL_FILE_EXTENSIONS; + } } const bool check_file_extension(const std::string& filename, LLFilePicker::ELoadFilter type) { - std::string ext = gDirUtilp->getExtension(filename); - - //strincmp doesn't like NULL pointers - if (ext.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - LLSD args; - args["FILE"] = short_name; - LLNotificationsUtil::add("NoFileExtension", args); - return false; - } - else - { - //so there is an extension - //loop over the valid extensions and compare to see - //if the extension is valid - - //now grab the set of valid file extensions - std::string valid_extensions = build_extensions_string(type); - - BOOL ext_valid = FALSE; - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep(" "); - tokenizer tokens(valid_extensions, sep); - tokenizer::iterator token_iter; - - //now loop over all valid file extensions - //and compare them to the extension of the file - //to be uploaded - for (token_iter = tokens.begin(); - token_iter != tokens.end() && ext_valid != TRUE; - ++token_iter) - { - const std::string& cur_token = *token_iter; - - if (cur_token == ext || cur_token == "*.*") - { - //valid extension - //or the acceptable extension is any - ext_valid = TRUE; - } - }//end for (loop over all tokens) - - if (ext_valid == FALSE) - { - //should only get here if the extension exists - //but is invalid - LLSD args; - args["EXTENSION"] = ext; - args["VALIDS"] = valid_extensions; - LLNotificationsUtil::add("InvalidFileExtension", args); - return false; - } - }//end else (non-null extension) - return true; + std::string ext = gDirUtilp->getExtension(filename); + + //strincmp doesn't like NULL pointers + if (ext.empty()) + { + std::string short_name = gDirUtilp->getBaseFileName(filename); + + // No extension + LLSD args; + args["FILE"] = short_name; + LLNotificationsUtil::add("NoFileExtension", args); + return false; + } + else + { + //so there is an extension + //loop over the valid extensions and compare to see + //if the extension is valid + + //now grab the set of valid file extensions + std::string valid_extensions = build_extensions_string(type); + + BOOL ext_valid = FALSE; + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + tokenizer tokens(valid_extensions, sep); + tokenizer::iterator token_iter; + + //now loop over all valid file extensions + //and compare them to the extension of the file + //to be uploaded + for (token_iter = tokens.begin(); + token_iter != tokens.end() && ext_valid != TRUE; + ++token_iter) + { + const std::string& cur_token = *token_iter; + + if (cur_token == ext || cur_token == "*.*") + { + //valid extension + //or the acceptable extension is any + ext_valid = TRUE; + } + }//end for (loop over all tokens) + + if (ext_valid == FALSE) + { + //should only get here if the extension exists + //but is invalid + LLSD args; + args["EXTENSION"] = ext; + args["VALIDS"] = valid_extensions; + LLNotificationsUtil::add("InvalidFileExtension", args); + return false; + } + }//end else (non-null extension) + return true; } const void upload_single_file(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type) { - std::string filename = filenames[0]; - if (!check_file_extension(filename, type)) return; - - if (!filename.empty()) - { - if (type == LLFilePicker::FFLOAD_WAV) - { - // pre-qualify wavs to make sure the format is acceptable - std::string error_msg; - if (check_for_invalid_wav_formats(filename, error_msg)) - { - LL_INFOS() << error_msg << ": " << filename << LL_ENDL; - LLSD args; - args["FILE"] = filename; - LLNotificationsUtil::add(error_msg, args); - return; - } - else - { - LLFloaterReg::showInstance("upload_sound", LLSD(filename)); - } - } - if (type == LLFilePicker::FFLOAD_IMAGE) - { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); - } - if (type == LLFilePicker::FFLOAD_ANIM) - { - std::string filename_lc(filename); - LLStringUtil::toLower(filename_lc); - if (filename_lc.rfind(".anim") != std::string::npos) - { - LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); - } - else - { - LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); - } - } - } - return; + std::string filename = filenames[0]; + if (!check_file_extension(filename, type)) return; + + if (!filename.empty()) + { + if (type == LLFilePicker::FFLOAD_WAV) + { + // pre-qualify wavs to make sure the format is acceptable + std::string error_msg; + if (check_for_invalid_wav_formats(filename, error_msg)) + { + LL_INFOS() << error_msg << ": " << filename << LL_ENDL; + LLSD args; + args["FILE"] = filename; + LLNotificationsUtil::add(error_msg, args); + return; + } + else + { + LLFloaterReg::showInstance("upload_sound", LLSD(filename)); + } + } + if (type == LLFilePicker::FFLOAD_IMAGE) + { + LLFloaterReg::showInstance("upload_image", LLSD(filename)); + } + if (type == LLFilePicker::FFLOAD_ANIM) + { + std::string filename_lc(filename); + LLStringUtil::toLower(filename_lc); + if (filename_lc.rfind(".anim") != std::string::npos) + { + LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); + } + else + { + LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); + } + } + } + return; } void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) - { - // Cancel upload - return; - } - - for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - std::string filename = (*in_iter); - - std::string name = gDirUtilp->getBaseFileName(filename, true); - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII(asset_name, '?'); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string ext = gDirUtilp->getExtension(filename); - LLAssetType::EType asset_type; - U32 codec; - S32 expected_upload_cost; - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) - { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + // Cancel upload + return; + } + + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + + std::string name = gDirUtilp->getBaseFileName(filename, true); + std::string asset_name = name; + LLStringUtil::replaceNonstandardASCII(asset_name, '?'); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string ext = gDirUtilp->getExtension(filename); + LLAssetType::EType asset_type; + U32 codec; + S32 expected_upload_cost; + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) + { LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( filename, asset_name, @@ -585,34 +585,34 @@ void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost, S32& file_count, S32& bvh_count) { - total_cost = 0; - file_count = 0; - bvh_count = 0; - for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - std::string filename = (*in_iter); - std::string ext = gDirUtilp->getExtension(filename); - - if (ext == "bvh") - { - bvh_count++; - } - - LLAssetType::EType asset_type; - U32 codec; - S32 cost; - - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) - { - total_cost += cost; - file_count++; - } + total_cost = 0; + file_count = 0; + bvh_count = 0; + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + std::string ext = gDirUtilp->getExtension(filename); + + if (ext == "bvh") + { + bvh_count++; + } + + LLAssetType::EType asset_type; + U32 codec; + S32 cost; + + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) + { + total_cost += cost; + file_count++; + } if (ext == "gltf" || ext == "glb") { S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - + tinygltf::Model model; if (LLTinyGLTFHelper::loadModel(filename, model)) @@ -652,87 +652,87 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3 } } } - } - + } + return file_count > 0; } const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type) { - // TODO: - // Check user balance for entire cost - // Charge user entire cost - // Loop, uploading - // If an upload fails, refund the user for that one - // - // Also fix single upload to charge first, then refund - - // FIXME PREMIUM what about known types that can't be bulk uploaded - // (bvh)? These will fail in the item by item upload but won't be - // mentioned in the notification. - std::vector<std::string> filtered_filenames; - for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - const std::string& filename = *in_iter; - if (check_file_extension(filename, type)) - { - filtered_filenames.push_back(filename); - } - } - - S32 expected_upload_cost; - S32 expected_upload_count; - S32 bvh_count; - if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) - { - LLSD args; - args["COST"] = expected_upload_cost; - args["COUNT"] = expected_upload_count; - LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); - - if (filtered_filenames.size() > expected_upload_count) - { - if (bvh_count == filtered_filenames.size() - expected_upload_count) - { - LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); - } - else - { - LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); - } - } - } - else if (bvh_count == filtered_filenames.size()) - { - LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); - } - else - { - LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); - } + // TODO: + // Check user balance for entire cost + // Charge user entire cost + // Loop, uploading + // If an upload fails, refund the user for that one + // + // Also fix single upload to charge first, then refund + + // FIXME PREMIUM what about known types that can't be bulk uploaded + // (bvh)? These will fail in the item by item upload but won't be + // mentioned in the notification. + std::vector<std::string> filtered_filenames; + for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + const std::string& filename = *in_iter; + if (check_file_extension(filename, type)) + { + filtered_filenames.push_back(filename); + } + } + + S32 expected_upload_cost; + S32 expected_upload_count; + S32 bvh_count; + if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) + { + LLSD args; + args["COST"] = expected_upload_cost; + args["COUNT"] = expected_upload_count; + LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); + + if (filtered_filenames.size() > expected_upload_count) + { + if (bvh_count == filtered_filenames.size() - expected_upload_count) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); + } + } + } + else if (bvh_count == filtered_filenames.size()) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); + } } class LLFileUploadImage : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); + return true; + } }; class LLFileUploadModel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LLFloaterModelPreview::showModelPreview(); return TRUE; - } + } }; class LLFileUploadMaterial : public view_listener_t @@ -746,101 +746,101 @@ class LLFileUploadMaterial : public view_listener_t class LLFileUploadSound : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); + return true; + } }; class LLFileUploadAnim : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); + return true; + } }; class LLFileUploadBulk : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); + return true; + } }; -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) +void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) { - LL_WARNS() << error_message << LL_ENDL; - LLNotificationsUtil::add(label, args); - if(LLFile::remove(filename) == -1) - { - LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; - } - LLFilePicker::instance().reset(); + LL_WARNS() << error_message << LL_ENDL; + LLNotificationsUtil::add(label, args); + if(LLFile::remove(filename) == -1) + { + LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; + } + LLFilePicker::instance().reset(); } class LLFileEnableCloseWindow : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); - bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); - return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); - } + return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); + } }; class LLFileCloseWindow : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); - LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); - - if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) - { - snapshot_floater->closeFloater(); - if (gFocusMgr.getKeyboardFocus() == NULL) - { - gFloaterView->focusFrontFloater(); - } - } - else - { - LLFloater::closeFrontmostFloater(); - } - if (gMenuHolder) gMenuHolder->hideMenus(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); + + if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) + { + snapshot_floater->closeFloater(); + if (gFocusMgr.getKeyboardFocus() == NULL) + { + gFloaterView->focusFrontFloater(); + } + } + else + { + LLFloater::closeFrontmostFloater(); + } + if (gMenuHolder) gMenuHolder->hideMenus(); + return true; + } }; class LLFileEnableCloseAllWindows : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); - bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()); - bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; - return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown(); - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); + bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()); + bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; + return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown(); + } }; -void close_all_windows() +void close_all_windows() { bool app_quitting = false; gFloaterView->closeAllChildren(app_quitting); @@ -853,112 +853,112 @@ void close_all_windows() class LLFileCloseAllWindows : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - close_all_windows(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + close_all_windows(); + return true; + } }; class LLFileTakeSnapshotToDisk : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPointer<LLImageRaw> raw = new LLImageRaw; - - S32 width = gViewerWindow->getWindowWidthRaw(); - S32 height = gViewerWindow->getWindowHeightRaw(); - - BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); - BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); - BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); - - BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); - if (high_res) - { - width *= 2; - height *= 2; - // not compatible with UI/HUD - render_ui = false; - render_hud = false; - } - - if (gViewerWindow->rawSnapshot(raw, - width, - height, - TRUE, - FALSE, - render_ui, - render_hud, - FALSE, - render_no_post, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side - { - LLPointer<LLImageFormatted> formatted; + bool handleEvent(const LLSD& userdata) + { + LLPointer<LLImageRaw> raw = new LLImageRaw; + + S32 width = gViewerWindow->getWindowWidthRaw(); + S32 height = gViewerWindow->getWindowHeightRaw(); + + BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); + BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); + + BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); + if (high_res) + { + width *= 2; + height *= 2; + // not compatible with UI/HUD + render_ui = false; + render_hud = false; + } + + if (gViewerWindow->rawSnapshot(raw, + width, + height, + TRUE, + FALSE, + render_ui, + render_hud, + FALSE, + render_no_post, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side + { + LLPointer<LLImageFormatted> formatted; LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); - switch (fmt) - { - case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG: - formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); - break; - default: - LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL; - case LLSnapshotModel::SNAPSHOT_FORMAT_PNG: - formatted = new LLImagePNG; - break; - case LLSnapshotModel::SNAPSHOT_FORMAT_BMP: - formatted = new LLImageBMP; - break; - } - formatted->enableOverSize() ; - formatted->encode(raw, 0); - formatted->disableOverSize() ; - LLSnapshotLivePreview::saveLocal(formatted); - } - return true; - } + switch (fmt) + { + case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG: + formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); + break; + default: + LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL; + case LLSnapshotModel::SNAPSHOT_FORMAT_PNG: + formatted = new LLImagePNG; + break; + case LLSnapshotModel::SNAPSHOT_FORMAT_BMP: + formatted = new LLImageBMP; + break; + } + formatted->enableOverSize() ; + formatted->encode(raw, 0); + formatted->disableOverSize() ; + LLSnapshotLivePreview::saveLocal(formatted); + } + return true; + } }; class LLFileQuit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAppViewer::instance()->userQuit(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAppViewer::instance()->userQuit(); + return true; + } }; void handle_compress_image(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) - { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) - { - std::string outfile = infile + ".j2c"; - - LL_INFOS() << "Input: " << infile << LL_ENDL; - LL_INFOS() << "Output: " << outfile << LL_ENDL; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - LL_INFOS() << "Compression complete" << LL_ENDL; - } - else - { - LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; - } - - infile = picker.getNextFile(); - } - } + LLFilePicker& picker = LLFilePicker::instance(); + if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) + { + std::string infile = picker.getFirstFile(); + while (!infile.empty()) + { + std::string outfile = infile + ".j2c"; + + LL_INFOS() << "Input: " << infile << LL_ENDL; + LL_INFOS() << "Output: " << outfile << LL_ENDL; + + BOOL success; + + success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + + if (success) + { + LL_INFOS() << "Compression complete" << LL_ENDL; + } + else + { + LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; + } + + infile = picker.getNextFile(); + } + } } // No convinient check in LLFile, and correct way would be something @@ -966,7 +966,7 @@ void handle_compress_image(void*) // so doing dirty, but OS independent fopen and fseek size_t get_file_size(std::string &filename) { - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -1051,21 +1051,21 @@ void handle_compress_file_test(void*) LLUUID upload_new_resource( - const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata, - bool show_inventory) -{ + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata, + bool show_inventory) +{ LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewFileResourceUploadInfo>( src_filename, @@ -1079,127 +1079,127 @@ LLUUID upload_new_resource( } void upload_done_callback( - const LLUUID& uuid, - void* user_data, - S32 result, - LLExtStat ext_status) // StoreAssetData callback (fixed) + const LLUUID& uuid, + void* user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) { - LLResourceData* data = (LLResourceData*)user_data; - S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; - //LLAssetType::EType pref_loc = data->mPreferredLocation; - BOOL is_balance_sufficient = TRUE; - - if(data) - { - if (result >= 0) - { - LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; - - if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || - LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || - LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) - { - // Charge the user for the upload. - LLViewerRegion* region = gAgent.getRegion(); - - if(!(can_afford_transaction(expected_upload_cost))) - { - LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); - is_balance_sufficient = FALSE; - } - else if(region) - { - // Charge user for upload - gStatusBar->debitBalance(expected_upload_cost); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); - msg->addU8("Flags", 0); - // we tell the sim how much we were expecting to pay so it - // can respond to any discrepancy - msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); - msg->addStringFast(_PREHASH_Description, NULL); - msg->sendReliable(region->getHost()); - } - } - - if(is_balance_sufficient) - { - // Actually add the upload to inventory - LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); - if(folder_id.notNull()) - { - U32 next_owner_perms = data->mNextOwnerPerm; - if(PERM_NONE == next_owner_perms) - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), - data->mAssetInfo.getDescription(), data->mAssetInfo.mType, + LLResourceData* data = (LLResourceData*)user_data; + S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; + //LLAssetType::EType pref_loc = data->mPreferredLocation; + BOOL is_balance_sufficient = TRUE; + + if(data) + { + if (result >= 0) + { + LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; + + if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || + LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || + LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) + { + // Charge the user for the upload. + LLViewerRegion* region = gAgent.getRegion(); + + if(!(can_afford_transaction(expected_upload_cost))) + { + LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); + is_balance_sufficient = FALSE; + } + else if(region) + { + // Charge user for upload + gStatusBar->debitBalance(expected_upload_cost); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoneyTransferRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_MoneyData); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); + msg->addU8("Flags", 0); + // we tell the sim how much we were expecting to pay so it + // can respond to any discrepancy + msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); + msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); + msg->addStringFast(_PREHASH_Description, NULL); + msg->sendReliable(region->getHost()); + } + } + + if(is_balance_sufficient) + { + // Actually add the upload to inventory + LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; + const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); + if(folder_id.notNull()) + { + U32 next_owner_perms = data->mNextOwnerPerm; + if(PERM_NONE == next_owner_perms) + { + next_owner_perms = PERM_MOVE | PERM_TRANSFER; + } + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), + data->mAssetInfo.getDescription(), data->mAssetInfo.mType, data->mInventoryType, NO_INV_SUBTYPE, next_owner_perms, - LLPointer<LLInventoryCallback>(NULL)); - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } - } - } - else // if(result >= 0) - { - LLSD args; - args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); - args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); - LLNotificationsUtil::add("CannotUploadReason", args); - } - - delete data; - data = NULL; - } - - LLUploadDialog::modalUploadFinished(); - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback; - void *userdata = NULL; - upload_new_resource( - next_file, - asset_name, - asset_name, // file - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } + LLPointer<LLInventoryCallback>(NULL)); + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } + } + } + else // if(result >= 0) + { + LLSD args; + args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); + args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); + LLNotificationsUtil::add("CannotUploadReason", args); + } + + delete data; + data = NULL; + } + + LLUploadDialog::modalUploadFinished(); + + // *NOTE: This is a pretty big hack. What this does is check the + // file picker if there are any more pending uploads. If so, + // upload that file. + const std::string& next_file = LLFilePicker::instance().getNextFile(); + if(is_balance_sufficient && !next_file.empty()) + { + std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); + LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string display_name = LLStringUtil::null; + LLAssetStorage::LLStoreAssetCallback callback; + void *userdata = NULL; + upload_new_resource( + next_file, + asset_name, + asset_name, // file + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + display_name, + callback, + expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost + userdata); + } } void upload_new_resource( @@ -1207,90 +1207,90 @@ void upload_new_resource( LLAssetStorage::LLStoreAssetCallback callback, void *userdata) { - if(gDisconnected) - { - return ; - } + if(gDisconnected) + { + return ; + } // uploadInfo->setAssetType(assetType); // uploadInfo->setTransactionId(tid); - std::string url = gAgent.getRegionCapability("NewFileAgentInventory"); + std::string url = gAgent.getRegionCapability("NewFileAgentInventory"); - if ( !url.empty() ) - { + if ( !url.empty() ) + { LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); - } - else - { + } + else + { uploadInfo->prepareUpload(); uploadInfo->logPreparedUpload(); - LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; - // check for adequate funds - // TODO: do this check on the sim - if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || + LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; + // check for adequate funds + // TODO: do this check on the sim + if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() || LLAssetType::AT_ANIMATION == uploadInfo->getAssetType()) - { - S32 balance = gStatusBar->getBalance(); - if (balance < uploadInfo->getExpectedUploadCost()) - { - // insufficient funds, bail on this upload + { + S32 balance = gStatusBar->getBalance(); + if (balance < uploadInfo->getExpectedUploadCost()) + { + // insufficient funds, bail on this upload LLBuyCurrencyHTML::openCurrencyFloater("", uploadInfo->getExpectedUploadCost()); - return; - } - } + return; + } + } - LLResourceData* data = new LLResourceData; - data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); - data->mAssetInfo.mUuid = uploadInfo->getAssetId(); + LLResourceData* data = new LLResourceData; + data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); + data->mAssetInfo.mUuid = uploadInfo->getAssetId(); data->mAssetInfo.mType = uploadInfo->getAssetType(); - data->mAssetInfo.mCreatorID = gAgentID; - data->mInventoryType = uploadInfo->getInventoryType(); - data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); - data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); - data->mUserData = userdata; - data->mAssetInfo.setName(uploadInfo->getName()); - data->mAssetInfo.setDescription(uploadInfo->getDescription()); - data->mPreferredLocation = uploadInfo->getDestinationFolderType(); - - LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; - if (callback) - { - asset_callback = callback; - } - gAssetStorage->storeAssetData( - data->mAssetInfo.mTransactionID, - data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); - } + data->mAssetInfo.mCreatorID = gAgentID; + data->mInventoryType = uploadInfo->getInventoryType(); + data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); + data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); + data->mUserData = userdata; + data->mAssetInfo.setName(uploadInfo->getName()); + data->mAssetInfo.setDescription(uploadInfo->getDescription()); + data->mPreferredLocation = uploadInfo->getDestinationFolderType(); + + LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; + if (callback) + { + asset_callback = callback; + } + gAssetStorage->storeAssetData( + data->mAssetInfo.mTransactionID, + data->mAssetInfo.mType, + asset_callback, + (void*)data, + FALSE); + } } void init_menu_file() { - view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); - view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); - view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); - view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); + view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); + view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); + view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); + view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); view_listener_t::addCommit(new LLFileUploadMaterial(), "File.UploadMaterial"); - view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); - view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); - view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); - view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); - view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); - view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); - view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); - - view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); - view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); + view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); + view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); + view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); + view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); + view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); + view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); + view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); + + view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); + view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); view_listener_t::addEnable(new LLFileEnableUploadMaterial(), "File.EnableUploadMaterial"); - view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); - view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); + view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); + view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); - // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. + // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index d41aa23829..5bf78a2c7f 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenufile.h * @brief "File" menu in the main menu bar. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -66,11 +66,11 @@ void upload_new_resource( void assign_defaults_and_show_upload_message( - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description); + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description); void close_all_windows(); @@ -79,39 +79,39 @@ class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) public: - static std::queue<LLFilePickerThread*> sDeadQ; - static LLMutex* sMutex; + static std::queue<LLFilePickerThread*> sDeadQ; + static LLMutex* sMutex; - static void initClass(); - static void cleanupClass(); - static void clearDead(); + static void initClass(); + static void cleanupClass(); + static void clearDead(); - std::vector<std::string> mResponses; - std::string mProposedName; + std::vector<std::string> mResponses; + std::string mProposedName; - LLFilePicker::ELoadFilter mLoadFilter; - LLFilePicker::ESaveFilter mSaveFilter; - bool mIsSaveDialog; - bool mIsGetMultiple; + LLFilePicker::ELoadFilter mLoadFilter; + LLFilePicker::ESaveFilter mSaveFilter; + bool mIsSaveDialog; + bool mIsGetMultiple; - LLFilePickerThread(LLFilePicker::ELoadFilter filter, bool get_multiple = false) - : LLThread("file picker"), mLoadFilter(filter), mIsSaveDialog(false), mIsGetMultiple(get_multiple) - { - } + LLFilePickerThread(LLFilePicker::ELoadFilter filter, bool get_multiple = false) + : LLThread("file picker"), mLoadFilter(filter), mIsSaveDialog(false), mIsGetMultiple(get_multiple) + { + } - LLFilePickerThread(LLFilePicker::ESaveFilter filter, const std::string &proposed_name) - : LLThread("file picker"), mSaveFilter(filter), mIsSaveDialog(true), mProposedName(proposed_name) - { - } + LLFilePickerThread(LLFilePicker::ESaveFilter filter, const std::string &proposed_name) + : LLThread("file picker"), mSaveFilter(filter), mIsSaveDialog(true), mProposedName(proposed_name) + { + } - void getFile(); + void getFile(); - virtual void run(); + virtual void run(); void runModeless(); static void modelessStringCallback(bool success, std::string &response, void *user_data); static void modelessVectorCallback(bool success, std::vector<std::string> &responses, void *user_data); - virtual void notify(const std::vector<std::string>& filenames) = 0; + virtual void notify(const std::vector<std::string>& filenames) = 0; }; @@ -119,12 +119,12 @@ class LLFilePickerReplyThread : public LLFilePickerThread { public: - typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; + typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; static void startPicker(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()); static void startPicker(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()); - virtual void notify(const std::vector<std::string>& filenames); + virtual void notify(const std::vector<std::string>& filenames); private: 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()); @@ -132,10 +132,10 @@ private: ~LLFilePickerReplyThread(); private: - LLFilePicker::ELoadFilter mLoadFilter; - LLFilePicker::ESaveFilter mSaveFilter; - file_picked_signal_t* mFilePickedSignal; - file_picked_signal_t* mFailureSignal; + LLFilePicker::ELoadFilter mLoadFilter; + LLFilePicker::ESaveFilter mSaveFilter; + file_picked_signal_t* mFilePickedSignal; + file_picked_signal_t* mFailureSignal; }; class LLMediaFilePicker : public LLFilePickerThread diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e8b81ac3b4..4e4b4db38d 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermessage.cpp * @brief Dumping ground for viewer-side message system callbacks. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,9 +29,9 @@ // Linden libraries #include "llanimationstates.h" -#include "llaudioengine.h" +#include "llaudioengine.h" #include "llavataractions.h" -#include "llavatarnamecache.h" // IDEVO HACK +#include "llavatarnamecache.h" // IDEVO HACK #include "lleventtimer.h" #include "llfloatercreatelandmark.h" #include "llfloaterreg.h" @@ -91,7 +91,7 @@ #include "lltrans.h" #include "lltranslate.h" #include "llviewerfoldertype.h" -#include "llvoavatar.h" // IDEVO HACK +#include "llvoavatar.h" // IDEVO HACK #include "lluri.h" #include "llviewergenericmessage.h" #include "llviewermenu.h" @@ -136,8 +136,8 @@ const F32 CAMERA_POSITION_THRESHOLD_SQUARED = 0.001f * 0.001f; // Determine how quickly residents' scripts can issue question dialogs // Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in -static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests -static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds +static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests +static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds extern BOOL gDebugClicks; extern bool gShiftFrame; @@ -154,9 +154,9 @@ const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds // Agent Update Flags (U8) -const U8 AU_FLAGS_NONE = 0x00; -const U8 AU_FLAGS_HIDETITLE = 0x01; -const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02; +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) { @@ -253,25 +253,25 @@ void decline_friendship_coro(std::string url, LLSD notification, S32 option) bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem* msg = gMessageSystem; - const LLSD& payload = notification["payload"]; - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLMessageSystem* msg = gMessageSystem; + const LLSD& payload = notification["payload"]; + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); // this will be skipped if the user offering friendship is blocked if (notification_ptr) { - switch(option) - { - case 0: - { - LLUIUsage::instance().logCommand("Agent.AcceptFriendship"); - // accept - LLAvatarTracker::formFriendship(payload["from_id"]); + switch(option) + { + case 0: + { + LLUIUsage::instance().logCommand("Agent.AcceptFriendship"); + // accept + LLAvatarTracker::formFriendship(payload["from_id"]); - const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - // This will also trigger an onlinenotification if the user is online + // This will also trigger an onlinenotification if the user is online std::string url = gAgent.getRegionCapability("AcceptFriendship"); LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) @@ -302,15 +302,15 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { LL_WARNS("Friendship") << "Failed to accept friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; } - break; - } - case 1: // Decline - // fall-through - case 2: // Send IM - decline and start IM session - { - LLUIUsage::instance().logCommand("Agent.DeclineFriendship"); - // decline - // We no longer notify other viewers, but we DO still send + break; + } + case 1: // Decline + // fall-through + case 2: // Send IM - decline and start IM session + { + LLUIUsage::instance().logCommand("Agent.DeclineFriendship"); + // decline + // We no longer notify other viewers, but we DO still send // the rejection to the simulator to delete the pending userop. std::string url = gAgent.getRegionCapability("DeclineFriendship"); LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; @@ -346,24 +346,24 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { LL_WARNS("Friendship") << "Failed to decline friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; } - } - default: - // close button probably, possibly timed out - break; - } + } + default: + // close button probably, possibly timed out + break; + } - // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): - // here appears three additional toasts instead one modified - // need investigation and fix + // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): + // here appears three additional toasts instead one modified + // need investigation and fix - // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); - // modified_form->setElementEnabled("Accept", false); - // modified_form->setElementEnabled("Decline", false); - // notification_ptr->updateForm(modified_form); - // notification_ptr->repost(); + // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + // modified_form->setElementEnabled("Accept", false); + // modified_form->setElementEnabled("Decline", false); + // notification_ptr->updateForm(modified_form); + // notification_ptr->repost(); } - return false; + return false; } static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); @@ -372,139 +372,139 @@ static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("Offer // void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group, - S32 trx_type, const std::string& desc) -{ - if(0 == amount || !region) return; - amount = abs(amount); - LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; - if(can_afford_transaction(amount)) - { - if (uuid.isNull()) - { - LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; - return; - } -// gStatusBar->debitBalance(amount); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + S32 trx_type, const std::string& desc) +{ + if(0 == amount || !region) return; + amount = abs(amount); + LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; + if(can_afford_transaction(amount)) + { + if (uuid.isNull()) + { + LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; + return; + } +// gStatusBar->debitBalance(amount); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoneyTransferRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_DestID, uuid); - msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); - msg->addS32Fast(_PREHASH_Amount, amount); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, trx_type ); - msg->addStringFast(_PREHASH_Description, desc); - msg->sendReliable(region->getHost()); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", amount); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount ); - } + msg->nextBlockFast(_PREHASH_MoneyData); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_DestID, uuid); + msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); + msg->addS32Fast(_PREHASH_Amount, amount); + msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addS32Fast(_PREHASH_TransactionType, trx_type ); + msg->addStringFast(_PREHASH_Description, desc); + msg->sendReliable(region->getHost()); + } + else + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", amount); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount ); + } } void send_complete_agent_movement(const LLHost& sim_host) { - LL_DEBUGS("Teleport", "Messaging") << "Sending CompleteAgentMovement to sim_host " << sim_host << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_CompleteAgentMovement); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode); - msg->sendReliable(sim_host); + LL_DEBUGS("Teleport", "Messaging") << "Sending CompleteAgentMovement to sim_host " << sim_host << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_CompleteAgentMovement); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode); + msg->sendReliable(sim_host); } void process_logout_reply(LLMessageSystem* msg, void**) { - // The server has told us it's ok to quit. - LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL; - - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - LLUUID session_id; - msg->getUUID("AgentData", "SessionID", session_id); - if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) - { - LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; - } - - LLInventoryModel::update_map_t parents; - S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); - for(S32 i = 0; i < count; ++i) - { - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - - if( (1 == count) && item_id.isNull() ) - { - // Detect dummy item. Indicates an empty list. - break; - } - - // We do not need to track the asset ids, just account for an - // updated inventory version. - LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; - LLInventoryItem* item = gInventory.getItem( item_id ); - if( item ) - { - parents[item->getParentUUID()] = 0; - gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); - } - else - { - LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL; - } - } + // The server has told us it's ok to quit. + LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL; + + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + LLUUID session_id; + msg->getUUID("AgentData", "SessionID", session_id); + if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) + { + LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; + } + + LLInventoryModel::update_map_t parents; + S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); + for(S32 i = 0; i < count; ++i) + { + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); + + if( (1 == count) && item_id.isNull() ) + { + // Detect dummy item. Indicates an empty list. + break; + } + + // We do not need to track the asset ids, just account for an + // updated inventory version. + LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; + LLInventoryItem* item = gInventory.getItem( item_id ); + if( item ) + { + parents[item->getParentUUID()] = 0; + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); + } + else + { + LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL; + } + } LLAppViewer::instance()->forceQuit(); } void process_layer_data(LLMessageSystem *mesgsys, void **user_data) { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); - - LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; - - if(!regionp) - { - LL_WARNS() << "Invalid region for layer data." << LL_ENDL; - return; - } - S32 size; - S8 type; - - mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type); - size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data); - if (0 == size) - { - LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL; - return; - } - if (size < 0) - { - // getSizeFast() is probably trying to tell us about an error - LL_WARNS("Messaging") << "getSizeFast() returned negative result: " - << size - << LL_ENDL; - return; - } - U8 *datap = new U8[size]; - mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); - LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); - if (mesgsys->getReceiveCompressedSize()) - { - gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveCompressedSize()); - } - else - { - gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveSize()); - } + LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); + + LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; + + if(!regionp) + { + LL_WARNS() << "Invalid region for layer data." << LL_ENDL; + return; + } + S32 size; + S8 type; + + mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type); + size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data); + if (0 == size) + { + LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL; + return; + } + if (size < 0) + { + // getSizeFast() is probably trying to tell us about an error + LL_WARNS("Messaging") << "getSizeFast() returned negative result: " + << size + << LL_ENDL; + return; + } + U8 *datap = new U8[size]; + mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); + LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); + if (mesgsys->getReceiveCompressedSize()) + { + gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveCompressedSize()); + } + else + { + gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveSize()); + } } // S32 exported_object_count = 0; @@ -524,223 +524,223 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) // void export_complete() // { -// LLUploadDialog::modalUploadFinished(); -// gExporterRequestID.setNull(); -// gExportDirectory = ""; - -// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ -// fseek(fXML, 0, SEEK_END); -// long length = ftell(fXML); -// fseek(fXML, 0, SEEK_SET); -// U8 *buffer = new U8[length + 1]; -// size_t nread = fread(buffer, 1, length, fXML); -// if (nread < (size_t) length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// buffer[nread] = '\0'; -// fclose(fXML); - -// char *pos = (char *)buffer; -// while ((pos = strstr(pos+1, "<sl:image ")) != 0) -// { -// char *pos_check = strstr(pos, "checksum=\""); - -// if (pos_check) -// { -// char *pos_uuid = strstr(pos_check, "\">"); - -// if (pos_uuid) -// { -// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ -// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ -// image_uuid_str[UUID_STR_SIZE-1] = 0; - -// LLUUID image_uuid(image_uuid_str); - -// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; - -// std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid); -// if (itor != gImageChecksums.end()) -// { -// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; -// if (!itor->second.empty()) -// { -// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ -// } -// } -// } -// } -// } - -// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ -// if (fwrite(buffer, 1, length, fXMLOut) != length) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fclose(fXMLOut); - -// delete [] buffer; +// LLUploadDialog::modalUploadFinished(); +// gExporterRequestID.setNull(); +// gExportDirectory = ""; + +// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ +// fseek(fXML, 0, SEEK_END); +// long length = ftell(fXML); +// fseek(fXML, 0, SEEK_SET); +// U8 *buffer = new U8[length + 1]; +// size_t nread = fread(buffer, 1, length, fXML); +// if (nread < (size_t) length) +// { +// LL_WARNS("Messaging") << "Short read" << LL_ENDL; +// } +// buffer[nread] = '\0'; +// fclose(fXML); + +// char *pos = (char *)buffer; +// while ((pos = strstr(pos+1, "<sl:image ")) != 0) +// { +// char *pos_check = strstr(pos, "checksum=\""); + +// if (pos_check) +// { +// char *pos_uuid = strstr(pos_check, "\">"); + +// if (pos_uuid) +// { +// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ +// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ +// image_uuid_str[UUID_STR_SIZE-1] = 0; + +// LLUUID image_uuid(image_uuid_str); + +// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; + +// std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid); +// if (itor != gImageChecksums.end()) +// { +// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; +// if (!itor->second.empty()) +// { +// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ +// } +// } +// } +// } +// } + +// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ +// if (fwrite(buffer, 1, length, fXMLOut) != length) +// { +// LL_WARNS("Messaging") << "Short write" << LL_ENDL; +// } +// fclose(fXMLOut); + +// delete [] buffer; // } // void exported_item_complete(const LLTSCode status, void *user_data) // { -// //std::string *filename = (std::string *)user_data; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; -// } -// else -// { -// ++current_object_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; - -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -// } +// //std::string *filename = (std::string *)user_data; + +// if (status < LLTS_OK) +// { +// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; +// } +// else +// { +// ++current_object_count; +// if (current_image_count == exported_image_count && current_object_count == exported_object_count) +// { +// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; + +// export_complete(); +// } +// else +// { +// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); +// } +// } // } // struct exported_image_info // { -// LLUUID image_id; -// std::string filename; -// U32 image_num; +// LLUUID image_id; +// std::string filename; +// U32 image_num; // }; // void exported_j2c_complete(const LLTSCode status, void *user_data) // { -// exported_image_info *info = (exported_image_info *)user_data; -// LLUUID image_id = info->image_id; -// U32 image_num = info->image_num; -// std::string filename = info->filename; -// delete info; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; -// } -// else -// { -// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ -// if (fIn) -// { -// LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C; -// LLPointer<LLImageTGA> TargaUtility = new LLImageTGA; - -// fseek(fIn, 0, SEEK_END); -// S32 length = ftell(fIn); -// fseek(fIn, 0, SEEK_SET); -// U8 *buffer = ImageUtility->allocateData(length); -// if (fread(buffer, 1, length, fIn) != length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// fclose(fIn); -// LLFile::remove(filename); - -// // Convert to TGA -// LLPointer<LLImageRaw> image = new LLImageRaw(); - -// ImageUtility->updateData(); -// ImageUtility->decode(image, 100000.0f); - -// TargaUtility->encode(image); -// U8 *data = TargaUtility->getData(); -// S32 data_size = TargaUtility->getDataSize(); - -// std::string file_path = gDirUtilp->getDirName(filename); - -// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; -// //S32 name_len = output_file.length(); -// //strcpy(&output_file[name_len-3], "tga"); -// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ -// char md5_hash_string[33]; /* Flawfinder: ignore */ -// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ -// if (fOut) -// { -// if (fwrite(data, 1, data_size, fOut) != data_size) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fseek(fOut, 0, SEEK_SET); -// fclose(fOut); -// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ -// LLMD5 my_md5_hash(fOut); -// my_md5_hash.hex_digest(md5_hash_string); -// } - -// gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string)); -// } -// } - -// ++current_image_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } +// exported_image_info *info = (exported_image_info *)user_data; +// LLUUID image_id = info->image_id; +// U32 image_num = info->image_num; +// std::string filename = info->filename; +// delete info; + +// if (status < LLTS_OK) +// { +// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; +// } +// else +// { +// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ +// if (fIn) +// { +// LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C; +// LLPointer<LLImageTGA> TargaUtility = new LLImageTGA; + +// fseek(fIn, 0, SEEK_END); +// S32 length = ftell(fIn); +// fseek(fIn, 0, SEEK_SET); +// U8 *buffer = ImageUtility->allocateData(length); +// if (fread(buffer, 1, length, fIn) != length) +// { +// LL_WARNS("Messaging") << "Short read" << LL_ENDL; +// } +// fclose(fIn); +// LLFile::remove(filename); + +// // Convert to TGA +// LLPointer<LLImageRaw> image = new LLImageRaw(); + +// ImageUtility->updateData(); +// ImageUtility->decode(image, 100000.0f); + +// TargaUtility->encode(image); +// U8 *data = TargaUtility->getData(); +// S32 data_size = TargaUtility->getDataSize(); + +// std::string file_path = gDirUtilp->getDirName(filename); + +// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; +// //S32 name_len = output_file.length(); +// //strcpy(&output_file[name_len-3], "tga"); +// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ +// char md5_hash_string[33]; /* Flawfinder: ignore */ +// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ +// if (fOut) +// { +// if (fwrite(data, 1, data_size, fOut) != data_size) +// { +// LL_WARNS("Messaging") << "Short write" << LL_ENDL; +// } +// fseek(fOut, 0, SEEK_SET); +// fclose(fOut); +// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ +// LLMD5 my_md5_hash(fOut); +// my_md5_hash.hex_digest(md5_hash_string); +// } + +// gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string)); +// } +// } + +// ++current_image_count; +// if (current_image_count == exported_image_count && current_object_count == exported_object_count) +// { +// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; +// export_complete(); +// } +// else +// { +// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); +// } //} void process_derez_ack(LLMessageSystem*, void**) { - if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); + if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); } void process_places_reply(LLMessageSystem* msg, void** data) { - LLUUID query_id; + LLUUID query_id; - msg->getUUID("AgentData", "QueryID", query_id); - if (query_id.isNull()) - { - LLFloaterLandHoldings::processPlacesReply(msg, data); - } - else if(gAgent.isInGroup(query_id)) - { - LLPanelGroupLandMoney::processPlacesReply(msg, data); - } - else - { - LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL; - } + msg->getUUID("AgentData", "QueryID", query_id); + if (query_id.isNull()) + { + LLFloaterLandHoldings::processPlacesReply(msg, data); + } + else if(gAgent.isInGroup(query_id)) + { + LLPanelGroupLandMoney::processPlacesReply(msg, data); + } + else + { + LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL; + } } void send_sound_trigger(const LLUUID& sound_id, F32 gain) { - if (sound_id.isNull() || gAgent.getRegion() == NULL) - { - // disconnected agent or zero guids don't get sent (no sound) - return; - } + if (sound_id.isNull() || gAgent.getRegion() == NULL) + { + // disconnected agent or zero guids don't get sent (no sound) + return; + } - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SoundTrigger); - msg->nextBlockFast(_PREHASH_SoundData); - msg->addUUIDFast(_PREHASH_SoundID, sound_id); - // Client untrusted, ids set on sim - msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_SoundTrigger); + msg->nextBlockFast(_PREHASH_SoundData); + msg->addUUIDFast(_PREHASH_SoundID, sound_id); + // Client untrusted, ids set on sim + msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); - msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); + msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); - LLVector3 position = gAgent.getPositionAgent(); - msg->addVector3Fast(_PREHASH_Position, position); - msg->addF32Fast(_PREHASH_Gain, gain); + LLVector3 position = gAgent.getPositionAgent(); + msg->addVector3Fast(_PREHASH_Position, position); + msg->addF32Fast(_PREHASH_Gain, gain); - gAgent.sendMessage(); + gAgent.sendMessage(); } static LLSD sSavedGroupInvite; @@ -839,10 +839,10 @@ void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accep EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE; - if (accept_invite) - { - LLUIUsage::instance().logCommand("Group.Join"); - } + if (accept_invite) + { + LLUIUsage::instance().logCommand("Group.Join"); + } send_improved_im(group_id, std::string("name"), @@ -868,122 +868,122 @@ void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accep bool join_group_response(const LLSD& notification, const LLSD& response) { -// A bit of variable saving and restoring is used to deal with the case where your group list is full and you -// receive an invitation to another group. The data from that invitation is stored in the sSaved -// variables. If you then drop a group and click on the Join button the stored data is restored and used -// to join the group. - LLSD notification_adjusted = notification; - LLSD response_adjusted = response; - - std::string action = notification["name"]; - -// Storing all the information by group id allows for the rare case of being at your maximum -// group count and receiving more than one invitation. - std::string id = notification_adjusted["payload"]["group_id"].asString(); - - if ("JoinGroup" == action || "JoinGroupCanAfford" == action) - { - sSavedGroupInvite[id] = notification; - sSavedResponse[id] = response; - } - else if ("JoinedTooManyGroupsMember" == action) - { - S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == opt) // Join button pressed - { - notification_adjusted = sSavedGroupInvite[id]; - response_adjusted = sSavedResponse[id]; - } - } - - S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); - bool accept_invite = false; - - LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); - LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); - std::string name = notification_adjusted["payload"]["name"].asString(); - std::string message = notification_adjusted["payload"]["message"].asString(); - S32 fee = notification_adjusted["payload"]["fee"].asInteger(); - U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); - - if (option == 2 && !group_id.isNull()) - { - LLGroupActions::show(group_id); - LLSD args; - args["MESSAGE"] = message; - LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); - return false; - } - - if(option == 0 && !group_id.isNull()) - { - // check for promotion or demotion. - S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); - if(gAgent.isInGroup(group_id)) ++max_groups; - - if(gAgent.mGroups.size() < max_groups) - { - accept_invite = true; - } - else - { - LLSD args; - args["NAME"] = name; - LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification_adjusted["payload"]); - return false; - } - } - send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); - - sSavedGroupInvite[id] = LLSD::emptyMap(); - sSavedResponse[id] = LLSD::emptyMap(); - - return false; +// A bit of variable saving and restoring is used to deal with the case where your group list is full and you +// receive an invitation to another group. The data from that invitation is stored in the sSaved +// variables. If you then drop a group and click on the Join button the stored data is restored and used +// to join the group. + LLSD notification_adjusted = notification; + LLSD response_adjusted = response; + + std::string action = notification["name"]; + +// Storing all the information by group id allows for the rare case of being at your maximum +// group count and receiving more than one invitation. + std::string id = notification_adjusted["payload"]["group_id"].asString(); + + if ("JoinGroup" == action || "JoinGroupCanAfford" == action) + { + sSavedGroupInvite[id] = notification; + sSavedResponse[id] = response; + } + else if ("JoinedTooManyGroupsMember" == action) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == opt) // Join button pressed + { + notification_adjusted = sSavedGroupInvite[id]; + response_adjusted = sSavedResponse[id]; + } + } + + S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); + bool accept_invite = false; + + LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); + LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); + std::string name = notification_adjusted["payload"]["name"].asString(); + std::string message = notification_adjusted["payload"]["message"].asString(); + S32 fee = notification_adjusted["payload"]["fee"].asInteger(); + U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); + + if (option == 2 && !group_id.isNull()) + { + LLGroupActions::show(group_id); + LLSD args; + args["MESSAGE"] = message; + LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); + return false; + } + + if(option == 0 && !group_id.isNull()) + { + // check for promotion or demotion. + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); + if(gAgent.isInGroup(group_id)) ++max_groups; + + if(gAgent.mGroups.size() < max_groups) + { + accept_invite = true; + } + else + { + LLSD args; + args["NAME"] = name; + LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification_adjusted["payload"]); + return false; + } + } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); + + sSavedGroupInvite[id] = LLSD::emptyMap(); + sSavedResponse[id] = LLSD::emptyMap(); + + return false; } static void highlight_inventory_objects_in_panel(const std::vector<LLUUID>& items, LLInventoryPanel *inventory_panel) { - if (NULL == inventory_panel) return; - - for (std::vector<LLUUID>::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) - { - const LLUUID& item_id = (*item_iter); - if(!highlight_offered_object(item_id)) - { - continue; - } - - LLInventoryObject* item = gInventory.getObject(item_id); - llassert(item); - if (!item) { - continue; - } - - LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; - LLFolderView* fv = inventory_panel->getRootFolder(); - if (fv) - { - LLFolderViewItem* fv_item = inventory_panel->getItemByID(item_id); - if (fv_item) - { - LLFolderViewItem* fv_folder = fv_item->getParentFolder(); - if (fv_folder) - { - // Parent folders can be different in case of 2 consecutive drag and drop - // operations when the second one is started before the first one completes. - LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; - fv_folder->setOpen(TRUE); - if (fv_folder->isSelected()) - { - fv->changeSelection(fv_folder, FALSE); - } - } - fv->changeSelection(fv_item, TRUE); - } - } - } + if (NULL == inventory_panel) return; + + for (std::vector<LLUUID>::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + if(!highlight_offered_object(item_id)) + { + continue; + } + + LLInventoryObject* item = gInventory.getObject(item_id); + llassert(item); + if (!item) { + continue; + } + + LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; + LLFolderView* fv = inventory_panel->getRootFolder(); + if (fv) + { + LLFolderViewItem* fv_item = inventory_panel->getItemByID(item_id); + if (fv_item) + { + LLFolderViewItem* fv_folder = fv_item->getParentFolder(); + if (fv_folder) + { + // Parent folders can be different in case of 2 consecutive drag and drop + // operations when the second one is started before the first one completes. + LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; + fv_folder->setOpen(TRUE); + if (fv_folder->isSelected()) + { + fv->changeSelection(fv_folder, FALSE); + } + } + fv->changeSelection(fv_item, TRUE); + } + } + } } static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response); @@ -997,30 +997,30 @@ static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_ class LLOpenAgentOffer : public LLInventoryFetchItemsObserver { public: - LLOpenAgentOffer(const LLUUID& object_id, - const std::string& from_name) : - LLInventoryFetchItemsObserver(object_id), - mFromName(from_name) {} - /*virtual*/ void startFetch() - { - for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if (cat) - { - mComplete.push_back((*it)); - } - } - LLInventoryFetchItemsObserver::startFetch(); - } - /*virtual*/ void done() - { - open_inventory_offer(mComplete, mFromName); - gInventory.removeObserver(this); - delete this; - } + LLOpenAgentOffer(const LLUUID& object_id, + const std::string& from_name) : + LLInventoryFetchItemsObserver(object_id), + mFromName(from_name) {} + /*virtual*/ void startFetch() + { + for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if (cat) + { + mComplete.push_back((*it)); + } + } + LLInventoryFetchItemsObserver::startFetch(); + } + /*virtual*/ void done() + { + open_inventory_offer(mComplete, mFromName); + gInventory.removeObserver(this); + delete this; + } private: - std::string mFromName; + std::string mFromName; }; /** @@ -1032,117 +1032,117 @@ private: class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver { public: - LLViewerInventoryMoveFromWorldObserver() - : LLInventoryAddItemByAssetObserver() - { + LLViewerInventoryMoveFromWorldObserver() + : LLInventoryAddItemByAssetObserver() + { - } + } - void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } private: - /*virtual */void onAssetAdded(const LLUUID& asset_id) - { - // Store active Inventory panel. - if (LLInventoryPanel::getActiveInventoryPanel()) - { - mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); - } - - // Store selected items (without destination folder) - mSelectedItems.clear(); - if (LLInventoryPanel::getActiveInventoryPanel()) - { - std::set<LLFolderViewItem*> selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); - for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); - it != end_it; - ++it) - { - mSelectedItems.insert(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); - } - } - mSelectedItems.erase(mMoveIntoFolderID); - } - - /** - * Selects added inventory items watched by their Asset UUIDs if selection was not changed since - * all items were started to watch (dropped into a folder). - */ - void done() - { - LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get()); - - // if selection is not changed since watch started lets hightlight new items. - if (active_panel && !isSelectionChanged()) - { - LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; - active_panel->clearSelection(); - highlight_inventory_objects_in_panel(mAddedItems, active_panel); - } - } - - /** - * Returns true if selected inventory items were changed since moved inventory items were started to watch. - */ - bool isSelectionChanged() - { - LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); - - if (NULL == active_panel) - { - return true; - } - - // get selected items (without destination folder) - selected_items_t selected_items; - - std::set<LLFolderViewItem*> selection = active_panel->getRootFolder()->getSelectionList(); - for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); - it != end_it; - ++it) - { - selected_items.insert(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); - } - selected_items.erase(mMoveIntoFolderID); - - // compare stored & current sets of selected items - selected_items_t different_items; - std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), - selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); - - LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() - << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; - - return different_items.size() > 0; - } - - LLHandle<LLPanel> mActivePanel; - typedef std::set<LLUUID> selected_items_t; - selected_items_t mSelectedItems; - - /** - * UUID of FolderViewFolder into which watched items are moved. - * - * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). - * - * If mouse is moved out it set unselected and number of selected items is changed - * even if selected items in Inventory stay the same. - * So, it is used to update stored selection list. - * - * @see onAssetAdded() - * @see isSelectionChanged() - */ - LLUUID mMoveIntoFolderID; + /*virtual */void onAssetAdded(const LLUUID& asset_id) + { + // Store active Inventory panel. + if (LLInventoryPanel::getActiveInventoryPanel()) + { + mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); + } + + // Store selected items (without destination folder) + mSelectedItems.clear(); + if (LLInventoryPanel::getActiveInventoryPanel()) + { + std::set<LLFolderViewItem*> selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); + for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); + it != end_it; + ++it) + { + mSelectedItems.insert(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); + } + } + mSelectedItems.erase(mMoveIntoFolderID); + } + + /** + * Selects added inventory items watched by their Asset UUIDs if selection was not changed since + * all items were started to watch (dropped into a folder). + */ + void done() + { + LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get()); + + // if selection is not changed since watch started lets hightlight new items. + if (active_panel && !isSelectionChanged()) + { + LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; + active_panel->clearSelection(); + highlight_inventory_objects_in_panel(mAddedItems, active_panel); + } + } + + /** + * Returns true if selected inventory items were changed since moved inventory items were started to watch. + */ + bool isSelectionChanged() + { + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); + + if (NULL == active_panel) + { + return true; + } + + // get selected items (without destination folder) + selected_items_t selected_items; + + std::set<LLFolderViewItem*> selection = active_panel->getRootFolder()->getSelectionList(); + for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); + it != end_it; + ++it) + { + selected_items.insert(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); + } + selected_items.erase(mMoveIntoFolderID); + + // compare stored & current sets of selected items + selected_items_t different_items; + std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), + selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); + + LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() + << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; + + return different_items.size() > 0; + } + + LLHandle<LLPanel> mActivePanel; + typedef std::set<LLUUID> selected_items_t; + selected_items_t mSelectedItems; + + /** + * UUID of FolderViewFolder into which watched items are moved. + * + * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). + * + * If mouse is moved out it set unselected and number of selected items is changed + * even if selected items in Inventory stay the same. + * So, it is used to update stored selection list. + * + * @see onAssetAdded() + * @see isSelectionChanged() + */ + LLUUID mMoveIntoFolderID; }; LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) { - start_new_inventory_observer(); + start_new_inventory_observer(); - gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); - gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); + gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); + gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); } @@ -1156,124 +1156,124 @@ class LLViewerInventoryMoveObserver : public LLInventoryObserver { public: - LLViewerInventoryMoveObserver(const LLUUID& object_id) - : LLInventoryObserver() - , mObjectID(object_id) - { - if (LLInventoryPanel::getActiveInventoryPanel()) - { - mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); - } - } - - virtual ~LLViewerInventoryMoveObserver() {} - virtual void changed(U32 mask); - + LLViewerInventoryMoveObserver(const LLUUID& object_id) + : LLInventoryObserver() + , mObjectID(object_id) + { + if (LLInventoryPanel::getActiveInventoryPanel()) + { + mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); + } + } + + virtual ~LLViewerInventoryMoveObserver() {} + virtual void changed(U32 mask); + private: - LLUUID mObjectID; - LLHandle<LLPanel> mActivePanel; + LLUUID mObjectID; + LLHandle<LLPanel> mActivePanel; }; void LLViewerInventoryMoveObserver::changed(U32 mask) { - LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get()); - - if (NULL == active_panel) - { - gInventory.removeObserver(this); - return; - } - - if((mask & (LLInventoryObserver::STRUCTURE)) != 0) - { - const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); - - std::set<LLUUID>::const_iterator id_it = changed_items.begin(); - std::set<LLUUID>::const_iterator id_end = changed_items.end(); - for (;id_it != id_end; ++id_it) - { - if ((*id_it) == mObjectID) - { - active_panel->clearSelection(); - std::vector<LLUUID> items; - items.push_back(mObjectID); - highlight_inventory_objects_in_panel(items, active_panel); - active_panel->getRootFolder()->scrollToShowSelection(); - - gInventory.removeObserver(this); - break; - } - } - } + LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get()); + + if (NULL == active_panel) + { + gInventory.removeObserver(this); + return; + } + + if((mask & (LLInventoryObserver::STRUCTURE)) != 0) + { + const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); + + std::set<LLUUID>::const_iterator id_it = changed_items.begin(); + std::set<LLUUID>::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + if ((*id_it) == mObjectID) + { + active_panel->clearSelection(); + std::vector<LLUUID> items; + items.push_back(mObjectID); + highlight_inventory_objects_in_panel(items, active_panel); + active_panel->getRootFolder()->scrollToShowSelection(); + + gInventory.removeObserver(this); + break; + } + } + } } void set_dad_inbox_object(const LLUUID& object_id) { - LLViewerInventoryMoveObserver* move_observer = new LLViewerInventoryMoveObserver(object_id); - gInventory.addObserver(move_observer); + LLViewerInventoryMoveObserver* move_observer = new LLViewerInventoryMoveObserver(object_id); + gInventory.addObserver(move_observer); } -//unlike the FetchObserver for AgentOffer, we only make one +//unlike the FetchObserver for AgentOffer, we only make one //instance of the AddedObserver for TaskOffers -//and it never dies. We do this because we don't know the UUID of -//task offers until they are accepted, so we don't wouldn't +//and it never dies. We do this because we don't know the UUID of +//task offers until they are accepted, so we don't wouldn't //know what to watch for, so instead we just watch for all additions. class LLOpenTaskOffer : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() - { - uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) - { - added.push_back(*it); - } - for (uuid_vec_t::iterator it = added.begin(); it != added.end();) - { - const LLUUID& item_uuid = *it; - bool was_moved = false; - LLInventoryObject* added_object = gInventory.getObject(item_uuid); - if (added_object) - { - // cast to item to get Asset UUID - LLInventoryItem* added_item = dynamic_cast<LLInventoryItem*>(added_object); - if (added_item) - { - const LLUUID& asset_uuid = added_item->getAssetUUID(); - if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) - { - LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; - was_moved = true; - } - } - } - - if (was_moved) - { - it = added.erase(it); - } - else ++it; - } - - open_inventory_offer(added, ""); - } + /*virtual*/ void done() + { + uuid_vec_t added; + for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + { + added.push_back(*it); + } + for (uuid_vec_t::iterator it = added.begin(); it != added.end();) + { + const LLUUID& item_uuid = *it; + bool was_moved = false; + LLInventoryObject* added_object = gInventory.getObject(item_uuid); + if (added_object) + { + // cast to item to get Asset UUID + LLInventoryItem* added_item = dynamic_cast<LLInventoryItem*>(added_object); + if (added_item) + { + const LLUUID& asset_uuid = added_item->getAssetUUID(); + if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + was_moved = true; + } + } + } + + if (was_moved) + { + it = added.erase(it); + } + else ++it; + } + + open_inventory_offer(added, ""); + } }; class LLOpenTaskGroupOffer : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() - { - uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) - { - added.push_back(*it); - } - open_inventory_offer(added, "group_offer"); - gInventory.removeObserver(this); - delete this; - } + /*virtual*/ void done() + { + uuid_vec_t added; + for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + { + added.push_back(*it); + } + open_inventory_offer(added, "group_offer"); + gInventory.removeObserver(this); + delete this; + } }; //one global instance to bind them @@ -1281,267 +1281,267 @@ LLOpenTaskOffer* gNewInventoryObserver=NULL; class LLNewInventoryHintObserver : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() - { - LLFirstUse::newInventory(); - } + /*virtual*/ void done() + { + LLFirstUse::newInventory(); + } }; LLNewInventoryHintObserver* gNewInventoryHintObserver=NULL; void start_new_inventory_observer() { - if (!gNewInventoryObserver) //task offer observer - { - // Observer is deleted by gInventory - gNewInventoryObserver = new LLOpenTaskOffer; - gInventory.addObserver(gNewInventoryObserver); - } + if (!gNewInventoryObserver) //task offer observer + { + // Observer is deleted by gInventory + gNewInventoryObserver = new LLOpenTaskOffer; + gInventory.addObserver(gNewInventoryObserver); + } - if (!gInventoryMoveObserver) //inventory move from the world observer - { - // Observer is deleted by gInventory - gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; - gInventory.addObserver(gInventoryMoveObserver); - } + if (!gInventoryMoveObserver) //inventory move from the world observer + { + // Observer is deleted by gInventory + gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; + gInventory.addObserver(gInventoryMoveObserver); + } - if (!gNewInventoryHintObserver) - { - // Observer is deleted by gInventory - gNewInventoryHintObserver = new LLNewInventoryHintObserver(); - gInventory.addObserver(gNewInventoryHintObserver); - } + if (!gNewInventoryHintObserver) + { + // Observer is deleted by gInventory + gNewInventoryHintObserver = new LLNewInventoryHintObserver(); + gInventory.addObserver(gNewInventoryHintObserver); + } } class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver { - LOG_CLASS(LLDiscardAgentOffer); + LOG_CLASS(LLDiscardAgentOffer); public: - LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : - LLInventoryFetchItemsObserver(object_id), - mFolderID(folder_id), - mObjectID(object_id) {} - - virtual void done() - { - LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; - - // We're invoked from LLInventoryModel::notifyObservers(). - // If we now try to remove the inventory item, it will cause a nested - // notifyObservers() call, which won't work. - // So defer moving the item to trash until viewer gets idle (in a moment). - // Use removeObject() rather than removeItem() because at this level, - // the object could be either an item or a folder. - LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); - gInventory.removeObserver(this); - delete this; - } + LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : + LLInventoryFetchItemsObserver(object_id), + mFolderID(folder_id), + mObjectID(object_id) {} + + virtual void done() + { + LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; + + // We're invoked from LLInventoryModel::notifyObservers(). + // If we now try to remove the inventory item, it will cause a nested + // notifyObservers() call, which won't work. + // So defer moving the item to trash until viewer gets idle (in a moment). + // Use removeObject() rather than removeItem() because at this level, + // the object could be either an item or a folder. + LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); + gInventory.removeObserver(this); + delete this; + } protected: - LLUUID mFolderID; - LLUUID mObjectID; + LLUUID mFolderID; + LLUUID mObjectID; }; //Returns TRUE if we are OK, FALSE if we are throttled -//Set check_only true if you want to know the throttle status +//Set check_only true if you want to know the throttle status //without registering a hit bool check_offer_throttle(const std::string& from_name, bool check_only) { - static U32 throttle_count; - static bool throttle_logged; - LLChat chat; - std::string log_message; - - if (!gSavedSettings.getBOOL("ShowNewInventory")) - return false; - - if (check_only) - { - return gThrottleTimer.hasExpired(); - } - - if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) - { - LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; - throttle_count=1; - throttle_logged=false; - return true; - } - else //has not expired - { - LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; - // When downloading the initial inventory we get a lot of new items - // coming in and can't tell that from spam. - if (LLStartUp::getStartupState() >= STATE_STARTED - && throttle_count >= OFFER_THROTTLE_MAX_COUNT) - { - if (!throttle_logged) - { - // Use the name of the last item giver, who is probably the person - // spamming you. - - LLStringUtil::format_map_t arg; - std::string log_msg; - std::ostringstream time ; - time<<OFFER_THROTTLE_TIME; - - arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle(); - arg["TIME"] = time.str(); - - if (!from_name.empty()) - { - arg["FROM_NAME"] = from_name; - log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); - } - else - { - log_msg = LLTrans::getString("ItemsComingInTooFast", arg); - } - - //this is kinda important, so actually put it on screen - LLSD args; - args["MESSAGE"] = log_msg; - LLNotificationsUtil::add("SystemMessage", args); - - throttle_logged=true; - } - return false; - } - else - { - throttle_count++; - return true; - } - } -} - + static U32 throttle_count; + static bool throttle_logged; + LLChat chat; + std::string log_message; + + if (!gSavedSettings.getBOOL("ShowNewInventory")) + return false; + + if (check_only) + { + return gThrottleTimer.hasExpired(); + } + + if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) + { + LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; + throttle_count=1; + throttle_logged=false; + return true; + } + else //has not expired + { + LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; + // When downloading the initial inventory we get a lot of new items + // coming in and can't tell that from spam. + if (LLStartUp::getStartupState() >= STATE_STARTED + && throttle_count >= OFFER_THROTTLE_MAX_COUNT) + { + if (!throttle_logged) + { + // Use the name of the last item giver, who is probably the person + // spamming you. + + LLStringUtil::format_map_t arg; + std::string log_msg; + std::ostringstream time ; + time<<OFFER_THROTTLE_TIME; + + arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle(); + arg["TIME"] = time.str(); + + if (!from_name.empty()) + { + arg["FROM_NAME"] = from_name; + log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); + } + else + { + log_msg = LLTrans::getString("ItemsComingInTooFast", arg); + } + + //this is kinda important, so actually put it on screen + LLSD args; + args["MESSAGE"] = log_msg; + LLNotificationsUtil::add("SystemMessage", args); + + throttle_logged=true; + } + return false; + } + else + { + throttle_count++; + return true; + } + } +} + // Return "true" if we have a preview method for that asset type, "false" otherwise bool check_asset_previewable(const LLAssetType::EType asset_type) { - return (asset_type == LLAssetType::AT_NOTECARD) || - (asset_type == LLAssetType::AT_LANDMARK) || - (asset_type == LLAssetType::AT_TEXTURE) || - (asset_type == LLAssetType::AT_ANIMATION) || - (asset_type == LLAssetType::AT_SCRIPT) || - (asset_type == LLAssetType::AT_SOUND) || + return (asset_type == LLAssetType::AT_NOTECARD) || + (asset_type == LLAssetType::AT_LANDMARK) || + (asset_type == LLAssetType::AT_TEXTURE) || + (asset_type == LLAssetType::AT_ANIMATION) || + (asset_type == LLAssetType::AT_SCRIPT) || + (asset_type == LLAssetType::AT_SOUND) || (asset_type == LLAssetType::AT_MATERIAL); } void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) { - for (uuid_vec_t::const_iterator obj_iter = objects.begin(); - obj_iter != objects.end(); - ++obj_iter) - { - const LLUUID& obj_id = (*obj_iter); - if(!highlight_offered_object(obj_id)) - { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); - if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH)) - { - gInventory.checkTrashOverflow(); - } - continue; - } - - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) - { - LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; - continue; - } - - const LLAssetType::EType asset_type = obj->getActualType(); - - // Either an inventory item or a category. - const LLInventoryItem* item = dynamic_cast<const LLInventoryItem*>(obj); - if (item && check_asset_previewable(asset_type)) - { - //////////////////////////////////////////////////////////////////////////////// - // Special handling for various types. - if (check_offer_throttle(from_name, false)) // If we are throttled, don't display - { - LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL; - // If we opened this ourselves, focus it - const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; - switch(asset_type) - { - case LLAssetType::AT_NOTECARD: - { - LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus); - break; - } - case LLAssetType::AT_LANDMARK: - { - LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); - if ("inventory_handler" == from_name) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id", item->getUUID())); - } - else if("group_offer" == from_name) - { - // "group_offer" is passed by LLOpenTaskGroupOffer - // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done(). - LLSD args; - args["type"] = "landmark"; - args["id"] = obj_id; - LLFloaterSidePanelContainer::showPanel("places", args); - - continue; - } - else if(from_name.empty()) - { - std::string folder_name; - if (parent_folder) - { - // Localize folder name. - // *TODO: share this code? - folder_name = parent_folder->getName(); - if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType())) - { - LLTrans::findString(folder_name, "InvFolder " + folder_name); - } - } - else - { - folder_name = LLTrans::getString("Unknown"); - } - - // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. - LLSD args; - args["LANDMARK_NAME"] = item->getName(); - args["FOLDER_NAME"] = folder_name; - LLNotificationsUtil::add("LandmarkCreated", args); - } - } - break; - case LLAssetType::AT_TEXTURE: - { - LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus); - break; - } - case LLAssetType::AT_ANIMATION: - LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus); - break; - case LLAssetType::AT_SCRIPT: - LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus); - break; - case LLAssetType::AT_SOUND: - LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); - break; + for (uuid_vec_t::const_iterator obj_iter = objects.begin(); + obj_iter != objects.end(); + ++obj_iter) + { + const LLUUID& obj_id = (*obj_iter); + if(!highlight_offered_object(obj_id)) + { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH)) + { + gInventory.checkTrashOverflow(); + } + continue; + } + + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (!obj) + { + LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; + continue; + } + + const LLAssetType::EType asset_type = obj->getActualType(); + + // Either an inventory item or a category. + const LLInventoryItem* item = dynamic_cast<const LLInventoryItem*>(obj); + if (item && check_asset_previewable(asset_type)) + { + //////////////////////////////////////////////////////////////////////////////// + // Special handling for various types. + if (check_offer_throttle(from_name, false)) // If we are throttled, don't display + { + LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL; + // If we opened this ourselves, focus it + const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; + switch(asset_type) + { + case LLAssetType::AT_NOTECARD: + { + LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus); + break; + } + case LLAssetType::AT_LANDMARK: + { + LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); + if ("inventory_handler" == from_name) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id", item->getUUID())); + } + else if("group_offer" == from_name) + { + // "group_offer" is passed by LLOpenTaskGroupOffer + // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done(). + LLSD args; + args["type"] = "landmark"; + args["id"] = obj_id; + LLFloaterSidePanelContainer::showPanel("places", args); + + continue; + } + else if(from_name.empty()) + { + std::string folder_name; + if (parent_folder) + { + // Localize folder name. + // *TODO: share this code? + folder_name = parent_folder->getName(); + if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType())) + { + LLTrans::findString(folder_name, "InvFolder " + folder_name); + } + } + else + { + folder_name = LLTrans::getString("Unknown"); + } + + // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. + LLSD args; + args["LANDMARK_NAME"] = item->getName(); + args["FOLDER_NAME"] = folder_name; + LLNotificationsUtil::add("LandmarkCreated", args); + } + } + break; + case LLAssetType::AT_TEXTURE: + { + LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus); + break; + } + case LLAssetType::AT_ANIMATION: + LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus); + break; + case LLAssetType::AT_SCRIPT: + LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus); + break; + case LLAssetType::AT_SOUND: + LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); + break; case LLAssetType::AT_MATERIAL: // Explicitly do nothing -- we don't want to open the material editor every time you add a material to inventory break; - default: - LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL; - break; - } - } - } - - //////////////////////////////////////////////////////////////////////////////// + default: + LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL; + break; + } + } + } + + //////////////////////////////////////////////////////////////////////////////// static LLUICachedControl<bool> find_original_new_floater("FindOriginalOpenWindow", false); //show in a new single-folder window if(find_original_new_floater && !from_name.empty()) @@ -1578,34 +1578,34 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id, use_main_panel); } - } + } } bool highlight_offered_object(const LLUUID& obj_id) { - const LLInventoryObject* obj = gInventory.getObject(obj_id); - if(!obj) - { - LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; - return false; - } - - //////////////////////////////////////////////////////////////////////////////// - // Don't highlight if it's in certain "quiet" folders which don't need UI - // notification (e.g. trash, cof, lost-and-found). - if(!gAgent.getAFK()) - { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); - if (parent) - { - const LLFolderType::EType parent_type = parent->getPreferredType(); - if (LLViewerFolderType::lookupIsQuietType(parent_type)) - { - return false; - } - } - } - + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if(!obj) + { + LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; + return false; + } + + //////////////////////////////////////////////////////////////////////////////// + // Don't highlight if it's in certain "quiet" folders which don't need UI + // notification (e.g. trash, cof, lost-and-found). + if(!gAgent.getAFK()) + { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent) + { + const LLFolderType::EType parent_type = parent->getPreferredType(); + if (LLViewerFolderType::lookupIsQuietType(parent_type)) + { + return false; + } + } + } + if (obj->getType() == LLAssetType::AT_LANDMARK) { LLFloaterCreateLandmark *floater = LLFloaterReg::findTypedInstance<LLFloaterCreateLandmark>("add_landmark"); @@ -1617,43 +1617,43 @@ bool highlight_offered_object(const LLUUID& obj_id) } } - return true; + return true; } void inventory_offer_mute_callback(const LLUUID& blocked_id, - const std::string& full_name, - bool is_group) -{ - // *NOTE: blocks owner if the offer came from an object - LLMute::EType mute_type = is_group ? LLMute::GROUP : LLMute::AGENT; - - LLMute mute(blocked_id, full_name, mute_type); - if (LLMuteList::getInstance()->add(mute)) - { - LLPanelBlockedList::showPanelAndSelect(blocked_id); - } - - // purge the message queue of any previously queued inventory offers from the same source. - class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher - { - public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const - { - if(notification->getName() == "ObjectGiveItem" - || notification->getName() == "OwnObjectGiveItem" - || notification->getName() == "UserGiveItem") - { - return (notification->getPayload()["from_id"].asUUID() == blocked_id); - } - return FALSE; - } - private: - const LLUUID& blocked_id; - }; - - LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( - gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); + const std::string& full_name, + bool is_group) +{ + // *NOTE: blocks owner if the offer came from an object + LLMute::EType mute_type = is_group ? LLMute::GROUP : LLMute::AGENT; + + LLMute mute(blocked_id, full_name, mute_type); + if (LLMuteList::getInstance()->add(mute)) + { + LLPanelBlockedList::showPanelAndSelect(blocked_id); + } + + // purge the message queue of any previously queued inventory offers from the same source. + class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher + { + public: + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} + bool matches(const LLNotificationPtr notification) const + { + if(notification->getName() == "ObjectGiveItem" + || notification->getName() == "OwnObjectGiveItem" + || notification->getName() == "UserGiveItem") + { + return (notification->getPayload()["from_id"].asUUID() == blocked_id); + } + return FALSE; + } + private: + const LLUUID& blocked_id; + }; + + LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( + gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); } @@ -1678,602 +1678,602 @@ LLOfferInfo::LLOfferInfo() LLOfferInfo::LLOfferInfo(const LLSD& sd) { - mIM = (EInstantMessage)sd["im_type"].asInteger(); - mFromID = sd["from_id"].asUUID(); - mFromGroup = sd["from_group"].asBoolean(); - mFromObject = sd["from_object"].asBoolean(); - mTransactionID = sd["transaction_id"].asUUID(); - mFolderID = sd["folder_id"].asUUID(); - mObjectID = sd["object_id"].asUUID(); - mType = LLAssetType::lookup(sd["type"].asString().c_str()); - mFromName = sd["from_name"].asString(); - mDesc = sd["description"].asString(); - mHost = LLHost(sd["sender"].asString()); - mPersist = sd["persist"].asBoolean(); + mIM = (EInstantMessage)sd["im_type"].asInteger(); + mFromID = sd["from_id"].asUUID(); + mFromGroup = sd["from_group"].asBoolean(); + mFromObject = sd["from_object"].asBoolean(); + mTransactionID = sd["transaction_id"].asUUID(); + mFolderID = sd["folder_id"].asUUID(); + mObjectID = sd["object_id"].asUUID(); + mType = LLAssetType::lookup(sd["type"].asString().c_str()); + mFromName = sd["from_name"].asString(); + mDesc = sd["description"].asString(); + mHost = LLHost(sd["sender"].asString()); + mPersist = sd["persist"].asBoolean(); } LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) { - mIM = info.mIM; - mFromID = info.mFromID; - mFromGroup = info.mFromGroup; - mFromObject = info.mFromObject; - mTransactionID = info.mTransactionID; - mFolderID = info.mFolderID; - mObjectID = info.mObjectID; - mType = info.mType; - mFromName = info.mFromName; - mDesc = info.mDesc; - mHost = info.mHost; - mPersist = info.mPersist; + mIM = info.mIM; + mFromID = info.mFromID; + mFromGroup = info.mFromGroup; + mFromObject = info.mFromObject; + mTransactionID = info.mTransactionID; + mFolderID = info.mFolderID; + mObjectID = info.mObjectID; + mType = info.mType; + mFromName = info.mFromName; + mDesc = info.mDesc; + mHost = info.mHost; + mPersist = info.mPersist; } LLSD LLOfferInfo::asLLSD() { - LLSD sd; + LLSD sd; sd["responder_type"] = mResponderType; - sd["im_type"] = mIM; - sd["from_id"] = mFromID; - sd["from_group"] = mFromGroup; - sd["from_object"] = mFromObject; - sd["transaction_id"] = mTransactionID; - sd["folder_id"] = mFolderID; - sd["object_id"] = mObjectID; - sd["type"] = LLAssetType::lookup(mType); - sd["from_name"] = mFromName; - sd["description"] = mDesc; - sd["sender"] = mHost.getIPandPort(); - sd["persist"] = mPersist; - return sd; + sd["im_type"] = mIM; + sd["from_id"] = mFromID; + sd["from_group"] = mFromGroup; + sd["from_object"] = mFromObject; + sd["transaction_id"] = mTransactionID; + sd["folder_id"] = mFolderID; + sd["object_id"] = mObjectID; + sd["type"] = LLAssetType::lookup(mType); + sd["from_name"] = mFromName; + sd["description"] = mDesc; + sd["sender"] = mHost.getIPandPort(); + sd["persist"] = mPersist; + return sd; } void LLOfferInfo::fromLLSD(const LLSD& params) { - *this = params; + *this = params; } void LLOfferInfo::sendReceiveResponse(bool accept, const LLUUID &destination_folder_id) { - if(IM_INVENTORY_OFFERED == mIM) - { - // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); - } - - if (mTransactionID.isNull()) - { - // Not provided, message won't work - return; - } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, mTransactionID); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, ""); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - - // ACCEPT. The math for the dialog works, because the accept - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 1 greater than the offer integer value. - // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, - // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - // Decline for inventory_offered, task_inventory_offer or - // group_notice_inventory is 2 greater than the offer integer value. - - EInstantMessage im = mIM; - if (mIM == IM_GROUP_NOTICE_REQUESTED) - { - // Request has no responder dialogs - im = IM_GROUP_NOTICE; - } - - if (accept) - { - msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(destination_folder_id.mData), - sizeof(destination_folder_id.mData)); - } - else - { - msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 2)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); - } - // send the message - msg->sendReliable(mHost); - - // transaction id is usable only once - // Note: a bit of a hack, clicking group notice attachment will not close notice - // so we reset no longer usable transaction id to know not to send message again - // Once capabilities for responses will be implemented LLOfferInfo will have to - // remember that it already responded in another way and ignore IOR_DECLINE - mTransactionID.setNull(); + if(IM_INVENTORY_OFFERED == mIM) + { + // add buddy to recent people list + LLRecentPeople::instance().add(mFromID); + } + + if (mTransactionID.isNull()) + { + // Not provided, message won't work + return; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ImprovedInstantMessage); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_MessageBlock); + msg->addBOOLFast(_PREHASH_FromGroup, FALSE); + msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); + msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); + msg->addUUIDFast(_PREHASH_ID, mTransactionID); + msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary + std::string name; + LLAgentUI::buildFullname(name); + msg->addStringFast(_PREHASH_FromAgentName, name); + msg->addStringFast(_PREHASH_Message, ""); + msg->addU32Fast(_PREHASH_ParentEstateID, 0); + msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); + msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); + + // ACCEPT. The math for the dialog works, because the accept + // for inventory_offered, task_inventory_offer or + // group_notice_inventory is 1 greater than the offer integer value. + // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, + // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED + // Decline for inventory_offered, task_inventory_offer or + // group_notice_inventory is 2 greater than the offer integer value. + + EInstantMessage im = mIM; + if (mIM == IM_GROUP_NOTICE_REQUESTED) + { + // Request has no responder dialogs + im = IM_GROUP_NOTICE; + } + + if (accept) + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 1)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(destination_folder_id.mData), + sizeof(destination_folder_id.mData)); + } + else + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 2)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); + } + // send the message + msg->sendReliable(mHost); + + // transaction id is usable only once + // Note: a bit of a hack, clicking group notice attachment will not close notice + // so we reset no longer usable transaction id to know not to send message again + // Once capabilities for responses will be implemented LLOfferInfo will have to + // remember that it already responded in another way and ignore IOR_DECLINE + mTransactionID.setNull(); } void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response) { - initRespondFunctionMap(); + initRespondFunctionMap(); - const std::string name = notification["name"].asString(); - if(mRespondFunctions.find(name) == mRespondFunctions.end()) - { - LL_WARNS() << "Unexpected notification name : " << name << LL_ENDL; - llassert(!"Unexpected notification name"); - return; - } + const std::string name = notification["name"].asString(); + if(mRespondFunctions.find(name) == mRespondFunctions.end()) + { + LL_WARNS() << "Unexpected notification name : " << name << LL_ENDL; + llassert(!"Unexpected notification name"); + return; + } - mRespondFunctions[name](notification, response); + mRespondFunctions[name](notification, response); } bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response) { - LLChat chat; - std::string log_message; - S32 button = LLNotificationsUtil::getSelectedOption(notification, response); - - LLInventoryObserver* opener = NULL; - LLViewerInventoryCategory* catp = NULL; - catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); - LLViewerInventoryItem* itemp = NULL; - if(!catp) - { - itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); - } - - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - // For muting, we need to add the mute, then decline the offer. - // This must be done here because: - // * callback may be called immediately, - // * adding the mute sends a message, - // * we can't build two messages at once. - if (IOR_MUTE == button) // Block - { - if (notification_ptr != NULL) - { - if (mFromGroup) - { - gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); - } - else - { - LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); - } - } - } - - std::string from_string; // Used in the pop-up. - std::string chatHistory_string; // Used in chat history. - - // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: - from_string = chatHistory_string = mFromName; - - // accept goes to proper folder, decline gets accepted to trash, muted gets declined - bool accept_to_trash = true; - - LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); - - switch(button) - { - case IOR_SHOW: - // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID - << LL_ENDL; - switch (mIM) - { - case IM_INVENTORY_OFFERED: - { - // This is an offer from an agent. In this case, the back - // end has already copied the items into your inventory, - // so we can fetch it out of our inventory. - if (gSavedSettings.getBOOL("ShowOfferedInventory")) - { - LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); - open_agent_offer->startFetch(); - if(catp || (itemp && itemp->isFinished())) - { - open_agent_offer->done(); - } - else - { - opener = open_agent_offer; - } - } - } - break; - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - opener = new LLOpenTaskGroupOffer; - sendReceiveResponse(true, mFolderID); - break; - case IM_TASK_INVENTORY_OFFERED: - // This is an offer from a task or group. - // We don't use a new instance of an opener - // We instead use the singular observer gOpenTaskOffer - // Since it already exists, we don't need to actually do anything - break; - default: - LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; - break; - } - - if (modified_form != NULL) - { - modified_form->setElementEnabled("Show", false); - } - break; - // end switch (mIM) - - case IOR_ACCEPT: - //don't spam them if they are getting flooded - if (check_offer_throttle(mFromName, true)) - { - log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - - break; - - case IOR_MUTE: - if (modified_form != NULL) - { - modified_form->setElementEnabled("Mute", false); - } - accept_to_trash = false; // for notices, but IOR_MUTE normally doesn't happen for notices - // MUTE falls through to decline - case IOR_DECLINE: - { - { - LLStringUtil::format_map_t log_message_args; - log_message_args["DESC"] = mDesc; - log_message_args["NAME"] = mFromName; - log_message = LLTrans::getString("InvOfferDecline", log_message_args); - } - chat.mText = log_message; - if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::isLinden(mFromName) ) // muting for SL-42269 - { - chat.mMuted = TRUE; - accept_to_trash = false; // will send decline message - } - - // *NOTE dzaporozhan - // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 - // LLFloaterChat::addChatHistory(chat); - - if (mObjectID.notNull()) //make sure we can discard - { - LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->startFetch(); - if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) - { - discard_agent_offer->done(); - } - else - { - opener = discard_agent_offer; - } - } - else if (mIM == IM_GROUP_NOTICE) - { - // group notice needs to request object to trash so that user will see it later - // Note: muted agent offers go to trash, not sure if we should do same for notices - LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - sendReceiveResponse(accept_to_trash, trash); - } - - if (modified_form != NULL) - { - modified_form->setElementEnabled("Show", false); - modified_form->setElementEnabled("Discard", false); - } - - break; - } - default: - // close button probably - // In case of agent offers item has already been fetched and is in your inventory, we simply won't highlight it - // OR delete it if the notification gets killed, since we don't want that to be a vector for - // losing inventory offers. - if (mIM == IM_GROUP_NOTICE) - { - LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - sendReceiveResponse(true, trash); - } - break; - } - - if(opener) - { - gInventory.addObserver(opener); - } - - if(!mPersist) - { - delete this; - } - - return false; + LLChat chat; + std::string log_message; + S32 button = LLNotificationsUtil::getSelectedOption(notification, response); + + LLInventoryObserver* opener = NULL; + LLViewerInventoryCategory* catp = NULL; + catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); + LLViewerInventoryItem* itemp = NULL; + if(!catp) + { + itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); + } + + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + // For muting, we need to add the mute, then decline the offer. + // This must be done here because: + // * callback may be called immediately, + // * adding the mute sends a message, + // * we can't build two messages at once. + if (IOR_MUTE == button) // Block + { + if (notification_ptr != NULL) + { + if (mFromGroup) + { + gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); + } + } + } + + std::string from_string; // Used in the pop-up. + std::string chatHistory_string; // Used in chat history. + + // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: + from_string = chatHistory_string = mFromName; + + // accept goes to proper folder, decline gets accepted to trash, muted gets declined + bool accept_to_trash = true; + + LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); + + switch(button) + { + case IOR_SHOW: + // we will want to open this item when it comes back. + LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID + << LL_ENDL; + switch (mIM) + { + case IM_INVENTORY_OFFERED: + { + // This is an offer from an agent. In this case, the back + // end has already copied the items into your inventory, + // so we can fetch it out of our inventory. + if (gSavedSettings.getBOOL("ShowOfferedInventory")) + { + LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); + open_agent_offer->startFetch(); + if(catp || (itemp && itemp->isFinished())) + { + open_agent_offer->done(); + } + else + { + opener = open_agent_offer; + } + } + } + break; + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: + opener = new LLOpenTaskGroupOffer; + sendReceiveResponse(true, mFolderID); + break; + case IM_TASK_INVENTORY_OFFERED: + // This is an offer from a task or group. + // We don't use a new instance of an opener + // We instead use the singular observer gOpenTaskOffer + // Since it already exists, we don't need to actually do anything + break; + default: + LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; + break; + } + + if (modified_form != NULL) + { + modified_form->setElementEnabled("Show", false); + } + break; + // end switch (mIM) + + case IOR_ACCEPT: + //don't spam them if they are getting flooded + if (check_offer_throttle(mFromName, true)) + { + log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + + break; + + case IOR_MUTE: + if (modified_form != NULL) + { + modified_form->setElementEnabled("Mute", false); + } + accept_to_trash = false; // for notices, but IOR_MUTE normally doesn't happen for notices + // MUTE falls through to decline + case IOR_DECLINE: + { + { + LLStringUtil::format_map_t log_message_args; + log_message_args["DESC"] = mDesc; + log_message_args["NAME"] = mFromName; + log_message = LLTrans::getString("InvOfferDecline", log_message_args); + } + chat.mText = log_message; + if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::isLinden(mFromName) ) // muting for SL-42269 + { + chat.mMuted = TRUE; + accept_to_trash = false; // will send decline message + } + + // *NOTE dzaporozhan + // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 + // LLFloaterChat::addChatHistory(chat); + + if (mObjectID.notNull()) //make sure we can discard + { + LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); + discard_agent_offer->startFetch(); + if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) + { + discard_agent_offer->done(); + } + else + { + opener = discard_agent_offer; + } + } + else if (mIM == IM_GROUP_NOTICE) + { + // group notice needs to request object to trash so that user will see it later + // Note: muted agent offers go to trash, not sure if we should do same for notices + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(accept_to_trash, trash); + } + + if (modified_form != NULL) + { + modified_form->setElementEnabled("Show", false); + modified_form->setElementEnabled("Discard", false); + } + + break; + } + default: + // close button probably + // In case of agent offers item has already been fetched and is in your inventory, we simply won't highlight it + // OR delete it if the notification gets killed, since we don't want that to be a vector for + // losing inventory offers. + if (mIM == IM_GROUP_NOTICE) + { + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(true, trash); + } + break; + } + + if(opener) + { + gInventory.addObserver(opener); + } + + if(!mPersist) + { + delete this; + } + + return false; } bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response) { - LLChat chat; - std::string log_message; - S32 button = LLNotification::getSelectedOption(notification, response); - - // For muting, we need to add the mute, then decline the offer. - // This must be done here because: - // * callback may be called immediately, - // * adding the mute sends a message, - // * we can't build two messages at once. - if (2 == button) - { - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - llassert(notification_ptr != NULL); - if (notification_ptr != NULL) - { - if (mFromGroup) - { - gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); - } - else - { - LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); - } - } - } - - std::string from_string; // Used in the pop-up. - std::string chatHistory_string; // Used in chat history. - - if (mFromObject == TRUE) - { - if (mFromGroup) - { - std::string group_name; - if (gCacheName->getGroupName(mFromID, group_name)) - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" - + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") - + " "+ "'" + group_name + "'"; - - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") - + " " + group_name + "'"; - } - else - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" - + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); - } - } - else - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(mFromID, &av_name)) - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName - + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + av_name.getUserName(); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + av_name.getUserName(); - } - else - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") - + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - } - } - } - else - { - from_string = chatHistory_string = mFromName; - } - - LLUUID destination; - bool accept = true; - - // If user accepted, accept to proper folder, if user discarded, accept to trash. - switch(button) - { - case IOR_ACCEPT: - destination = mFolderID; - //don't spam user if flooded - if (check_offer_throttle(mFromName, true)) - { - log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - break; - case IOR_MUTE: - // MUTE falls through to decline - accept = false; - case IOR_DECLINE: - default: - // close button probably (or any of the fall-throughs from above) - destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (accept && LLMuteList::getInstance()->isMuted(mFromID, mFromName)) - { - // Note: muted offers are usually declined automatically, - // but user can mute object after receiving message - accept = false; - } - break; - } - - sendReceiveResponse(accept, destination); - - if(!mPersist) - { - delete this; - } - return false; + LLChat chat; + std::string log_message; + S32 button = LLNotification::getSelectedOption(notification, response); + + // For muting, we need to add the mute, then decline the offer. + // This must be done here because: + // * callback may be called immediately, + // * adding the mute sends a message, + // * we can't build two messages at once. + if (2 == button) + { + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + llassert(notification_ptr != NULL); + if (notification_ptr != NULL) + { + if (mFromGroup) + { + gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); + } + } + } + + std::string from_string; // Used in the pop-up. + std::string chatHistory_string; // Used in chat history. + + if (mFromObject == TRUE) + { + if (mFromGroup) + { + std::string group_name; + if (gCacheName->getGroupName(mFromID, group_name)) + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" + + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") + + " "+ "'" + group_name + "'"; + + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") + + " " + group_name + "'"; + } + else + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" + + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); + } + } + else + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(mFromID, &av_name)) + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName + + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + av_name.getUserName(); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + av_name.getUserName(); + } + else + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") + + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); + } + } + } + else + { + from_string = chatHistory_string = mFromName; + } + + LLUUID destination; + bool accept = true; + + // If user accepted, accept to proper folder, if user discarded, accept to trash. + switch(button) + { + case IOR_ACCEPT: + destination = mFolderID; + //don't spam user if flooded + if (check_offer_throttle(mFromName, true)) + { + log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + break; + case IOR_MUTE: + // MUTE falls through to decline + accept = false; + case IOR_DECLINE: + default: + // close button probably (or any of the fall-throughs from above) + destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (accept && LLMuteList::getInstance()->isMuted(mFromID, mFromName)) + { + // Note: muted offers are usually declined automatically, + // but user can mute object after receiving message + accept = false; + } + break; + } + + sendReceiveResponse(accept, destination); + + if(!mPersist) + { + delete this; + } + return false; } std::string LLOfferInfo::getSanitizedDescription() { - // currently we get description from server as: 'Object' ( Location ) - // object name shouldn't be shown as a hyperlink - std::string description = mDesc; + // currently we get description from server as: 'Object' ( Location ) + // object name shouldn't be shown as a hyperlink + std::string description = mDesc; - std::size_t start = mDesc.find_first_of("'"); - std::size_t end = mDesc.find_last_of("'"); - if ((start != std::string::npos) && (end != std::string::npos)) - { - description.insert(start, "<nolink>"); - description.insert(end + 8, "</nolink>"); - } - return description; + std::size_t start = mDesc.find_first_of("'"); + std::size_t end = mDesc.find_last_of("'"); + if ((start != std::string::npos) && (end != std::string::npos)) + { + description.insert(start, "<nolink>"); + description.insert(end + 8, "</nolink>"); + } + return description; } void LLOfferInfo::initRespondFunctionMap() { - if(mRespondFunctions.empty()) - { - mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); - mRespondFunctions["OwnObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); - mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2); - } + if(mRespondFunctions.empty()) + { + mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); + mRespondFunctions["OwnObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); + mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2); + } } bool lure_callback(const LLSD& notification, const LLSD& response) { - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); - BOOL godlike = notification["payload"]["godlike"].asBoolean(); - - switch(option) - { - case 0: - { - // accept - gAgent.teleportViaLure(lure_id, godlike); - } - break; - case 1: - default: - // decline - send_simple_im(from_id, - LLStringUtil::null, - IM_LURE_DECLINED, - lure_id); - break; - } - - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - if (notification_ptr) - { - LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); - modified_form->setElementEnabled("Teleport", false); - modified_form->setElementEnabled("Cancel", false); - notification_ptr->updateForm(modified_form); - notification_ptr->repost(); - } - - return false; + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); + + switch(option) + { + case 0: + { + // accept + gAgent.teleportViaLure(lure_id, godlike); + } + break; + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); + break; + } + + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + if (notification_ptr) + { + LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + modified_form->setElementEnabled("Teleport", false); + modified_form->setElementEnabled("Cancel", false); + notification_ptr->updateForm(modified_form); + notification_ptr->repost(); + } + + return false; } static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); bool mature_lure_callback(const LLSD& notification, const LLSD& response) { - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); - BOOL godlike = notification["payload"]["godlike"].asBoolean(); - U8 region_access = static_cast<U8>(notification["payload"]["region_maturity"].asInteger()); - - switch(option) - { - case 0: - { - // accept - gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(region_access)); - gAgent.setMaturityRatingChangeDuringTeleport(region_access); - gAgent.teleportViaLure(lure_id, godlike); - } - break; - case 1: - default: - // decline - send_simple_im(from_id, - LLStringUtil::null, - IM_LURE_DECLINED, - lure_id); - break; - } - return false; + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); + U8 region_access = static_cast<U8>(notification["payload"]["region_maturity"].asInteger()); + + switch(option) + { + case 0: + { + // accept + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(region_access)); + gAgent.setMaturityRatingChangeDuringTeleport(region_access); + gAgent.teleportViaLure(lure_id, godlike); + } + break; + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); + break; + } + return false; } static LLNotificationFunctorRegistration mature_lure_callback_reg("TeleportOffered_MaturityExceeded", mature_lure_callback); bool goto_url_callback(const LLSD& notification, const LLSD& response) { - std::string url = notification["payload"]["url"].asString(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(1 == option) - { - LLWeb::loadURL(url); - } - return false; + std::string url = notification["payload"]["url"].asString(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(1 == option) + { + LLWeb::loadURL(url); + } + return false; } static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]); + } + return false; } static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback); class LLPostponedServerObjectNotification: public LLPostponedNotification { protected: - /* virtual */ - void modifyNotificationParams() - { - LLSD payload = mParams.payload; - mParams.payload = payload; - } + /* virtual */ + void modifyNotificationParams() + { + LLSD payload = mParams.payload; + mParams.payload = payload; + } }; void process_improved_im(LLMessageSystem *msg, void **user_data) @@ -2303,7 +2303,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, d); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); - //msg->getData("MessageBlock", "Count", &count); + //msg->getData("MessageBlock", "Count", &count); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, agentName); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); @@ -2333,129 +2333,129 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) void send_do_not_disturb_message (LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) { - if (gAgent.isDoNotDisturb()) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response = gSavedPerAccountSettings.getString("DoNotDisturbModeResponse"); - pack_instant_message( - msg, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - response, - IM_ONLINE, - IM_DO_NOT_DISTURB_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - } + if (gAgent.isDoNotDisturb()) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response = gSavedPerAccountSettings.getString("DoNotDisturbModeResponse"); + pack_instant_message( + msg, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + from_id, + my_name, + response, + IM_ONLINE, + IM_DO_NOT_DISTURB_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + } } bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLUUID fid; - LLUUID from_id; - LLMessageSystem* msg = gMessageSystem; - switch(option) - { - case 0: - // accept - msg->newMessageFast(_PREHASH_AcceptCallingCard); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - break; - case 1: - // decline - msg->newMessageFast(_PREHASH_DeclineCallingCard); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - send_do_not_disturb_message(msg, notification["payload"]["source_id"].asUUID()); - break; - default: - // close button probably, possibly timed out - break; - } - - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLUUID fid; + LLUUID from_id; + LLMessageSystem* msg = gMessageSystem; + switch(option) + { + case 0: + // accept + msg->newMessageFast(_PREHASH_AcceptCallingCard); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); + fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + break; + case 1: + // decline + msg->newMessageFast(_PREHASH_DeclineCallingCard); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + send_do_not_disturb_message(msg, notification["payload"]["source_id"].asUUID()); + break; + default: + // close button probably, possibly timed out + break; + } + + return false; } static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); void process_offer_callingcard(LLMessageSystem* msg, void**) { - // someone has offered to form a friendship - LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL; - - LLUUID source_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); - LLUUID tid; - msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid); - - LLSD payload; - payload["transaction_id"] = tid; - payload["source_id"] = source_id; - payload["sender"] = msg->getSender().getIPandPort(); - - LLViewerObject* source = gObjectList.findObject(source_id); - LLSD args; - std::string source_name; - if(source && source->isAvatar()) - { - LLNameValue* nvfirst = source->getNVPair("FirstName"); - LLNameValue* nvlast = source->getNVPair("LastName"); - if (nvfirst && nvlast) - { - source_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - } - - if(!source_name.empty()) - { - if (gAgent.isDoNotDisturb() - || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) - { - // automatically decline offer - LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1); - } - else - { - args["NAME"] = source_name; - LLNotificationsUtil::add("OfferCallingCard", args, payload); - } - } - else - { - LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL; - } + // someone has offered to form a friendship + LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL; + + LLUUID source_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); + LLUUID tid; + msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid); + + LLSD payload; + payload["transaction_id"] = tid; + payload["source_id"] = source_id; + payload["sender"] = msg->getSender().getIPandPort(); + + LLViewerObject* source = gObjectList.findObject(source_id); + LLSD args; + std::string source_name; + if(source && source->isAvatar()) + { + LLNameValue* nvfirst = source->getNVPair("FirstName"); + LLNameValue* nvlast = source->getNVPair("LastName"); + if (nvfirst && nvlast) + { + source_name = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + } + } + + if(!source_name.empty()) + { + if (gAgent.isDoNotDisturb() + || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) + { + // automatically decline offer + LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1); + } + else + { + args["NAME"] = source_name; + LLNotificationsUtil::add("OfferCallingCard", args, payload); + } + } + else + { + LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL; + } } void process_accept_callingcard(LLMessageSystem* msg, void**) { - LLNotificationsUtil::add("CallingCardAccepted"); + LLNotificationsUtil::add("CallingCardAccepted"); } void process_decline_callingcard(LLMessageSystem* msg, void**) { - LLNotificationsUtil::add("CallingCardDeclined"); + LLNotificationsUtil::add("CallingCardDeclined"); } void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std::string expectLang, std::string translation, const std::string detected_language) { - // filter out non-interesting responses + // filter out non-interesting responses if (!translation.empty() && ((detected_language.empty()) || (expectLang != detected_language)) && (LLStringUtil::compareInsensitive(translation, originalMsg) != 0)) @@ -2463,7 +2463,7 @@ void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std: chat.mText += " (" + LLTranslate::removeNoTranslateTags(translation) + ")"; } - LLTranslate::instance().logSuccess(1); + LLTranslate::instance().logSuccess(1); LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs); } @@ -2473,424 +2473,424 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages chat.mText += " (" + msg + ")"; - LLTranslate::instance().logFailure(1); + LLTranslate::instance().logFailure(1); LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs); } void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { - if (gNonInteractive) - { - return; - } - LLChat chat; - std::string mesg; - std::string from_name; - U8 source_temp; - U8 type_temp; - U8 audible_temp; - LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f); - LLUUID from_id; - LLUUID owner_id; - LLViewerObject* chatter; - - msg->getString("ChatData", "FromName", from_name); - - msg->getUUID("ChatData", "SourceID", from_id); - chat.mFromID = from_id; - - // Object owner for objects - msg->getUUID("ChatData", "OwnerID", owner_id); - - msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); - chat.mSourceType = (EChatSourceType)source_temp; - - msg->getU8("ChatData", "ChatType", type_temp); - chat.mChatType = (EChatType)type_temp; - - msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp); - chat.mAudible = (EChatAudible)audible_temp; - - chat.mTime = LLFrameTimer::getElapsedSeconds(); - - // IDEVO Correct for new-style "Resident" names - if (chat.mSourceType == CHAT_SOURCE_AGENT) - { - // I don't know if it's OK to change this here, if - // anything downstream does lookups by name, for instance - - LLAvatarName av_name; - if (LLAvatarNameCache::get(from_id, &av_name)) - { - chat.mFromName = av_name.getCompleteName(); - } - else - { - chat.mFromName = LLCacheName::cleanFullName(from_name); - } - } - else - { - // make sure that we don't have an empty or all-whitespace name - LLStringUtil::trim(from_name); - if (from_name.empty()) - { - from_name = LLTrans::getString("Unnamed"); - } - chat.mFromName = from_name; - } - - BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - - BOOL is_muted = FALSE; - BOOL is_linden = FALSE; - is_muted = LLMuteList::getInstance()->isMuted( - from_id, - from_name, - LLMute::flagTextChat) - || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat); - is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && - LLMuteList::isLinden(from_name); - - if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) - { - return; - } - - BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); - chatter = gObjectList.findObject(from_id); - if (chatter) - { - chat.mPosAgent = chatter->getPositionAgent(); - - // Make swirly things only for talking objects. (not script debug messages, though) - if (chat.mSourceType == CHAT_SOURCE_OBJECT - && chat.mChatType != CHAT_TYPE_DEBUG_MSG - && gSavedSettings.getBOOL("EffectScriptChatParticles") ) - { - LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); - psc->setSourceObject(chatter); - psc->setColor(color); - //We set the particles to be owned by the object's owner, - //just in case they should be muted by the mute list - psc->setOwnerUUID(owner_id); - LLViewerPartSim::getInstance()->addPartSource(psc); - } - - // record last audible utterance - if (is_audible - && (is_linden || (!is_muted && !is_do_not_disturb))) - { - if (chat.mChatType != CHAT_TYPE_START - && chat.mChatType != CHAT_TYPE_STOP) - { - gAgent.heardChat(chat.mFromID); - } - } - } - - if (is_audible) - { - //BOOL visible_in_chat_bubble = FALSE; - - color.setVec(1.f,1.f,1.f,1.f); - msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); - - BOOL ircstyle = FALSE; - - // Look for IRC-style emotes here so chatbubbles work - std::string prefix = mesg.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - ircstyle = TRUE; - } - chat.mText = mesg; - - // Look for the start of typing so we can put "..." in the bubbles. - if (CHAT_TYPE_START == chat.mChatType) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE); - - // Might not have the avatar constructed yet, eg on login. - if (chatter && chatter->isAvatar()) - { - ((LLVOAvatar*)chatter)->startTyping(); - } - return; - } - else if (CHAT_TYPE_STOP == chat.mChatType) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - - // Might not have the avatar constructed yet, eg on login. - if (chatter && chatter->isAvatar()) - { - ((LLVOAvatar*)chatter)->stopTyping(); - } - return; - } - - // Look for IRC-style emotes - if (ircstyle) - { - // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656 - chat.mChatStyle = CHAT_STYLE_IRC; - - // Do nothing, ircstyle is fixed above for chat bubbles - } - else - { - chat.mText = ""; - switch(chat.mChatType) - { - case CHAT_TYPE_WHISPER: - chat.mText = LLTrans::getString("whisper") + " "; - break; - case CHAT_TYPE_DEBUG_MSG: - case CHAT_TYPE_OWNER: - case CHAT_TYPE_NORMAL: - case CHAT_TYPE_DIRECT: - break; - case CHAT_TYPE_SHOUT: - chat.mText = LLTrans::getString("shout") + " "; - break; - case CHAT_TYPE_START: - case CHAT_TYPE_STOP: - LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL; - break; - default: - LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; - break; - } - - chat.mText += mesg; - } - - // We have a real utterance now, so can stop showing "..." and proceed. - if (chatter && chatter->isAvatar()) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - ((LLVOAvatar*)chatter)->stopTyping(); - - if (!is_muted && !is_do_not_disturb) - { - //visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); - std::string formated_msg = ""; - LLViewerChat::formatChatMsg(chat, formated_msg); - LLChat chat_bubble = chat; - chat_bubble.mText = formated_msg; - ((LLVOAvatar*)chatter)->addChat(chat_bubble); - } - } - - if (chatter) - { - chat.mPosAgent = chatter->getPositionAgent(); - } - - // truth table: - // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY - // F F F F * Yes Yes - // F F F T * Yes Yes - // F F T F * No No - // F F T T * No No - // F T F F * No Yes - // F T F T * Yes Yes - // F T T F * No No - // F T T T * No No - // T * * * F Yes Yes - - chat.mMuted = is_muted && !is_linden; - - // pass owner_id to chat so that we can display the remote - // object inspect for an object that is chatting with you - LLSD args; - chat.mOwnerID = owner_id; - - LLTranslate::instance().logCharsSeen(mesg.size()); - if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM) - { - if (chat.mChatStyle == CHAT_STYLE_IRC) - { - mesg = mesg.substr(4, std::string::npos); - } - const std::string from_lang = ""; // leave empty to trigger autodetect - const std::string to_lang = LLTranslate::getTranslateLanguage(); - - LLTranslate::instance().logCharsSent(mesg.size()); - LLTranslate::translateMessage(from_lang, to_lang, mesg, - boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2), - boost::bind(&translateFailure, chat, args, _1, _2)); + if (gNonInteractive) + { + return; + } + LLChat chat; + std::string mesg; + std::string from_name; + U8 source_temp; + U8 type_temp; + U8 audible_temp; + LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f); + LLUUID from_id; + LLUUID owner_id; + LLViewerObject* chatter; - } - else - { - LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); - } + msg->getString("ChatData", "FromName", from_name); - // don't call notification for debug messages from not owned objects - if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) - { - if (gAgentID != chat.mOwnerID) - { - return; - } - } + msg->getUUID("ChatData", "SourceID", from_id); + chat.mFromID = from_id; - if (mesg != "") - { - LLSD msg_notify = LLSD(LLSD::emptyMap()); - msg_notify["session_id"] = LLUUID(); - msg_notify["from_id"] = chat.mFromID; - msg_notify["source_type"] = chat.mSourceType; - on_new_message(msg_notify); - } + // Object owner for objects + msg->getUUID("ChatData", "OwnerID", owner_id); - } -} + msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); + chat.mSourceType = (EChatSourceType)source_temp; + msg->getU8("ChatData", "ChatType", type_temp); + chat.mChatType = (EChatType)type_temp; -// Simulator we're on is informing the viewer that the agent -// is starting to teleport (perhaps to another sim, perhaps to the -// same sim). If we initiated the teleport process by sending some kind -// of TeleportRequest, then this info is redundant, but if the sim -// initiated the teleport (via a script call, being killed, etc.) -// then this info is news to us. -void process_teleport_start(LLMessageSystem *msg, void**) -{ - // on teleport, don't tell them about destination guide anymore - LLFirstUse::notUsingDestinationGuide(false); - U32 teleport_flags = 0x0; - msg->getU32("Info", "TeleportFlags", teleport_flags); + msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp); + chat.mAudible = (EChatAudible)audible_temp; - if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) - { - // Race condition? - LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; - } + chat.mTime = LLFrameTimer::getElapsedSeconds(); - LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; + // IDEVO Correct for new-style "Resident" names + if (chat.mSourceType == CHAT_SOURCE_AGENT) + { + // I don't know if it's OK to change this here, if + // anything downstream does lookups by name, for instance - // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM - LLViewerMessage::getInstance()->mTeleportStartedSignal(); + LLAvatarName av_name; + if (LLAvatarNameCache::get(from_id, &av_name)) + { + chat.mFromName = av_name.getCompleteName(); + } + else + { + chat.mFromName = LLCacheName::cleanFullName(from_name); + } + } + else + { + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(from_name); + if (from_name.empty()) + { + from_name = LLTrans::getString("Unnamed"); + } + chat.mFromName = from_name; + } - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) - { - gViewerWindow->setProgressCancelButtonVisible(FALSE); - } - else - { - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); - } + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - // Freeze the UI and show progress bar - // Note: could add data here to differentiate between normal teleport and death. + BOOL is_muted = FALSE; + BOOL is_linden = FALSE; + is_muted = LLMuteList::getInstance()->isMuted( + from_id, + from_name, + LLMute::flagTextChat) + || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat); + is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && + LLMuteList::isLinden(from_name); - if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) - { - gTeleportDisplay = TRUE; - gAgent.setTeleportState( LLAgent::TELEPORT_START ); - make_ui_sound("UISndTeleportOut"); - - LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; + if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) + { + return; + } - // Don't call LLFirstUse::useTeleport here because this could be - // due to being killed, which would send you home, not to a Telehub - } + BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); + chatter = gObjectList.findObject(from_id); + if (chatter) + { + chat.mPosAgent = chatter->getPositionAgent(); + + // Make swirly things only for talking objects. (not script debug messages, though) + if (chat.mSourceType == CHAT_SOURCE_OBJECT + && chat.mChatType != CHAT_TYPE_DEBUG_MSG + && gSavedSettings.getBOOL("EffectScriptChatParticles") ) + { + LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); + psc->setSourceObject(chatter); + psc->setColor(color); + //We set the particles to be owned by the object's owner, + //just in case they should be muted by the mute list + psc->setOwnerUUID(owner_id); + LLViewerPartSim::getInstance()->addPartSource(psc); + } + + // record last audible utterance + if (is_audible + && (is_linden || (!is_muted && !is_do_not_disturb))) + { + if (chat.mChatType != CHAT_TYPE_START + && chat.mChatType != CHAT_TYPE_STOP) + { + gAgent.heardChat(chat.mFromID); + } + } + } + + if (is_audible) + { + //BOOL visible_in_chat_bubble = FALSE; + + color.setVec(1.f,1.f,1.f,1.f); + msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); + + BOOL ircstyle = FALSE; + + // Look for IRC-style emotes here so chatbubbles work + std::string prefix = mesg.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + ircstyle = TRUE; + } + chat.mText = mesg; + + // Look for the start of typing so we can put "..." in the bubbles. + if (CHAT_TYPE_START == chat.mChatType) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE); + + // Might not have the avatar constructed yet, eg on login. + if (chatter && chatter->isAvatar()) + { + ((LLVOAvatar*)chatter)->startTyping(); + } + return; + } + else if (CHAT_TYPE_STOP == chat.mChatType) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); + + // Might not have the avatar constructed yet, eg on login. + if (chatter && chatter->isAvatar()) + { + ((LLVOAvatar*)chatter)->stopTyping(); + } + return; + } + + // Look for IRC-style emotes + if (ircstyle) + { + // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656 + chat.mChatStyle = CHAT_STYLE_IRC; + + // Do nothing, ircstyle is fixed above for chat bubbles + } + else + { + chat.mText = ""; + switch(chat.mChatType) + { + case CHAT_TYPE_WHISPER: + chat.mText = LLTrans::getString("whisper") + " "; + break; + case CHAT_TYPE_DEBUG_MSG: + case CHAT_TYPE_OWNER: + case CHAT_TYPE_NORMAL: + case CHAT_TYPE_DIRECT: + break; + case CHAT_TYPE_SHOUT: + chat.mText = LLTrans::getString("shout") + " "; + break; + case CHAT_TYPE_START: + case CHAT_TYPE_STOP: + LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL; + break; + default: + LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; + break; + } + + chat.mText += mesg; + } + + // We have a real utterance now, so can stop showing "..." and proceed. + if (chatter && chatter->isAvatar()) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); + ((LLVOAvatar*)chatter)->stopTyping(); + + if (!is_muted && !is_do_not_disturb) + { + //visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); + std::string formated_msg = ""; + LLViewerChat::formatChatMsg(chat, formated_msg); + LLChat chat_bubble = chat; + chat_bubble.mText = formated_msg; + ((LLVOAvatar*)chatter)->addChat(chat_bubble); + } + } + + if (chatter) + { + chat.mPosAgent = chatter->getPositionAgent(); + } + + // truth table: + // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY + // F F F F * Yes Yes + // F F F T * Yes Yes + // F F T F * No No + // F F T T * No No + // F T F F * No Yes + // F T F T * Yes Yes + // F T T F * No No + // F T T T * No No + // T * * * F Yes Yes + + chat.mMuted = is_muted && !is_linden; + + // pass owner_id to chat so that we can display the remote + // object inspect for an object that is chatting with you + LLSD args; + chat.mOwnerID = owner_id; + + LLTranslate::instance().logCharsSeen(mesg.size()); + if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM) + { + if (chat.mChatStyle == CHAT_STYLE_IRC) + { + mesg = mesg.substr(4, std::string::npos); + } + const std::string from_lang = ""; // leave empty to trigger autodetect + const std::string to_lang = LLTranslate::getTranslateLanguage(); + + LLTranslate::instance().logCharsSent(mesg.size()); + LLTranslate::translateMessage(from_lang, to_lang, mesg, + boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2), + boost::bind(&translateFailure, chat, args, _1, _2)); + + } + else + { + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + } + + // don't call notification for debug messages from not owned objects + if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) + { + if (gAgentID != chat.mOwnerID) + { + return; + } + } + + if (mesg != "") + { + LLSD msg_notify = LLSD(LLSD::emptyMap()); + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + msg_notify["source_type"] = chat.mSourceType; + on_new_message(msg_notify); + } + + } +} + + +// Simulator we're on is informing the viewer that the agent +// is starting to teleport (perhaps to another sim, perhaps to the +// same sim). If we initiated the teleport process by sending some kind +// of TeleportRequest, then this info is redundant, but if the sim +// initiated the teleport (via a script call, being killed, etc.) +// then this info is news to us. +void process_teleport_start(LLMessageSystem *msg, void**) +{ + // on teleport, don't tell them about destination guide anymore + LLFirstUse::notUsingDestinationGuide(false); + U32 teleport_flags = 0x0; + msg->getU32("Info", "TeleportFlags", teleport_flags); + + if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) + { + // Race condition? + LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; + } + + LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; + + // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM + LLViewerMessage::getInstance()->mTeleportStartedSignal(); + + if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) + { + gViewerWindow->setProgressCancelButtonVisible(FALSE); + } + else + { + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); + } + + // Freeze the UI and show progress bar + // Note: could add data here to differentiate between normal teleport and death. + + if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + { + gTeleportDisplay = TRUE; + gAgent.setTeleportState( LLAgent::TELEPORT_START ); + make_ui_sound("UISndTeleportOut"); + + LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; + + // Don't call LLFirstUse::useTeleport here because this could be + // due to being killed, which would send you home, not to a Telehub + } } boost::signals2::connection LLViewerMessage::setTeleportStartedCallback(teleport_started_callback_t cb) { - return mTeleportStartedSignal.connect(cb); + return mTeleportStartedSignal.connect(cb); } void process_teleport_progress(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - if((gAgent.getID() != agent_id) - || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) - { - LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; - return; - } - U32 teleport_flags = 0x0; - msg->getU32("Info", "TeleportFlags", teleport_flags); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) - { - gViewerWindow->setProgressCancelButtonVisible(FALSE); - } - else - { - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); - } - std::string buffer; - msg->getString("Info", "Message", buffer); - LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; - - //Sorta hacky...default to using simulator raw messages - //if we don't find the coresponding mapping in our progress mappings - std::string message = buffer; - - if (LLAgent::sTeleportProgressMessages.find(buffer) != - LLAgent::sTeleportProgressMessages.end() ) - { - message = LLAgent::sTeleportProgressMessages[buffer]; - } - - gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + if((gAgent.getID() != agent_id) + || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) + { + LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; + return; + } + U32 teleport_flags = 0x0; + msg->getU32("Info", "TeleportFlags", teleport_flags); + if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) + { + gViewerWindow->setProgressCancelButtonVisible(FALSE); + } + else + { + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); + } + std::string buffer; + msg->getString("Info", "Message", buffer); + LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; + + //Sorta hacky...default to using simulator raw messages + //if we don't find the coresponding mapping in our progress mappings + std::string message = buffer; + + if (LLAgent::sTeleportProgressMessages.find(buffer) != + LLAgent::sTeleportProgressMessages.end() ) + { + message = LLAgent::sTeleportProgressMessages[buffer]; + } + + gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); } class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea(const uuid_vec_t &ids) : - LLInventoryFetchDescendentsObserver(ids) - {} - virtual void done() - { - LLIsType is_landmark(LLAssetType::AT_LANDMARK); - LLIsType is_card(LLAssetType::AT_CALLINGCARD); - - LLInventoryModel::cat_array_t card_cats; - LLInventoryModel::item_array_t card_items; - LLInventoryModel::cat_array_t land_cats; - LLInventoryModel::item_array_t land_items; - - uuid_vec_t::iterator it = mComplete.begin(); - uuid_vec_t::iterator end = mComplete.end(); - for(; it != end; ++it) - { - gInventory.collectDescendentsIf( - (*it), - land_cats, - land_items, - LLInventoryModel::EXCLUDE_TRASH, - is_landmark); - gInventory.collectDescendentsIf( - (*it), - card_cats, - card_items, - LLInventoryModel::EXCLUDE_TRASH, - is_card); - } - - gInventory.removeObserver(this); - delete this; - } + LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLInventoryFetchDescendentsObserver(ids) + {} + virtual void done() + { + LLIsType is_landmark(LLAssetType::AT_LANDMARK); + LLIsType is_card(LLAssetType::AT_CALLINGCARD); + + LLInventoryModel::cat_array_t card_cats; + LLInventoryModel::item_array_t card_items; + LLInventoryModel::cat_array_t land_cats; + LLInventoryModel::item_array_t land_items; + + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); + for(; it != end; ++it) + { + gInventory.collectDescendentsIf( + (*it), + land_cats, + land_items, + LLInventoryModel::EXCLUDE_TRASH, + is_landmark); + gInventory.collectDescendentsIf( + (*it), + card_cats, + card_items, + LLInventoryModel::EXCLUDE_TRASH, + is_card); + } + + gInventory.removeObserver(this); + delete this; + } }; -class LLPostTeleportNotifiers : public LLEventTimer +class LLPostTeleportNotifiers : public LLEventTimer { public: - LLPostTeleportNotifiers(); - virtual ~LLPostTeleportNotifiers(); + LLPostTeleportNotifiers(); + virtual ~LLPostTeleportNotifiers(); - //function to be called at the supplied frequency - bool tick() override; + //function to be called at the supplied frequency + bool tick() override; }; LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) @@ -2903,34 +2903,34 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() bool LLPostTeleportNotifiers::tick() { - bool all_done = false; - if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) - { - // get callingcards and landmarks available to the user arriving. - uuid_vec_t folders; - const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(callingcard_id.notNull()) - folders.push_back(callingcard_id); - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - if(folder_id.notNull()) - folders.push_back(folder_id); - if(!folders.empty()) - { - LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); - fetcher->startFetch(); - if(fetcher->isFinished()) - { - fetcher->done(); - } - else - { - gInventory.addObserver(fetcher); - } - } - all_done = true; - } - - return all_done; + bool all_done = false; + if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + { + // get callingcards and landmarks available to the user arriving. + uuid_vec_t folders; + const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + if(callingcard_id.notNull()) + folders.push_back(callingcard_id); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + if(folder_id.notNull()) + folders.push_back(folder_id); + if(!folders.empty()) + { + LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); + fetcher->startFetch(); + if(fetcher->isFinished()) + { + fetcher->done(); + } + else + { + gInventory.addObserver(fetcher); + } + } + all_done = true; + } + + return all_done; } @@ -2939,14 +2939,14 @@ bool LLPostTeleportNotifiers::tick() // We're going to pretend to be a new agent void process_teleport_finish(LLMessageSystem* msg, void**) { - LL_DEBUGS("Teleport","Messaging") << "Received TeleportFinish message" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Teleport","Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; - return; - } + LL_DEBUGS("Teleport","Messaging") << "Received TeleportFinish message" << LL_ENDL; + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS("Teleport","Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; + return; + } if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { @@ -2954,7 +2954,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) { // Server either ignored teleport cancel message or did not receive it in time. // This message can't be ignored since teleport is complete at server side - LL_INFOS("Teleport") << "Restoring canceled teleport request" << LL_ENDL; + LL_INFOS("Teleport") << "Restoring canceled teleport request" << LL_ENDL; gAgent.restoreCanceledTeleportRequest(); } else @@ -2971,663 +2971,663 @@ void process_teleport_finish(LLMessageSystem* msg, void**) { LL_WARNS("Teleport","Messaging") << "Teleport message in the middle of other teleport" << LL_ENDL; } - - // Teleport is finished; it can't be cancelled now. - gViewerWindow->setProgressCancelButtonVisible(FALSE); - - // Do teleport effect for where you're leaving - // VEFFECT: TeleportStart - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - - U32 location_id; - U32 sim_ip; - U16 sim_port; - LLVector3 pos, look_at; - U64 region_handle; - msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); - msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip); - msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port); - //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); - //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); - msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle); - U32 teleport_flags; - msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - std::string seedCap; - msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); - - LL_DEBUGS("Teleport") << "TeleportFinish message params are:" - << " sim_ip " << sim_ip - << " sim_port " << sim_port - << " region_handle " << region_handle - << " teleport_flags " << teleport_flags - << " seedCap " << seedCap - << LL_ENDL; - - // update home location if we are teleporting out of prelude - specific to teleporting to welcome area - if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) - && (!gAgent.isGodlike())) - { - gAgent.setHomePosRegion(region_handle, pos); - - // Create a timer that will send notices when teleporting is all finished. Since this is - // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked. - new LLPostTeleportNotifiers(); - } - - LLHost sim_host(sim_ip, sim_port); - - // Viewer trusts the simulator. - gMessageSystem->enableCircuit(sim_host, TRUE); - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + // Teleport is finished; it can't be cancelled now. + gViewerWindow->setProgressCancelButtonVisible(FALSE); + + // Do teleport effect for where you're leaving + // VEFFECT: TeleportStart + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + + U32 location_id; + U32 sim_ip; + U16 sim_port; + LLVector3 pos, look_at; + U64 region_handle; + msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); + msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip); + msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port); + //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); + //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); + msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle); + U32 teleport_flags; + msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + + std::string seedCap; + msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); + + LL_DEBUGS("Teleport") << "TeleportFinish message params are:" + << " sim_ip " << sim_ip + << " sim_port " << sim_port + << " region_handle " << region_handle + << " teleport_flags " << teleport_flags + << " seedCap " << seedCap + << LL_ENDL; + + // update home location if we are teleporting out of prelude - specific to teleporting to welcome area + if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) + && (!gAgent.isGodlike())) + { + gAgent.setHomePosRegion(region_handle, pos); + + // Create a timer that will send notices when teleporting is all finished. Since this is + // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked. + new LLPostTeleportNotifiers(); + } + + LLHost sim_host(sim_ip, sim_port); + + // Viewer trusts the simulator. + gMessageSystem->enableCircuit(sim_host, TRUE); + LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); /* - // send camera update to new region - gAgentCamera.updateCamera(); - - // likewise make sure the camera is behind the avatar - gAgentCamera.resetView(TRUE); - LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal()); - gAgent.setRegion(regionp); - gObjectList.shiftObjects(shift_vector); - - if (isAgentAvatarValid()) - { - gAgentAvatarp->clearChatText(); - gAgentCamera.slamLookAt(look_at); - } - gAgent.setPositionAgent(pos); - gAssetStorage->setUpstream(sim); - gCacheName->setUpstream(sim); + // send camera update to new region + gAgentCamera.updateCamera(); + + // likewise make sure the camera is behind the avatar + gAgentCamera.resetView(TRUE); + LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal()); + gAgent.setRegion(regionp); + gObjectList.shiftObjects(shift_vector); + + if (isAgentAvatarValid()) + { + gAgentAvatarp->clearChatText(); + gAgentCamera.slamLookAt(look_at); + } + gAgent.setPositionAgent(pos); + gAssetStorage->setUpstream(sim); + gCacheName->setUpstream(sim); */ - // Make sure we're standing - gAgent.standUp(); + // Make sure we're standing + gAgent.standUp(); - // now, use the circuit info to tell simulator about us! - LL_INFOS("Teleport","Messaging") << "process_teleport_finish() sending UseCircuitCode to enable sim_host " - << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable(sim_host); + // now, use the circuit info to tell simulator about us! + LL_INFOS("Teleport","Messaging") << "process_teleport_finish() sending UseCircuitCode to enable sim_host " + << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; + msg->newMessageFast(_PREHASH_UseCircuitCode); + msg->nextBlockFast(_PREHASH_CircuitCode); + msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); + msg->sendReliable(sim_host); - LL_INFOS("Teleport") << "Calling send_complete_agent_movement() and setting state to TELEPORT_MOVING" << LL_ENDL; - send_complete_agent_movement(sim_host); - gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); - gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); + LL_INFOS("Teleport") << "Calling send_complete_agent_movement() and setting state to TELEPORT_MOVING" << LL_ENDL; + send_complete_agent_movement(sim_host); + gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); + gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability(). Seed cap == " - << seedCap << LL_ENDL; - regionp->setSeedCapability(seedCap); + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability(). Seed cap == " + << seedCap << LL_ENDL; + regionp->setSeedCapability(seedCap); - // Don't send camera updates to the new region until we're - // actually there... + // Don't send camera updates to the new region until we're + // actually there... - // Now do teleport effect for where you're going. - // VEFFECT: TeleportEnd - effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); + // Now do teleport effect for where you're going. + // VEFFECT: TeleportEnd + effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); -// gTeleportDisplay = TRUE; -// gTeleportDisplayTimer.reset(); -// gViewerWindow->setShowProgress(TRUE); +// gTeleportDisplay = TRUE; +// gTeleportDisplayTimer.reset(); +// gViewerWindow->setShowProgress(TRUE); } // stuff we have to do every time we get an AvatarInitComplete from a sim /* void process_avatar_init_complete(LLMessageSystem* msg, void**) { - LLVector3 agent_pos; - msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos); - agent_movement_complete(msg->getSender(), agent_pos); + LLVector3 agent_pos; + msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos); + agent_movement_complete(msg->getSender(), agent_pos); } */ void process_agent_movement_complete(LLMessageSystem* msg, void**) { - LL_INFOS("Teleport","Messaging") << "Received ProcessAgentMovementComplete" << LL_ENDL; - - gShiftFrame = true; - gAgentMovementCompleted = true; - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) - { - LL_WARNS("Teleport", "Messaging") << "Incorrect agent or session id in process_agent_movement_complete()" - << " agent " << agent_id << " expected " << gAgent.getID() - << " session " << session_id << " expected " << gAgent.getSessionID() - << ", ignoring" << LL_ENDL; - return; - } - - // *TODO: check timestamp to make sure the movement compleation - // makes sense. - LLVector3 agent_pos; - msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos); - LLVector3 look_at; - msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at); - U64 region_handle; - msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle); - - std::string version_channel; - msg->getString("SimData", "ChannelVersion", version_channel); - - if (!isAgentAvatarValid()) - { - // Could happen if you were immediately god-teleported away on login, - // maybe other cases. Continue, but warn. - LL_WARNS("Teleport", "Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; - } - - F32 x, y; - from_region_handle(region_handle, &x, &y); - LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); - if (!regionp) - { - if (gAgent.getRegion()) - { - LL_WARNS("Teleport", "Messaging") << "current region origin " - << gAgent.getRegion()->getOriginGlobal() << " id " << gAgent.getRegion()->getRegionID() << LL_ENDL; - } - - LL_WARNS("Teleport", "Messaging") << "Agent being sent to invalid home region: " - << x << ":" << y - << " current pos " << gAgent.getPositionGlobal() - << ", calling forceDisconnect()" - << LL_ENDL; - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); - return; - - } - - LL_INFOS("Teleport","Messaging") << "Changing home region to region id " << regionp->getRegionID() << " handle " << region_handle << " == x,y " << x << "," << y << LL_ENDL; - - // set our upstream host the new simulator and shuffle things as - // appropriate. - LLVector3 shift_vector = regionp->getPosRegionFromGlobal( - gAgent.getRegion()->getOriginGlobal()); - gAgent.setRegion(regionp); - gObjectList.shiftObjects(shift_vector); - gAssetStorage->setUpstream(msg->getSender()); - gCacheName->setUpstream(msg->getSender()); - gViewerThrottle.sendToSim(); - gViewerWindow->sendShapeToSim(); - - bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - - if( is_teleport ) - { - if (gAgent.getTeleportKeepsLookAt()) - { - // *NOTE: the LookAt data we get from the sim here doesn't - // seem to be useful, so get it from the camera instead - look_at = LLViewerCamera::getInstance()->getAtAxis(); - } - // Force the camera back onto the agent, don't animate. - gAgentCamera.setFocusOnAvatar(TRUE, FALSE); - gAgentCamera.slamLookAt(look_at); - gAgentCamera.updateCamera(); - - LL_INFOS("Teleport") << "Agent movement complete, setting state to TELEPORT_START_ARRIVAL" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); - - if (isAgentAvatarValid()) - { - // Set the new position - gAgentAvatarp->setPositionAgent(agent_pos); - gAgentAvatarp->clearChat(); - gAgentAvatarp->slamPosition(); - } - } - else - { - // This is initial log-in or a region crossing - LL_INFOS("Teleport") << "State is not TELEPORT_MOVING, so this is initial log-in or region crossing. " - << "Setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - - if(LLStartUp::getStartupState() < STATE_STARTED) - { // This is initial log-in, not a region crossing: - // Set the camera looking ahead of the AV so send_agent_update() below - // will report the correct location to the server. - LLVector3 look_at_point = look_at; - look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat()); - - static LLVector3 up_direction(0.0f, 0.0f, 1.0f); - LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction); - } - } - - if ( LLTracker::isTracking(NULL) ) - { - // Check distance to beacon, if < 5m, remove beacon - LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal(); - LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0); - if (beacon_dir.magVecSquared() < 25.f) - { - LLTracker::stopTracking(false); - } - else if ( is_teleport && !gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) - { - //look at the beacon - LLVector3 global_agent_pos = agent_pos; - global_agent_pos[0] += x; - global_agent_pos[1] += y; - look_at = (LLVector3)beacon_pos - global_agent_pos; - look_at.normVec(); - gAgentCamera.slamLookAt(look_at); - } - } - - // TODO: Put back a check for flying status! DK 12/19/05 - // Sim tells us whether the new position is off the ground - /* - if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) - { - gAgent.setFlying(TRUE); - } - else - { - gAgent.setFlying(FALSE); - } - */ - - send_agent_update(TRUE, TRUE); - - if (gAgent.getRegion()->getBlockFly()) - { - gAgent.setFlying(gAgent.canFly()); - } - - // force simulator to recognize do not disturb state - if (gAgent.isDoNotDisturb()) - { - gAgent.setDoNotDisturb(true); - } - else - { - gAgent.setDoNotDisturb(false); - } - - if (isAgentAvatarValid()) - { - gAgentAvatarp->mFootPlane.clearVec(); - } - - // send walk-vs-run status - gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); - - // If the server version has changed, display an info box and offer - // to display the release notes, unless this is the initial log in. - if (gLastVersionChannel == version_channel) - { - return; - } - - gLastVersionChannel = version_channel; -} + LL_INFOS("Teleport","Messaging") << "Received ProcessAgentMovementComplete" << LL_ENDL; -void process_crossed_region(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) - { - LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" - << LL_ENDL; - return; - } - LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; - gAgentAvatarp->resetRegionCrossingTimer(); + gShiftFrame = true; + gAgentMovementCompleted = true; - U32 sim_ip; - msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); - U16 sim_port; - msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port); - LLHost sim_host(sim_ip, sim_port); - U64 region_handle; - msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); - - std::string seedCap; - msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, seedCap); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + { + LL_WARNS("Teleport", "Messaging") << "Incorrect agent or session id in process_agent_movement_complete()" + << " agent " << agent_id << " expected " << gAgent.getID() + << " session " << session_id << " expected " << gAgent.getSessionID() + << ", ignoring" << LL_ENDL; + return; + } - send_complete_agent_movement(sim_host); + // *TODO: check timestamp to make sure the movement compleation + // makes sense. + LLVector3 agent_pos; + msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos); + LLVector3 look_at; + msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at); + U64 region_handle; + msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle); - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + std::string version_channel; + msg->getString("SimData", "ChannelVersion", version_channel); - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " - << seedCap << LL_ENDL; - regionp->setSeedCapability(seedCap); -} + if (!isAgentAvatarValid()) + { + // Could happen if you were immediately god-teleported away on login, + // maybe other cases. Continue, but warn. + LL_WARNS("Teleport", "Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; + } + F32 x, y; + from_region_handle(region_handle, &x, &y); + LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + if (!regionp) + { + if (gAgent.getRegion()) + { + LL_WARNS("Teleport", "Messaging") << "current region origin " + << gAgent.getRegion()->getOriginGlobal() << " id " << gAgent.getRegion()->getRegionID() << LL_ENDL; + } + LL_WARNS("Teleport", "Messaging") << "Agent being sent to invalid home region: " + << x << ":" << y + << " current pos " << gAgent.getPositionGlobal() + << ", calling forceDisconnect()" + << LL_ENDL; + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); + return; -// Sends avatar and camera information to simulator. -// Sent roughly once per frame, or 20 times per second, whichever is less often + } -const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot -const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot - // between these values we delay the updates (but no more than one second) + LL_INFOS("Teleport","Messaging") << "Changing home region to region id " << regionp->getRegionID() << " handle " << region_handle << " == x,y " << x << "," << y << LL_ENDL; -void send_agent_update(BOOL force_send, BOOL send_reliable) -{ - LL_PROFILE_ZONE_SCOPED; - llassert(!gCubeSnapshot); + // set our upstream host the new simulator and shuffle things as + // appropriate. + LLVector3 shift_vector = regionp->getPosRegionFromGlobal( + gAgent.getRegion()->getOriginGlobal()); + gAgent.setRegion(regionp); + gObjectList.shiftObjects(shift_vector); + gAssetStorage->setUpstream(msg->getSender()); + gCacheName->setUpstream(msg->getSender()); + gViewerThrottle.sendToSim(); + gViewerWindow->sendShapeToSim(); - if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) - { - // We don't care if they want to send an agent update, they're not allowed to until the simulator - // that's the target is ready to receive them (after avatar_init_complete is received) - return; - } - - // We have already requested to log out. Don't send agent updates. - if(LLAppViewer::instance()->logoutRequestSent()) - { - return; - } - - // no region to send update to - if(gAgent.getRegion() == NULL) - { - return; - } - - const F32 TRANSLATE_THRESHOLD = 0.01f; - - // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation - // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change - // Thus, we're actually testing against 0.2 degrees - const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above - - const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent - - // Store data on last sent update so that if no changes, no send - static LLVector3 last_camera_pos_agent, - last_camera_at, - last_camera_left, - last_camera_up; - - static LLVector3 cam_center_chg, - cam_rot_chg; - - static LLQuaternion last_head_rot; - static U32 last_control_flags = 0; - static U8 last_render_state; - static U8 duplicate_count = 0; - static F32 head_rot_chg = 1.0; - static U8 last_flags; - - LLMessageSystem *msg = gMessageSystem; - LLVector3 camera_pos_agent; // local to avatar's region - U8 render_state; - - LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion(); - LLQuaternion head_rotation = gAgent.getHeadRotation(); - - camera_pos_agent = gAgentCamera.getCameraPositionAgent(); - - render_state = gAgent.getRenderState(); - - U32 control_flag_change = 0; - U8 flag_change = 0; - - cam_center_chg = last_camera_pos_agent - camera_pos_agent; - cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis(); - - // If a modifier key is held down, turn off - // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't - // trigger a control event. - U32 control_flags = gAgent.getControlFlags(); - - MASK key_mask = gKeyboard->currentMask(TRUE); - - if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) - { - control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | - AGENT_CONTROL_ML_LBUTTON_DOWN ); - control_flags |= AGENT_CONTROL_LBUTTON_UP | - AGENT_CONTROL_ML_LBUTTON_UP ; - } - - control_flag_change = last_control_flags ^ control_flags; - - U8 flags = AU_FLAGS_NONE; - if (gAgent.isGroupTitleHidden()) - { - flags |= AU_FLAGS_HIDETITLE; - } - if (gAgent.getAutoPilot()) - { - flags |= AU_FLAGS_CLIENT_AUTOPILOT; - } - - flag_change = last_flags ^ flags; - - head_rot_chg = dot(last_head_rot, head_rotation); - - //static S32 msg_number = 0; // Used for diagnostic log messages - - if (force_send || - (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || - (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || - (last_render_state != render_state) || - (cam_rot_chg.magVec() > ROTATION_THRESHOLD) || - control_flag_change != 0 || - flag_change != 0) - { - /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block - msg_number += 1; - if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) - { - //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL; - } - if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) - { - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL; - } - if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) - { - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL; - } -// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) -// { -// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL; -// } - if (control_flag_change) - { - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL; - } -*/ + bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - duplicate_count = 0; - } - else - { - duplicate_count++; - - if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND) - { - // The head_rotation is sent for updating things like attached guns. - // We only trigger a new update when head_rotation deviates beyond - // some threshold from the last update, however this can break fine - // adjustments when trying to aim an attached gun, so what we do here - // (where we would normally skip sending an update when nothing has changed) - // is gradually reduce the threshold to allow a better update to - // eventually get sent... should update to within 0.5 degrees in less - // than a second. - if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND) - { - duplicate_count = 0; - } - else - { - return; - } - } - else - { - return; - } - } - - if (duplicate_count < DUP_MSGS && !gDisconnected) - { - /* More diagnostics to count AgentUpdate messages - static S32 update_sec = 0; - static S32 update_count = 0; - static S32 max_update_count = 0; - S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() ); - update_count += 1; - if (cur_sec != update_sec) - { - if (update_sec != 0) - { - update_sec = cur_sec; - //msg_number = 0; - max_update_count = llmax(max_update_count, update_count); - LL_INFOS() << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << LL_ENDL; - } - update_sec = cur_sec; - update_count = 0; - } - */ - - // Build the message - msg->newMessageFast(_PREHASH_AgentUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); - msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); - msg->addU8Fast(_PREHASH_State, render_state); - msg->addU8Fast(_PREHASH_Flags, flags); - -// if (camera_pos_agent.mV[VY] > 255.f) -// { -// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; -// } - - msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); - msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); - msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); - msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); - - msg->addU32Fast(_PREHASH_ControlFlags, control_flags); - - if (gDebugClicks) - { - if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) - { - LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; - } - - if (control_flags & AGENT_CONTROL_LBUTTON_UP) - { - LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; - } - } - - gAgent.enableControlFlagReset(); - - if (!send_reliable) - { - gAgent.sendMessage(); - } - else - { - gAgent.sendReliableMessage(); - } - -// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; - - // Copy the old data - last_head_rot = head_rotation; - last_render_state = render_state; - last_camera_pos_agent = camera_pos_agent; - last_camera_at = LLViewerCamera::getInstance()->getAtAxis(); - last_camera_left = LLViewerCamera::getInstance()->getLeftAxis(); - last_camera_up = LLViewerCamera::getInstance()->getUpAxis(); - last_control_flags = control_flags; - last_flags = flags; - } -} + if( is_teleport ) + { + if (gAgent.getTeleportKeepsLookAt()) + { + // *NOTE: the LookAt data we get from the sim here doesn't + // seem to be useful, so get it from the camera instead + look_at = LLViewerCamera::getInstance()->getAtAxis(); + } + // Force the camera back onto the agent, don't animate. + gAgentCamera.setFocusOnAvatar(TRUE, FALSE); + gAgentCamera.slamLookAt(look_at); + gAgentCamera.updateCamera(); + LL_INFOS("Teleport") << "Agent movement complete, setting state to TELEPORT_START_ARRIVAL" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); -// sounds can arrive before objects, store them for a short time -// Note: this is a workaround for MAINT-4743, real fix would be to make -// server send sound along with object update that creates (rezes) the object -class PostponedSoundData -{ -public: - PostponedSoundData() : - mExpirationTime(0) - {} - PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); - bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + if (isAgentAvatarValid()) + { + // Set the new position + gAgentAvatarp->setPositionAgent(agent_pos); + gAgentAvatarp->clearChat(); + gAgentAvatarp->slamPosition(); + } + } + else + { + // This is initial log-in or a region crossing + LL_INFOS("Teleport") << "State is not TELEPORT_MOVING, so this is initial log-in or region crossing. " + << "Setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + + if(LLStartUp::getStartupState() < STATE_STARTED) + { // This is initial log-in, not a region crossing: + // Set the camera looking ahead of the AV so send_agent_update() below + // will report the correct location to the server. + LLVector3 look_at_point = look_at; + look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat()); + + static LLVector3 up_direction(0.0f, 0.0f, 1.0f); + LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction); + } + } - LLUUID mObjectId; - LLUUID mSoundId; - LLUUID mOwnerId; - F32 mGain; - U8 mFlags; - static const F64 MAXIMUM_PLAY_DELAY; + if ( LLTracker::isTracking(NULL) ) + { + // Check distance to beacon, if < 5m, remove beacon + LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal(); + LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0); + if (beacon_dir.magVecSquared() < 25.f) + { + LLTracker::stopTracking(false); + } + else if ( is_teleport && !gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) + { + //look at the beacon + LLVector3 global_agent_pos = agent_pos; + global_agent_pos[0] += x; + global_agent_pos[1] += y; + look_at = (LLVector3)beacon_pos - global_agent_pos; + look_at.normVec(); + gAgentCamera.slamLookAt(look_at); + } + } -private: - F64 mExpirationTime; //seconds since epoch -}; -const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; -static F64 postponed_sounds_update_expiration = 0.0; -static std::map<LLUUID, PostponedSoundData> postponed_sounds; + // TODO: Put back a check for flying status! DK 12/19/05 + // Sim tells us whether the new position is off the ground + /* + if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) + { + gAgent.setFlying(TRUE); + } + else + { + gAgent.setFlying(FALSE); + } + */ -void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) -{ - if (LLMuteList::getInstance()->isMuted(object_id)) return; + send_agent_update(TRUE, TRUE); - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + if (gAgent.getRegion()->getBlockFly()) + { + gAgent.setFlying(gAgent.canFly()); + } - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos = objectp->getPositionGlobal(); - if (!gAgent.canAccessMaturityAtGlobal(pos)) + // force simulator to recognize do not disturb state + if (gAgent.isDoNotDisturb()) + { + gAgent.setDoNotDisturb(true); + } + else + { + gAgent.setDoNotDisturb(false); + } + + if (isAgentAvatarValid()) + { + gAgentAvatarp->mFootPlane.clearVec(); + } + + // send walk-vs-run status + gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); + + // If the server version has changed, display an info box and offer + // to display the release notes, unless this is the initial log in. + if (gLastVersionChannel == version_channel) { return; } - objectp->setAttachedSound(sound_id, owner_id, gain, flags); + gLastVersionChannel = version_channel; } -PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) - : - mObjectId(object_id), - mSoundId(sound_id), - mOwnerId(owner_id), - mGain(gain), - mFlags(flags), - mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +void process_crossed_region(LLMessageSystem* msg, void**) { + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + { + LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" + << LL_ENDL; + return; + } + LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; + gAgentAvatarp->resetRegionCrossingTimer(); + + U32 sim_ip; + msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); + U16 sim_port; + msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port); + LLHost sim_host(sim_ip, sim_port); + U64 region_handle; + msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + + std::string seedCap; + msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, seedCap); + + send_complete_agent_movement(sim_host); + + LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " + << seedCap << LL_ENDL; + regionp->setSeedCapability(seedCap); } -// static -void update_attached_sounds() + + +// Sends avatar and camera information to simulator. +// Sent roughly once per frame, or 20 times per second, whichever is less often + +const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot +const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot + // between these values we delay the updates (but no more than one second) + +void send_agent_update(BOOL force_send, BOOL send_reliable) { - if (postponed_sounds.empty()) + LL_PROFILE_ZONE_SCOPED; + llassert(!gCubeSnapshot); + + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + // We don't care if they want to send an agent update, they're not allowed to until the simulator + // that's the target is ready to receive them (after avatar_init_complete is received) + return; + } + + // We have already requested to log out. Don't send agent updates. + if(LLAppViewer::instance()->logoutRequestSent()) + { + return; + } + + // no region to send update to + if(gAgent.getRegion() == NULL) + { + return; + } + + const F32 TRANSLATE_THRESHOLD = 0.01f; + + // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation + // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change + // Thus, we're actually testing against 0.2 degrees + const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above + + const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent + + // Store data on last sent update so that if no changes, no send + static LLVector3 last_camera_pos_agent, + last_camera_at, + last_camera_left, + last_camera_up; + + static LLVector3 cam_center_chg, + cam_rot_chg; + + static LLQuaternion last_head_rot; + static U32 last_control_flags = 0; + static U8 last_render_state; + static U8 duplicate_count = 0; + static F32 head_rot_chg = 1.0; + static U8 last_flags; + + LLMessageSystem *msg = gMessageSystem; + LLVector3 camera_pos_agent; // local to avatar's region + U8 render_state; + + LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion(); + LLQuaternion head_rotation = gAgent.getHeadRotation(); + + camera_pos_agent = gAgentCamera.getCameraPositionAgent(); + + render_state = gAgent.getRenderState(); + + U32 control_flag_change = 0; + U8 flag_change = 0; + + cam_center_chg = last_camera_pos_agent - camera_pos_agent; + cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis(); + + // If a modifier key is held down, turn off + // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't + // trigger a control event. + U32 control_flags = gAgent.getControlFlags(); + + MASK key_mask = gKeyboard->currentMask(TRUE); + + if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) + { + control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | + AGENT_CONTROL_ML_LBUTTON_DOWN ); + control_flags |= AGENT_CONTROL_LBUTTON_UP | + AGENT_CONTROL_ML_LBUTTON_UP ; + } + + control_flag_change = last_control_flags ^ control_flags; + + U8 flags = AU_FLAGS_NONE; + if (gAgent.isGroupTitleHidden()) + { + flags |= AU_FLAGS_HIDETITLE; + } + if (gAgent.getAutoPilot()) + { + flags |= AU_FLAGS_CLIENT_AUTOPILOT; + } + + flag_change = last_flags ^ flags; + + head_rot_chg = dot(last_head_rot, head_rotation); + + //static S32 msg_number = 0; // Used for diagnostic log messages + + if (force_send || + (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || + (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || + (last_render_state != render_state) || + (cam_rot_chg.magVec() > ROTATION_THRESHOLD) || + control_flag_change != 0 || + flag_change != 0) + { + /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block + msg_number += 1; + if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) + { + //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL; + } + if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) + { + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL; + } + if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) + { + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL; + } +// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) +// { +// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL; +// } + if (control_flag_change) + { + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL; + } +*/ + + duplicate_count = 0; + } + else + { + duplicate_count++; + + if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND) + { + // The head_rotation is sent for updating things like attached guns. + // We only trigger a new update when head_rotation deviates beyond + // some threshold from the last update, however this can break fine + // adjustments when trying to aim an attached gun, so what we do here + // (where we would normally skip sending an update when nothing has changed) + // is gradually reduce the threshold to allow a better update to + // eventually get sent... should update to within 0.5 degrees in less + // than a second. + if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND) + { + duplicate_count = 0; + } + else + { + return; + } + } + else + { + return; + } + } + + if (duplicate_count < DUP_MSGS && !gDisconnected) + { + /* More diagnostics to count AgentUpdate messages + static S32 update_sec = 0; + static S32 update_count = 0; + static S32 max_update_count = 0; + S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() ); + update_count += 1; + if (cur_sec != update_sec) + { + if (update_sec != 0) + { + update_sec = cur_sec; + //msg_number = 0; + max_update_count = llmax(max_update_count, update_count); + LL_INFOS() << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << LL_ENDL; + } + update_sec = cur_sec; + update_count = 0; + } + */ + + // Build the message + msg->newMessageFast(_PREHASH_AgentUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); + msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); + msg->addU8Fast(_PREHASH_State, render_state); + msg->addU8Fast(_PREHASH_Flags, flags); + +// if (camera_pos_agent.mV[VY] > 255.f) +// { +// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; +// } + + msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); + msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); + msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); + msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); + msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); + + msg->addU32Fast(_PREHASH_ControlFlags, control_flags); + + if (gDebugClicks) + { + if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) + { + LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; + } + + if (control_flags & AGENT_CONTROL_LBUTTON_UP) + { + LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; + } + } + + gAgent.enableControlFlagReset(); + + if (!send_reliable) + { + gAgent.sendMessage(); + } + else + { + gAgent.sendReliableMessage(); + } + +// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; + + // Copy the old data + last_head_rot = head_rotation; + last_render_state = render_state; + last_camera_pos_agent = camera_pos_agent; + last_camera_at = LLViewerCamera::getInstance()->getAtAxis(); + last_camera_left = LLViewerCamera::getInstance()->getLeftAxis(); + last_camera_up = LLViewerCamera::getInstance()->getUpAxis(); + last_control_flags = control_flags; + last_flags = flags; + } +} + + +// sounds can arrive before objects, store them for a short time +// Note: this is a workaround for MAINT-4743, real fix would be to make +// server send sound along with object update that creates (rezes) the object +class PostponedSoundData +{ +public: + PostponedSoundData() : + mExpirationTime(0) + {} + PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); + bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + + LLUUID mObjectId; + LLUUID mSoundId; + LLUUID mOwnerId; + F32 mGain; + U8 mFlags; + static const F64 MAXIMUM_PLAY_DELAY; + +private: + F64 mExpirationTime; //seconds since epoch +}; +const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; +static F64 postponed_sounds_update_expiration = 0.0; +static std::map<LLUUID, PostponedSoundData> postponed_sounds; + +void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos = objectp->getPositionGlobal(); + if (!gAgent.canAccessMaturityAtGlobal(pos)) + { + return; + } + + objectp->setAttachedSound(sound_id, owner_id, gain, flags); +} + +PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) + : + mObjectId(object_id), + mSoundId(sound_id), + mOwnerId(owner_id), + mGain(gain), + mFlags(flags), + mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +{ +} + +// static +void update_attached_sounds() +{ + if (postponed_sounds.empty()) { return; } @@ -3681,177 +3681,177 @@ void clear_expired_postponed_sounds() extern U32Bits gObjectData; void process_object_update(LLMessageSystem *mesgsys, void **user_data) -{ - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } - - // Update the object... - S32 old_num_objects = gObjectList.mNumNewObjects; - gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); - if (old_num_objects != gObjectList.mNumNewObjects) - { - update_attached_sounds(); - } +{ + // Update the data counters + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } + + // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; + gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) { - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } - - // Update the object... - S32 old_num_objects = gObjectList.mNumNewObjects; - gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); - if (old_num_objects != gObjectList.mNumNewObjects) - { - update_attached_sounds(); - } + // Update the data counters + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } + + // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; + gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) { - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } + // Update the data counters + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } - // Update the object... - gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED); + // Update the object... + gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED); } void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) { - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } - S32 old_num_objects = gObjectList.mNumNewObjects; - gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); - if (old_num_objects != gObjectList.mNumNewObjects) - { - update_attached_sounds(); - } + S32 old_num_objects = gObjectList.mNumNewObjects; + gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } void process_kill_object(LLMessageSystem *mesgsys, void **user_data) { LL_PROFILE_ZONE_SCOPED; - LLUUID id; - - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - LLViewerRegion* regionp = NULL; - { - LLHost host(ip, port); - regionp = LLWorld::getInstance()->getRegion(host); - } - - bool delete_object = LLViewerRegion::sVOCacheCullingEnabled; - S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); - for (S32 i = 0; i < num_objects; ++i) - { - U32 local_id; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - - LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); - if (id == LLUUID::null) - { - LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; - continue; - } - else - { - LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; - } - - if (id == gAgentID) - { - // never kill our avatar - continue; - } - - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) - { - // Display green bubble on kill - if ( gShowObjectUpdates ) - { - LLColor4 color(0.f,1.f,0.f,1.f); - gPipeline.addDebugBlip(objectp->getPositionAgent(), color); - LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; - } - - // Do the kill - gObjectList.killObject(objectp); - } - - if(delete_object) - { - regionp->killCacheEntry(local_id); - } - - // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, + LLUUID id; + + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); + LLViewerRegion* regionp = NULL; + { + LLHost host(ip, port); + regionp = LLWorld::getInstance()->getRegion(host); + } + + bool delete_object = LLViewerRegion::sVOCacheCullingEnabled; + S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (S32 i = 0; i < num_objects; ++i) + { + U32 local_id; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); + + LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); + if (id == LLUUID::null) + { + LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; + continue; + } + else + { + LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; + } + + if (id == gAgentID) + { + // never kill our avatar + continue; + } + + LLViewerObject *objectp = gObjectList.findObject(id); + if (objectp) + { + // Display green bubble on kill + if ( gShowObjectUpdates ) + { + LLColor4 color(0.f,1.f,0.f,1.f); + gPipeline.addDebugBlip(objectp->getPositionAgent(), color); + LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; + } + + // Do the kill + gObjectList.killObject(objectp); + } + + if(delete_object) + { + regionp->killCacheEntry(local_id); + } + + // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, // which is using the object, release the mouse capture correctly when the object dies. // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). - LLSelectMgr::getInstance()->removeObjectFromSelections(id); + LLSelectMgr::getInstance()->removeObjectFromSelections(id); - } // end for loop + } // end for loop LLViewerStatsRecorder::instance().recordObjectKills(num_objects); } void process_time_synch(LLMessageSystem *mesgsys, void **user_data) { - LLVector3 sun_direction; + LLVector3 sun_direction; LLVector3 moon_direction; - LLVector3 sun_ang_velocity; - F32 phase; - U64 space_time_usec; + LLVector3 sun_ang_velocity; + F32 phase; + U64 space_time_usec; U32 seconds_per_day; U32 seconds_per_year; - // "SimulatorViewerTimeMessage" - mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec); - mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day); - mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year); + // "SimulatorViewerTimeMessage" + mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec); + mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day); + mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year); - // This should eventually be moved to an "UpdateHeavenlyBodies" message - mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase); - mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction); - mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity); + // This should eventually be moved to an "UpdateHeavenlyBodies" message + mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase); + mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction); + mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity); - LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); + LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); - LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; + LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; - /* LAPRAS + /* LAPRAS We decode these parts of the message but ignore them as the real values are provided elsewhere. */ (void)sun_direction, (void)moon_direction, (void)phase; @@ -3859,396 +3859,396 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) void process_sound_trigger(LLMessageSystem *msg, void **) { - if (!gAudiop) - { + if (!gAudiop) + { #if !LL_LINUX - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; #endif - return; - } - - U64 region_handle = 0; - F32 gain = 0; - LLUUID sound_id; - LLUUID owner_id; - LLUUID object_id; - LLUUID parent_id; - LLVector3 pos_local; - - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); - msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle); - msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local); - msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain); - - // adjust sound location to true global coords - LLVector3d pos_global = from_region_handle(region_handle); - pos_global.mdV[VX] += pos_local.mV[VX]; - pos_global.mdV[VY] += pos_local.mV[VY]; - pos_global.mdV[VZ] += pos_local.mV[VZ]; - - // Don't play a trigger sound if you can't hear it due - // to parcel "local audio only" settings. - if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return; - - // Don't play sounds triggered by someone you muted. - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - // Don't play sounds from an object you muted - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - // Don't play sounds from an object whose parent you muted - if (parent_id.notNull() - && LLMuteList::getInstance()->isMuted(parent_id)) - { - return; - } - - // Don't play sounds from a region with maturity above current agent maturity - if( !gAgent.canAccessMaturityInRegion( region_handle ) ) - { - return; - } - - // Don't play sounds from gestures if they are not enabled. - // Do play sounds triggered by avatar, since muting your own - // gesture sounds and your own sounds played inworld from - // Inventory can cause confusion. - if (object_id == owner_id + return; + } + + U64 region_handle = 0; + F32 gain = 0; + LLUUID sound_id; + LLUUID owner_id; + LLUUID object_id; + LLUUID parent_id; + LLVector3 pos_local; + + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id); + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); + msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle); + msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local); + msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain); + + // adjust sound location to true global coords + LLVector3d pos_global = from_region_handle(region_handle); + pos_global.mdV[VX] += pos_local.mV[VX]; + pos_global.mdV[VY] += pos_local.mV[VY]; + pos_global.mdV[VZ] += pos_local.mV[VZ]; + + // Don't play a trigger sound if you can't hear it due + // to parcel "local audio only" settings. + if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return; + + // Don't play sounds triggered by someone you muted. + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from an object you muted + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + // Don't play sounds from an object whose parent you muted + if (parent_id.notNull() + && LLMuteList::getInstance()->isMuted(parent_id)) + { + return; + } + + // Don't play sounds from a region with maturity above current agent maturity + if( !gAgent.canAccessMaturityInRegion( region_handle ) ) + { + return; + } + + // Don't play sounds from gestures if they are not enabled. + // Do play sounds triggered by avatar, since muting your own + // gesture sounds and your own sounds played inworld from + // Inventory can cause confusion. + if (object_id == owner_id && owner_id != gAgentID && !gSavedSettings.getBOOL("EnableGestureSounds")) - { - return; - } + { + return; + } - if (LLMaterialTable::basic.isCollisionSound(sound_id) && !gSavedSettings.getBOOL("EnableCollisionSounds")) - { - return; - } + if (LLMaterialTable::basic.isCollisionSound(sound_id) && !gSavedSettings.getBOOL("EnableCollisionSounds")) + { + return; + } - gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global); + gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global); } void process_preload_sound(LLMessageSystem *msg, void **user_data) { - if (!gAudiop) - { + if (!gAudiop) + { #if !LL_LINUX - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; #endif - return; - } + return; + } + + LLUUID sound_id; + LLUUID object_id; + LLUUID owner_id; + + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); - LLUUID sound_id; - LLUUID object_id; - LLUUID owner_id; + LLViewerObject *objectp = gObjectList.findObject(object_id); + if (!objectp) return; - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); + if (LLMuteList::getInstance()->isMuted(object_id)) return; + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) return; + LLAudioSource *sourcep = objectp->getAudioSource(owner_id); + if (!sourcep) return; - if (LLMuteList::getInstance()->isMuted(object_id)) return; - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - LLAudioSource *sourcep = objectp->getAudioSource(owner_id); - if (!sourcep) return; - - LLAudioData *datap = gAudiop->getAudioData(sound_id); + LLAudioData *datap = gAudiop->getAudioData(sound_id); - // Note that I don't actually do any loading of the - // audio data into a buffer at this point, as it won't actually - // help us out. + // Note that I don't actually do any loading of the + // audio data into a buffer at this point, as it won't actually + // help us out. - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos_global = objectp->getPositionGlobal(); - if (gAgent.canAccessMaturityAtGlobal(pos_global)) - { - // Add audioData starts a transfer internally. - sourcep->addAudioData(datap, FALSE); - } + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos_global = objectp->getPositionGlobal(); + if (gAgent.canAccessMaturityAtGlobal(pos_global)) + { + // Add audioData starts a transfer internally. + sourcep->addAudioData(datap, FALSE); + } } void process_attached_sound(LLMessageSystem *msg, void **user_data) { - F32 gain = 0; - LLUUID sound_id; - LLUUID object_id; - LLUUID owner_id; - U8 flags; - - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); - msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); - msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); - - LLViewerObject *objectp = gObjectList.findObject(object_id); - if (objectp) - { - set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); - } - else if (sound_id.notNull()) - { - // we don't know about this object yet, probably it has yet to arrive - // std::map for dupplicate prevention. - postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); - clear_expired_postponed_sounds(); - } - else - { - std::map<LLUUID, PostponedSoundData>::iterator iter = postponed_sounds.find(object_id); - if (iter != postponed_sounds.end()) - { - postponed_sounds.erase(iter); - } - } + F32 gain = 0; + LLUUID sound_id; + LLUUID object_id; + LLUUID owner_id; + U8 flags; + + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); + msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); + msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); + + LLViewerObject *objectp = gObjectList.findObject(object_id); + if (objectp) + { + set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); + } + else if (sound_id.notNull()) + { + // we don't know about this object yet, probably it has yet to arrive + // std::map for dupplicate prevention. + postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); + clear_expired_postponed_sounds(); + } + else + { + std::map<LLUUID, PostponedSoundData>::iterator iter = postponed_sounds.find(object_id); + if (iter != postponed_sounds.end()) + { + postponed_sounds.erase(iter); + } + } } void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data) { - F32 gain = 0; - LLUUID object_guid; - LLViewerObject *objectp = NULL; + F32 gain = 0; + LLUUID object_guid; + LLViewerObject *objectp = NULL; - mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); + mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); - if (!((objectp = gObjectList.findObject(object_guid)))) - { - // we don't know about this object, just bail - return; - } + if (!((objectp = gObjectList.findObject(object_guid)))) + { + // we don't know about this object, just bail + return; + } - mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); + mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); - objectp->adjustAudioGain(gain); + objectp->adjustAudioGain(gain); } void process_health_message(LLMessageSystem *mesgsys, void **user_data) { - F32 health; + F32 health; - mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health); + mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health); - if (gStatusBar) - { - gStatusBar->setHealth((S32)health); - } + if (gStatusBar) + { + gStatusBar->setHealth((S32)health); + } } void process_sim_stats(LLMessageSystem *msg, void **user_data) -{ - S32 count = msg->getNumberOfBlocks("Stat"); - for (S32 i = 0; i < count; ++i) - { - U32 stat_id; - F32 stat_value; - msg->getU32("Stat", "StatID", stat_id, i); - msg->getF32("Stat", "StatValue", stat_value, i); - auto measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id); - - if (measurementp ) - { - measurementp->sample(stat_value); - } - else - { - LL_WARNS() << "Unknown sim stat identifier: " << stat_id << LL_ENDL; - } - } - - // - // Various hacks that aren't statistics, but are being handled here. - // - U32 max_tasks_per_region; - U64 region_flags; - msg->getU32("Region", "ObjectCapacity", max_tasks_per_region); - - if (msg->has(_PREHASH_RegionInfo)) - { - msg->getU64("RegionInfo", "RegionFlagsExtended", region_flags); - } - else - { - U32 flags = 0; - msg->getU32("Region", "RegionFlags", flags); - region_flags = flags; - } - - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - BOOL was_flying = gAgent.getFlying(); - regionp->setRegionFlags(region_flags); - regionp->setMaxTasks(max_tasks_per_region); - // HACK: This makes agents drop from the sky if the region is - // set to no fly while people are still in the sim. - if (was_flying && regionp->getBlockFly()) - { - gAgent.setFlying(gAgent.canFly()); - } - } +{ + S32 count = msg->getNumberOfBlocks("Stat"); + for (S32 i = 0; i < count; ++i) + { + U32 stat_id; + F32 stat_value; + msg->getU32("Stat", "StatID", stat_id, i); + msg->getF32("Stat", "StatValue", stat_value, i); + auto measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id); + + if (measurementp ) + { + measurementp->sample(stat_value); + } + else + { + LL_WARNS() << "Unknown sim stat identifier: " << stat_id << LL_ENDL; + } + } + + // + // Various hacks that aren't statistics, but are being handled here. + // + U32 max_tasks_per_region; + U64 region_flags; + msg->getU32("Region", "ObjectCapacity", max_tasks_per_region); + + if (msg->has(_PREHASH_RegionInfo)) + { + msg->getU64("RegionInfo", "RegionFlagsExtended", region_flags); + } + else + { + U32 flags = 0; + msg->getU32("Region", "RegionFlags", flags); + region_flags = flags; + } + + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + BOOL was_flying = gAgent.getFlying(); + regionp->setRegionFlags(region_flags); + regionp->setMaxTasks(max_tasks_per_region); + // HACK: This makes agents drop from the sky if the region is + // set to no fly while people are still in the sim. + if (was_flying && regionp->getBlockFly()) + { + gAgent.setFlying(gAgent.canFly()); + } + } } void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) { - LLUUID animation_id; - LLUUID uuid; - S32 anim_sequence_id; - LLVOAvatar *avatarp = NULL; - - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + LLUUID animation_id; + LLUUID uuid; + S32 anim_sequence_id; + LLVOAvatar *avatarp = NULL; + + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - LLViewerObject *objp = gObjectList.findObject(uuid); + LLViewerObject *objp = gObjectList.findObject(uuid); if (objp) { avatarp = objp->asAvatar(); } - if (!avatarp) - { - // no agent by this ID...error? - LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL; - return; - } - - S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); - S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); - - LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; - - //clear animation flags - avatarp->mSignaledAnimations.clear(); - - if (avatarp->isSelf()) - { - LLUUID object_id; - - for( S32 i = 0; i < num_blocks; i++ ) - { - mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); - mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; - - // *HACK: Disabling flying mode if it has been enabled shortly before the agent - // stand up animation is signaled. In this case we don't get a signal to start - // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the - // avatar does not play flying animation, so we switch flying mode off. - // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink. - // See EXT-2781. - if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying()) - { - gAgent.setFlying(FALSE); - } - - if (i < num_source_blocks) - { - mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i); - - LLViewerObject* object = gObjectList.findObject(object_id); - if (object) - { - object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, TRUE); - - BOOL anim_found = FALSE; - LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); - for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) - { - if (anim_it->first != object_id) - { - // elements with the same key are always contiguous, bail if we went past the - // end of this object's animations - break; - } - if (anim_it->second == animation_id) - { - anim_found = TRUE; - break; - } - } - - if (!anim_found) - { - avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); - } - } - LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id - << " Animation id: " << animation_id - << " From block: " << object_id << LL_ENDL; - } - else - { - LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id - << " Animation id: " << animation_id << LL_ENDL; - } - } - } - else - { - for( S32 i = 0; i < num_blocks; i++ ) - { - mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); - mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; - } - } - - if (num_blocks) - { - avatarp->processAnimationStateChanges(); - } + if (!avatarp) + { + // no agent by this ID...error? + LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL; + return; + } + + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); + S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); + + LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; + + //clear animation flags + avatarp->mSignaledAnimations.clear(); + + if (avatarp->isSelf()) + { + LLUUID object_id; + + for( S32 i = 0; i < num_blocks; i++ ) + { + mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); + mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); + + avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; + + // *HACK: Disabling flying mode if it has been enabled shortly before the agent + // stand up animation is signaled. In this case we don't get a signal to start + // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the + // avatar does not play flying animation, so we switch flying mode off. + // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink. + // See EXT-2781. + if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying()) + { + gAgent.setFlying(FALSE); + } + + if (i < num_source_blocks) + { + mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i); + + LLViewerObject* object = gObjectList.findObject(object_id); + if (object) + { + object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, TRUE); + + BOOL anim_found = FALSE; + LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); + for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) + { + if (anim_it->first != object_id) + { + // elements with the same key are always contiguous, bail if we went past the + // end of this object's animations + break; + } + if (anim_it->second == animation_id) + { + anim_found = TRUE; + break; + } + } + + if (!anim_found) + { + avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); + } + } + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id + << " From block: " << object_id << LL_ENDL; + } + else + { + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id << LL_ENDL; + } + } + } + else + { + for( S32 i = 0; i < num_blocks; i++ ) + { + mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); + mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); + avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; + } + } + + if (num_blocks) + { + avatarp->processAnimationStateChanges(); + } } void process_object_animation(LLMessageSystem *mesgsys, void **user_data) { - LLUUID animation_id; - LLUUID uuid; - S32 anim_sequence_id; - - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + LLUUID animation_id; + LLUUID uuid; + S32 anim_sequence_id; + + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for object " << uuid << LL_ENDL; signaled_animation_map_t signaled_anims; - S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); - LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); + LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; for( S32 i = 0; i < num_blocks; i++ ) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); signaled_anims[animation_id] = anim_sequence_id; - LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object " + LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object " << uuid << " animation id " << animation_id << LL_ENDL; } LLObjectSignaledAnimationMap::instance().getMap()[uuid] = signaled_anims; - + LLViewerObject *objp = gObjectList.findObject(uuid); if (!objp || objp->isDead()) { - LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; return; } - - LLVOVolume *volp = dynamic_cast<LLVOVolume*>(objp); + + LLVOVolume *volp = dynamic_cast<LLVOVolume*>(objp); if (!volp) { - LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; return; } if (!volp->isAnimatedObject()) { - LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; return; } @@ -4259,7 +4259,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) LL_DEBUGS("AnimatedObjectsNotify") << "Received animation request for object with no control avatar, ignoring " << uuid << LL_ENDL; return; } - + if (!avatarp->mPlaying) { avatarp->mPlaying = true; @@ -4269,315 +4269,315 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mRootVolp->recursiveMarkForUpdate(); } } - + avatarp->updateAnimations(); } void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) { - LLUUID uuid; - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + LLUUID uuid; + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); - if (avatarp) - { - avatarp->processAvatarAppearance( mesgsys ); - } - else - { - LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL; - } + LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); + if (avatarp) + { + avatarp->processAvatarAppearance( mesgsys ); + } + else + { + LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL; + } } void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) { - LLVector4 cameraCollidePlane; - mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); + LLVector4 cameraCollidePlane; + mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); - gAgentCamera.setCameraCollidePlane(cameraCollidePlane); + gAgentCamera.setCameraCollidePlane(cameraCollidePlane); } void near_sit_object(BOOL success, void *data) { - if (success) - { - // Send message to sit on object - gMessageSystem->newMessageFast(_PREHASH_AgentSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } + if (success) + { + // Send message to sit on object + gMessageSystem->newMessageFast(_PREHASH_AgentSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + } } void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) { - LLVector3 sitPosition; - LLQuaternion sitRotation; - LLUUID sitObjectID; - BOOL use_autopilot; - mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID); - mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot); - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition); - mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation); - LLVector3 camera_eye; - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye); - LLVector3 camera_at; - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at); - BOOL force_mouselook; - mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); - - if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > CAMERA_POSITION_THRESHOLD_SQUARED) - { - gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); - } - - gAgentCamera.setForceMouselook(force_mouselook); - // Forcing turning off flying here to prevent flying after pressing "Stand" - // to stand up from an object. See EXT-1655. - gAgent.setFlying(FALSE); - - LLViewerObject* object = gObjectList.findObject(sitObjectID); - if (object) - { - LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); - if (!use_autopilot || (isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot())) - { - //we're already sitting on this object, so don't autopilot - } - else - { - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); - } - } - else - { - LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL; - } + LLVector3 sitPosition; + LLQuaternion sitRotation; + LLUUID sitObjectID; + BOOL use_autopilot; + mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID); + mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot); + mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition); + mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation); + LLVector3 camera_eye; + mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye); + LLVector3 camera_at; + mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at); + BOOL force_mouselook; + mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); + + if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > CAMERA_POSITION_THRESHOLD_SQUARED) + { + gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); + } + + gAgentCamera.setForceMouselook(force_mouselook); + // Forcing turning off flying here to prevent flying after pressing "Stand" + // to stand up from an object. See EXT-1655. + gAgent.setFlying(FALSE); + + LLViewerObject* object = gObjectList.findObject(sitObjectID); + if (object) + { + LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); + if (!use_autopilot || (isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot())) + { + //we're already sitting on this object, so don't autopilot + } + else + { + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); + } + } + else + { + LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL; + } } void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) { - LLUUID source_id; + LLUUID source_id; - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - LLFollowCamMgr::getInstance()->removeFollowCamParams(source_id); + LLFollowCamMgr::getInstance()->removeFollowCamParams(source_id); } void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) { - S32 type; - F32 value; - bool settingPosition = false; - bool settingFocus = false; - bool settingFocusOffset = false; - LLVector3 position; - LLVector3 focus; - LLVector3 focus_offset; - - LLUUID source_id; - - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - - LLViewerObject* objectp = gObjectList.findObject(source_id); - if (objectp) - { - objectp->setFlagsWithoutUpdate(FLAGS_CAMERA_SOURCE, TRUE); - } - - S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); - for (S32 block_index = 0; block_index < num_objects; block_index++) - { - mesgsys->getS32("CameraProperty", "Type", type, block_index); - mesgsys->getF32("CameraProperty", "Value", value, block_index); - switch(type) - { - case FOLLOWCAM_PITCH: - LLFollowCamMgr::getInstance()->setPitch(source_id, value); - break; - case FOLLOWCAM_FOCUS_OFFSET_X: - focus_offset.mV[VX] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_FOCUS_OFFSET_Y: - focus_offset.mV[VY] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_FOCUS_OFFSET_Z: - focus_offset.mV[VZ] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_POSITION_LAG: - LLFollowCamMgr::getInstance()->setPositionLag(source_id, value); - break; - case FOLLOWCAM_FOCUS_LAG: - LLFollowCamMgr::getInstance()->setFocusLag(source_id, value); - break; - case FOLLOWCAM_DISTANCE: - LLFollowCamMgr::getInstance()->setDistance(source_id, value); - break; - case FOLLOWCAM_BEHINDNESS_ANGLE: - LLFollowCamMgr::getInstance()->setBehindnessAngle(source_id, value); - break; - case FOLLOWCAM_BEHINDNESS_LAG: - LLFollowCamMgr::getInstance()->setBehindnessLag(source_id, value); - break; - case FOLLOWCAM_POSITION_THRESHOLD: - LLFollowCamMgr::getInstance()->setPositionThreshold(source_id, value); - break; - case FOLLOWCAM_FOCUS_THRESHOLD: - LLFollowCamMgr::getInstance()->setFocusThreshold(source_id, value); - break; - case FOLLOWCAM_ACTIVE: - //if 1, set using followcam,. - LLFollowCamMgr::getInstance()->setCameraActive(source_id, value != 0.f); - break; - case FOLLOWCAM_POSITION_X: - settingPosition = true; - position.mV[ 0 ] = value; - break; - case FOLLOWCAM_POSITION_Y: - settingPosition = true; - position.mV[ 1 ] = value; - break; - case FOLLOWCAM_POSITION_Z: - settingPosition = true; - position.mV[ 2 ] = value; - break; - case FOLLOWCAM_FOCUS_X: - settingFocus = true; - focus.mV[ 0 ] = value; - break; - case FOLLOWCAM_FOCUS_Y: - settingFocus = true; - focus.mV[ 1 ] = value; - break; - case FOLLOWCAM_FOCUS_Z: - settingFocus = true; - focus.mV[ 2 ] = value; - break; - case FOLLOWCAM_POSITION_LOCKED: - LLFollowCamMgr::getInstance()->setPositionLocked(source_id, value != 0.f); - break; - case FOLLOWCAM_FOCUS_LOCKED: - LLFollowCamMgr::getInstance()->setFocusLocked(source_id, value != 0.f); - break; - - default: - break; - } - } - - if ( settingPosition ) - { - LLFollowCamMgr::getInstance()->setPosition(source_id, position); - } - if ( settingFocus ) - { - LLFollowCamMgr::getInstance()->setFocus(source_id, focus); - } - if ( settingFocusOffset ) - { - LLFollowCamMgr::getInstance()->setFocusOffset(source_id, focus_offset); - } -} -//end Ventrella + S32 type; + F32 value; + bool settingPosition = false; + bool settingFocus = false; + bool settingFocusOffset = false; + LLVector3 position; + LLVector3 focus; + LLVector3 focus_offset; + + LLUUID source_id; + + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); + + LLViewerObject* objectp = gObjectList.findObject(source_id); + if (objectp) + { + objectp->setFlagsWithoutUpdate(FLAGS_CAMERA_SOURCE, TRUE); + } + + S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); + for (S32 block_index = 0; block_index < num_objects; block_index++) + { + mesgsys->getS32("CameraProperty", "Type", type, block_index); + mesgsys->getF32("CameraProperty", "Value", value, block_index); + switch(type) + { + case FOLLOWCAM_PITCH: + LLFollowCamMgr::getInstance()->setPitch(source_id, value); + break; + case FOLLOWCAM_FOCUS_OFFSET_X: + focus_offset.mV[VX] = value; + settingFocusOffset = true; + break; + case FOLLOWCAM_FOCUS_OFFSET_Y: + focus_offset.mV[VY] = value; + settingFocusOffset = true; + break; + case FOLLOWCAM_FOCUS_OFFSET_Z: + focus_offset.mV[VZ] = value; + settingFocusOffset = true; + break; + case FOLLOWCAM_POSITION_LAG: + LLFollowCamMgr::getInstance()->setPositionLag(source_id, value); + break; + case FOLLOWCAM_FOCUS_LAG: + LLFollowCamMgr::getInstance()->setFocusLag(source_id, value); + break; + case FOLLOWCAM_DISTANCE: + LLFollowCamMgr::getInstance()->setDistance(source_id, value); + break; + case FOLLOWCAM_BEHINDNESS_ANGLE: + LLFollowCamMgr::getInstance()->setBehindnessAngle(source_id, value); + break; + case FOLLOWCAM_BEHINDNESS_LAG: + LLFollowCamMgr::getInstance()->setBehindnessLag(source_id, value); + break; + case FOLLOWCAM_POSITION_THRESHOLD: + LLFollowCamMgr::getInstance()->setPositionThreshold(source_id, value); + break; + case FOLLOWCAM_FOCUS_THRESHOLD: + LLFollowCamMgr::getInstance()->setFocusThreshold(source_id, value); + break; + case FOLLOWCAM_ACTIVE: + //if 1, set using followcam,. + LLFollowCamMgr::getInstance()->setCameraActive(source_id, value != 0.f); + break; + case FOLLOWCAM_POSITION_X: + settingPosition = true; + position.mV[ 0 ] = value; + break; + case FOLLOWCAM_POSITION_Y: + settingPosition = true; + position.mV[ 1 ] = value; + break; + case FOLLOWCAM_POSITION_Z: + settingPosition = true; + position.mV[ 2 ] = value; + break; + case FOLLOWCAM_FOCUS_X: + settingFocus = true; + focus.mV[ 0 ] = value; + break; + case FOLLOWCAM_FOCUS_Y: + settingFocus = true; + focus.mV[ 1 ] = value; + break; + case FOLLOWCAM_FOCUS_Z: + settingFocus = true; + focus.mV[ 2 ] = value; + break; + case FOLLOWCAM_POSITION_LOCKED: + LLFollowCamMgr::getInstance()->setPositionLocked(source_id, value != 0.f); + break; + case FOLLOWCAM_FOCUS_LOCKED: + LLFollowCamMgr::getInstance()->setFocusLocked(source_id, value != 0.f); + break; + + default: + break; + } + } + + if ( settingPosition ) + { + LLFollowCamMgr::getInstance()->setPosition(source_id, position); + } + if ( settingFocus ) + { + LLFollowCamMgr::getInstance()->setFocus(source_id, focus); + } + if ( settingFocusOffset ) + { + LLFollowCamMgr::getInstance()->setFocusOffset(source_id, focus_offset); + } +} +//end Ventrella // Culled from newsim lltask.cpp void process_name_value(LLMessageSystem *mesgsys, void **user_data) { - std::string temp_str; - LLUUID id; - S32 i, num_blocks; + std::string temp_str; + LLUUID id; + S32 i, num_blocks; - mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); + mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); - LLViewerObject* object = gObjectList.findObject(id); + LLViewerObject* object = gObjectList.findObject(id); - if (object) - { - num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); - for (i = 0; i < num_blocks; i++) - { - mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); - LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL; - object->addNVPair(temp_str); - } - } - else - { - LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL; - } + if (object) + { + num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); + for (i = 0; i < num_blocks; i++) + { + mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); + LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL; + object->addNVPair(temp_str); + } + } + else + { + LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL; + } } void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) { - std::string temp_str; - LLUUID id; - S32 i, num_blocks; + std::string temp_str; + LLUUID id; + S32 i, num_blocks; - mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); + mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); - LLViewerObject* object = gObjectList.findObject(id); + LLViewerObject* object = gObjectList.findObject(id); - if (object) - { - num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); - for (i = 0; i < num_blocks; i++) - { - mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); - LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL; - object->removeNVPair(temp_str); - } - } - else - { - LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL; - } + if (object) + { + num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); + for (i = 0; i < num_blocks; i++) + { + mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); + LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL; + object->removeNVPair(temp_str); + } + } + else + { + LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL; + } } void process_kick_user(LLMessageSystem *msg, void** /*user_data*/) { - std::string message; + std::string message; - msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, message); + msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, message); - LLAppViewer::instance()->forceDisconnect(message); + LLAppViewer::instance()->forceDisconnect(message); } /* void process_user_list_reply(LLMessageSystem *msg, void **user_data) { - LLUserList::processUserListReply(msg, user_data); - return; - char firstname[MAX_STRING+1]; - char lastname[MAX_STRING+1]; - U8 status; - S32 user_count; - - user_count = msg->getNumberOfBlocks("UserBlock"); - - for (S32 i = 0; i < user_count; i++) - { - msg->getData("UserBlock", i, "FirstName", firstname); - msg->getData("UserBlock", i, "LastName", lastname); - msg->getData("UserBlock", i, "Status", &status); - - if (status & 0x01) - { - dialog_friends_add_friend(buffer, TRUE); - } - else - { - dialog_friends_add_friend(buffer, FALSE); - } - } - - dialog_friends_done_adding(); + LLUserList::processUserListReply(msg, user_data); + return; + char firstname[MAX_STRING+1]; + char lastname[MAX_STRING+1]; + U8 status; + S32 user_count; + + user_count = msg->getNumberOfBlocks("UserBlock"); + + for (S32 i = 0; i < user_count; i++) + { + msg->getData("UserBlock", i, "FirstName", firstname); + msg->getData("UserBlock", i, "LastName", lastname); + msg->getData("UserBlock", i, "Status", &status); + + if (status & 0x01) + { + dialog_friends_add_friend(buffer, TRUE); + } + else + { + dialog_friends_add_friend(buffer, FALSE); + } + } + + dialog_friends_done_adding(); } */ @@ -4585,635 +4585,635 @@ void process_user_list_reply(LLMessageSystem *msg, void **user_data) /* void process_time_dilation(LLMessageSystem *msg, void **user_data) { - // get the time_dilation - U16 foo; - msg->getData("TimeDilation", "TimeDilation", &foo); - F32 time_dilation = ((F32) foo) / 65535.f; + // get the time_dilation + U16 foo; + msg->getData("TimeDilation", "TimeDilation", &foo); + F32 time_dilation = ((F32) foo) / 65535.f; - // get the pointer to the right region - U32 ip = msg->getSenderIP(); - U32 port = msg->getSenderPort(); - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port); - if (regionp) - { - regionp->setTimeDilation(time_dilation); - } + // get the pointer to the right region + U32 ip = msg->getSenderIP(); + U32 port = msg->getSenderPort(); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port); + if (regionp) + { + regionp->setTimeDilation(time_dilation); + } } */ void process_money_balance_reply( LLMessageSystem* msg, void** ) { - S32 balance = 0; - S32 credit = 0; - S32 committed = 0; - std::string desc; - LLUUID tid; - - msg->getUUID("MoneyData", "TransactionID", tid); - msg->getS32("MoneyData", "MoneyBalance", balance); - msg->getS32("MoneyData", "SquareMetersCredit", credit); - msg->getS32("MoneyData", "SquareMetersCommitted", committed); - msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc); - LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " " - << committed << LL_ENDL; - - if (gStatusBar) - { - gStatusBar->setBalance(balance); - gStatusBar->setLandCredit(credit); - gStatusBar->setLandCommitted(committed); - } - - if (desc.empty() - || !gSavedSettings.getBOOL("NotifyMoneyChange")) - { - // ...nothing to display - return; - } - - // Suppress duplicate messages about the same transaction - static std::deque<LLUUID> recent; - if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend()) - { - return; - } - - // Once the 'recent' container gets large enough, chop some - // off the beginning. - const U32 MAX_LOOKBACK = 30; - const S32 POP_FRONT_SIZE = 12; - if(recent.size() > MAX_LOOKBACK) - { - LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; - recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); - } - //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; - recent.push_back(tid); - - if (msg->has("TransactionInfo")) - { - // ...message has extended info for localization - process_money_balance_reply_extended(msg); - } - else - { - // Only old dev grids will not supply the TransactionInfo block, - // so we can just use the hard-coded English string. - LLSD args; - args["MESSAGE"] = desc; - LLNotificationsUtil::add("SystemMessage", args); - } + S32 balance = 0; + S32 credit = 0; + S32 committed = 0; + std::string desc; + LLUUID tid; + + msg->getUUID("MoneyData", "TransactionID", tid); + msg->getS32("MoneyData", "MoneyBalance", balance); + msg->getS32("MoneyData", "SquareMetersCredit", credit); + msg->getS32("MoneyData", "SquareMetersCommitted", committed); + msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc); + LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " " + << committed << LL_ENDL; + + if (gStatusBar) + { + gStatusBar->setBalance(balance); + gStatusBar->setLandCredit(credit); + gStatusBar->setLandCommitted(committed); + } + + if (desc.empty() + || !gSavedSettings.getBOOL("NotifyMoneyChange")) + { + // ...nothing to display + return; + } + + // Suppress duplicate messages about the same transaction + static std::deque<LLUUID> recent; + if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend()) + { + return; + } + + // Once the 'recent' container gets large enough, chop some + // off the beginning. + const U32 MAX_LOOKBACK = 30; + const S32 POP_FRONT_SIZE = 12; + if(recent.size() > MAX_LOOKBACK) + { + LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; + recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); + } + //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; + recent.push_back(tid); + + if (msg->has("TransactionInfo")) + { + // ...message has extended info for localization + process_money_balance_reply_extended(msg); + } + else + { + // Only old dev grids will not supply the TransactionInfo block, + // so we can just use the hard-coded English string. + LLSD args; + args["MESSAGE"] = desc; + LLNotificationsUtil::add("SystemMessage", args); + } } static std::string reason_from_transaction_type(S32 transaction_type, - const std::string& item_desc) -{ - // *NOTE: The keys for the reason strings are unusual because - // an earlier version of the code used English language strings - // extracted from hard-coded server English descriptions. - // Keeping them so we don't have to re-localize them. - switch (transaction_type) - { - case TRANS_OBJECT_SALE: - { - LLStringUtil::format_map_t arg; - arg["ITEM"] = item_desc; - return LLTrans::getString("for item", arg); - } - case TRANS_LAND_SALE: - return LLTrans::getString("for a parcel of land"); - - case TRANS_LAND_PASS_SALE: - return LLTrans::getString("for a land access pass"); - - case TRANS_GROUP_LAND_DEED: - return LLTrans::getString("for deeding land"); - - case TRANS_GROUP_CREATE: - return LLTrans::getString("to create a group"); - - case TRANS_GROUP_JOIN: - return LLTrans::getString("to join a group"); - - case TRANS_UPLOAD_CHARGE: - return LLTrans::getString("to upload"); - - case TRANS_CLASSIFIED_CHARGE: - return LLTrans::getString("to publish a classified ad"); - - case TRANS_GIFT: - // Simulator returns "Payment" if no custom description has been entered - return (item_desc == "Payment" ? std::string() : item_desc); - - // These have no reason to display, but are expected and should not - // generate warnings - case TRANS_PAY_OBJECT: - case TRANS_OBJECT_PAYS: - return std::string(); - - default: - LL_WARNS() << "Unknown transaction type " - << transaction_type << LL_ENDL; - return std::string(); - } + const std::string& item_desc) +{ + // *NOTE: The keys for the reason strings are unusual because + // an earlier version of the code used English language strings + // extracted from hard-coded server English descriptions. + // Keeping them so we don't have to re-localize them. + switch (transaction_type) + { + case TRANS_OBJECT_SALE: + { + LLStringUtil::format_map_t arg; + arg["ITEM"] = item_desc; + return LLTrans::getString("for item", arg); + } + case TRANS_LAND_SALE: + return LLTrans::getString("for a parcel of land"); + + case TRANS_LAND_PASS_SALE: + return LLTrans::getString("for a land access pass"); + + case TRANS_GROUP_LAND_DEED: + return LLTrans::getString("for deeding land"); + + case TRANS_GROUP_CREATE: + return LLTrans::getString("to create a group"); + + case TRANS_GROUP_JOIN: + return LLTrans::getString("to join a group"); + + case TRANS_UPLOAD_CHARGE: + return LLTrans::getString("to upload"); + + case TRANS_CLASSIFIED_CHARGE: + return LLTrans::getString("to publish a classified ad"); + + case TRANS_GIFT: + // Simulator returns "Payment" if no custom description has been entered + return (item_desc == "Payment" ? std::string() : item_desc); + + // These have no reason to display, but are expected and should not + // generate warnings + case TRANS_PAY_OBJECT: + case TRANS_OBJECT_PAYS: + return std::string(); + + default: + LL_WARNS() << "Unknown transaction type " + << transaction_type << LL_ENDL; + return std::string(); + } } static void money_balance_group_notify(const LLUUID& group_id, - const std::string& name, - bool is_group, - std::string notification, - LLSD args, - LLSD payload) + const std::string& name, + bool is_group, + std::string notification, + LLSD args, + LLSD payload) { - // Message uses name SLURLs, don't actually have to substitute in - // the name. We're just making sure it's available. - // Notification is either PaymentReceived or PaymentSent - LLNotificationsUtil::add(notification, args, payload); + // Message uses name SLURLs, don't actually have to substitute in + // the name. We're just making sure it's available. + // Notification is either PaymentReceived or PaymentSent + LLNotificationsUtil::add(notification, args, payload); } static void money_balance_avatar_notify(const LLUUID& agent_id, - const LLAvatarName& av_name, - std::string notification, - LLSD args, - LLSD payload) + const LLAvatarName& av_name, + std::string notification, + LLSD args, + LLSD payload) { - // Message uses name SLURLs, don't actually have to substitute in - // the name. We're just making sure it's available. - // Notification is either PaymentReceived or PaymentSent - LLNotificationsUtil::add(notification, args, payload); + // Message uses name SLURLs, don't actually have to substitute in + // the name. We're just making sure it's available. + // Notification is either PaymentReceived or PaymentSent + LLNotificationsUtil::add(notification, args, payload); } -static void process_money_balance_reply_extended(LLMessageSystem* msg) -{ - // Added in server 1.40 and viewer 2.1, support for localization - // and agent ids for name lookup. - S32 transaction_type = 0; - LLUUID source_id; - BOOL is_source_group = FALSE; - LLUUID dest_id; - BOOL is_dest_group = FALSE; - S32 amount = 0; - std::string item_description; - BOOL success = FALSE; +static void process_money_balance_reply_extended(LLMessageSystem* msg) +{ + // Added in server 1.40 and viewer 2.1, support for localization + // and agent ids for name lookup. + S32 transaction_type = 0; + LLUUID source_id; + BOOL is_source_group = FALSE; + LLUUID dest_id; + BOOL is_dest_group = FALSE; + S32 amount = 0; + std::string item_description; + BOOL success = FALSE; + + msg->getS32("TransactionInfo", "TransactionType", transaction_type); + msg->getUUID("TransactionInfo", "SourceID", source_id); + msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group); + msg->getUUID("TransactionInfo", "DestID", dest_id); + msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); + msg->getS32("TransactionInfo", "Amount", amount); + msg->getString("TransactionInfo", "ItemDescription", item_description); + msg->getBOOL("MoneyData", "TransactionSuccess", success); + LL_INFOS("Money") << "MoneyBalanceReply source " << source_id + << " dest " << dest_id + << " type " << transaction_type + << " item " << item_description << LL_ENDL; + + if (source_id.isNull() && dest_id.isNull()) + { + // this is a pure balance update, no notification required + return; + } + + std::string source_slurl; + if (is_source_group) + { + source_slurl = + LLSLURL( "group", source_id, "inspect").getSLURLString(); + } + else + { + source_slurl = + LLSLURL( "agent", source_id, "completename").getSLURLString(); + } + + std::string dest_slurl; + if (is_dest_group) + { + dest_slurl = + LLSLURL( "group", dest_id, "inspect").getSLURLString(); + } + else + { + dest_slurl = + LLSLURL( "agent", dest_id, "completename").getSLURLString(); + } + + std::string reason = + reason_from_transaction_type(transaction_type, item_description); + + LLStringUtil::format_map_t args; + args["REASON"] = reason; // could be empty + args["AMOUNT"] = llformat("%d", amount); + + // Need to delay until name looked up, so need to know whether or not + // is group + bool is_name_group = false; + LLUUID name_id; + std::string message; + std::string notification; + LLSD final_args; + LLSD payload; + + bool you_paid_someone = (source_id == gAgentID); + std::string gift_suffix = (transaction_type == TRANS_GIFT ? "_gift" : ""); + if (you_paid_someone) + { + if(!gSavedSettings.getBOOL("NotifyMoneySpend")) + { + return; + } + args["NAME"] = dest_slurl; + is_name_group = is_dest_group; + name_id = dest_id; + if (!reason.empty()) + { + if (dest_id.notNull()) + { + message = success ? LLTrans::getString("you_paid_ldollars" + gift_suffix, args) : + LLTrans::getString("you_paid_failure_ldollars" + gift_suffix, args); + } + else + { + // transaction fee to the system, eg, to create a group + message = success ? LLTrans::getString("you_paid_ldollars_no_name", args) : + LLTrans::getString("you_paid_failure_ldollars_no_name", args); + } + } + else + { + if (dest_id.notNull()) + { + message = success ? LLTrans::getString("you_paid_ldollars_no_reason", args) : + LLTrans::getString("you_paid_failure_ldollars_no_reason", args); + } + else + { + // no target, no reason, you just paid money + message = success ? LLTrans::getString("you_paid_ldollars_no_info", args) : + LLTrans::getString("you_paid_failure_ldollars_no_info", args); + } + } + final_args["MESSAGE"] = message; + payload["dest_id"] = dest_id; + notification = success ? "PaymentSent" : "PaymentFailure"; + } + else + { + // ...someone paid you + if(!gSavedSettings.getBOOL("NotifyMoneyReceived")) + { + return; + } + args["NAME"] = source_slurl; + is_name_group = is_source_group; + name_id = source_id; + + if (!reason.empty() && !LLMuteList::getInstance()->isMuted(source_id)) + { + message = LLTrans::getString("paid_you_ldollars" + gift_suffix, args); + } + else + { + message = LLTrans::getString("paid_you_ldollars_no_reason", args); + } + final_args["MESSAGE"] = message; + + // make notification loggable + payload["from_id"] = source_id; + notification = "PaymentReceived"; + } + + // Despite using SLURLs, wait until the name is available before + // showing the notification, otherwise the UI layout is strange and + // the user sees a "Loading..." message + if (is_name_group) + { + gCacheName->getGroup(name_id, + boost::bind(&money_balance_group_notify, + _1, _2, _3, + notification, final_args, payload)); + } + else + { + LLAvatarNameCache::get(name_id, boost::bind(&money_balance_avatar_notify, _1, _2, notification, final_args, payload)); + } +} + +bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + // set the preference to the maturity of the region we're calling + U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); + } + + return false; +} + +bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + // set the preference to the maturity of the region we're calling + U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); + gAgent.setMaturityRatingChangeDuringTeleport(preferredMaturity); + gAgent.restartFailedTeleportRequest(); + } + else + { + gAgent.clearTeleportRequest(); + } + + return false; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) +{ + bool returnValue = false; + if(llsdBlock.has("_region_access")) + { + U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + + if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + } + + return returnValue; +} + +bool handle_trusted_experiences_notification(const LLSD& llsdBlock) +{ + if(llsdBlock.has("trusted_experiences")) + { + std::ostringstream str; + const LLSD& experiences = llsdBlock["trusted_experiences"]; + LLSD::array_const_iterator it = experiences.beginArray(); + for(/**/; it != experiences.endArray(); ++it) + { + str<<LLSLURL("experience", it->asUUID(), "profile").getSLURLString() << "\n"; + } + std::string str_list = str.str(); + if(!str_list.empty()) + { + LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list)); + return true; + } + } + return false; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage) +{ + bool returnValue = false; + if(llsdBlock.has("_region_access")) + { + U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + + LLNotificationPtr tp_failure_notification; + std::string notifySuffix; + + if (notificationID == std::string("TeleportEntryAccessBlocked")) + { + notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + } // End of special handling for "TeleportEntryAccessBlocked" + else + { // Normal case, no message munging + gAgent.clearTeleportRequest(); + if (LLNotifications::getInstance()->templateExists(notificationID)) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); + } + else + { + llsdBlock["MESSAGE"] = defaultMessage; + tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); + } + returnValue = true; + } + + if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored()) + { + // Given a simple notification if no tp_failure_notification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + } - msg->getS32("TransactionInfo", "TransactionType", transaction_type); - msg->getUUID("TransactionInfo", "SourceID", source_id); - msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group); - msg->getUUID("TransactionInfo", "DestID", dest_id); - msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); - msg->getS32("TransactionInfo", "Amount", amount); - msg->getString("TransactionInfo", "ItemDescription", item_description); - msg->getBOOL("MoneyData", "TransactionSuccess", success); - LL_INFOS("Money") << "MoneyBalanceReply source " << source_id - << " dest " << dest_id - << " type " << transaction_type - << " item " << item_description << LL_ENDL; - - if (source_id.isNull() && dest_id.isNull()) - { - // this is a pure balance update, no notification required - return; - } - - std::string source_slurl; - if (is_source_group) - { - source_slurl = - LLSLURL( "group", source_id, "inspect").getSLURLString(); - } - else - { - source_slurl = - LLSLURL( "agent", source_id, "completename").getSLURLString(); - } - - std::string dest_slurl; - if (is_dest_group) - { - dest_slurl = - LLSLURL( "group", dest_id, "inspect").getSLURLString(); - } - else - { - dest_slurl = - LLSLURL( "agent", dest_id, "completename").getSLURLString(); - } - - std::string reason = - reason_from_transaction_type(transaction_type, item_description); - - LLStringUtil::format_map_t args; - args["REASON"] = reason; // could be empty - args["AMOUNT"] = llformat("%d", amount); - - // Need to delay until name looked up, so need to know whether or not - // is group - bool is_name_group = false; - LLUUID name_id; - std::string message; - std::string notification; - LLSD final_args; - LLSD payload; - - bool you_paid_someone = (source_id == gAgentID); - std::string gift_suffix = (transaction_type == TRANS_GIFT ? "_gift" : ""); - if (you_paid_someone) - { - if(!gSavedSettings.getBOOL("NotifyMoneySpend")) - { - return; - } - args["NAME"] = dest_slurl; - is_name_group = is_dest_group; - name_id = dest_id; - if (!reason.empty()) - { - if (dest_id.notNull()) - { - message = success ? LLTrans::getString("you_paid_ldollars" + gift_suffix, args) : - LLTrans::getString("you_paid_failure_ldollars" + gift_suffix, args); - } - else - { - // transaction fee to the system, eg, to create a group - message = success ? LLTrans::getString("you_paid_ldollars_no_name", args) : - LLTrans::getString("you_paid_failure_ldollars_no_name", args); - } - } - else - { - if (dest_id.notNull()) - { - message = success ? LLTrans::getString("you_paid_ldollars_no_reason", args) : - LLTrans::getString("you_paid_failure_ldollars_no_reason", args); - } - else - { - // no target, no reason, you just paid money - message = success ? LLTrans::getString("you_paid_ldollars_no_info", args) : - LLTrans::getString("you_paid_failure_ldollars_no_info", args); - } - } - final_args["MESSAGE"] = message; - payload["dest_id"] = dest_id; - notification = success ? "PaymentSent" : "PaymentFailure"; - } - else - { - // ...someone paid you - if(!gSavedSettings.getBOOL("NotifyMoneyReceived")) - { - return; - } - args["NAME"] = source_slurl; - is_name_group = is_source_group; - name_id = source_id; - - if (!reason.empty() && !LLMuteList::getInstance()->isMuted(source_id)) - { - message = LLTrans::getString("paid_you_ldollars" + gift_suffix, args); - } - else - { - message = LLTrans::getString("paid_you_ldollars_no_reason", args); - } - final_args["MESSAGE"] = message; - - // make notification loggable - payload["from_id"] = source_id; - notification = "PaymentReceived"; - } - - // Despite using SLURLs, wait until the name is available before - // showing the notification, otherwise the UI layout is strange and - // the user sees a "Loading..." message - if (is_name_group) - { - gCacheName->getGroup(name_id, - boost::bind(&money_balance_group_notify, - _1, _2, _3, - notification, final_args, payload)); - } - else - { - LLAvatarNameCache::get(name_id, boost::bind(&money_balance_avatar_notify, _1, _2, notification, final_args, payload)); - } + handle_trusted_experiences_notification(llsdBlock); + return returnValue; } -bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) +bool attempt_standard_notification(LLMessageSystem* msgsystem) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - // set the preference to the maturity of the region we're calling - U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); - gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); - } + // if we have additional alert data + if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) + { + // notification was specified using the new mechanism, so we can just handle it here + std::string notificationID; + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + + //SL-13824 skip notification when both joining a group and leaving a group + //remove this after server stops sending these messages + if (notificationID == "JoinGroupSuccess" || + notificationID == "GroupDepart") + { + return true; + } - return false; -} + if (!LLNotifications::getInstance()->templateExists(notificationID)) + { + return false; + } -bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - // set the preference to the maturity of the region we're calling - U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); - gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); - gAgent.setMaturityRatingChangeDuringTeleport(preferredMaturity); - gAgent.restartFailedTeleportRequest(); - } - else - { - gAgent.clearTeleportRequest(); - } - - return false; -} + std::string llsdRaw; + LLSD llsdBlock; + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); + if (llsdRaw.length()) + { + std::istringstream llsdData(llsdRaw); + if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length())) + { + LL_WARNS() << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + } + } -// some of the server notifications need special handling. This is where we do that. -bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) -{ - bool returnValue = false; - if(llsdBlock.has("_region_access")) - { - U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - LLNotificationPtr maturityLevelNotification; - std::string notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) - { - if (gAgent.isTeen()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG()) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; - } - } - - if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) - { - // Given a simple notification if no maturityLevelNotification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); - } - } - - return returnValue; -} -bool handle_trusted_experiences_notification(const LLSD& llsdBlock) -{ - if(llsdBlock.has("trusted_experiences")) - { - std::ostringstream str; - const LLSD& experiences = llsdBlock["trusted_experiences"]; - LLSD::array_const_iterator it = experiences.beginArray(); - for(/**/; it != experiences.endArray(); ++it) - { - str<<LLSLURL("experience", it->asUUID(), "profile").getSLURLString() << "\n"; - } - std::string str_list = str.str(); - if(!str_list.empty()) - { - LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list)); - return true; - } - } - return false; -} + handle_trusted_experiences_notification(llsdBlock); -// some of the server notifications need special handling. This is where we do that. -bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage) -{ - bool returnValue = false; - if(llsdBlock.has("_region_access")) - { - U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - - LLNotificationPtr tp_failure_notification; - std::string notifySuffix; - - if (notificationID == std::string("TeleportEntryAccessBlocked")) - { - notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) - { - if (gAgent.isTeen()) - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG()) - { - if (gAgent.hasRestartableFailedTeleportRequest()) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - if (gAgent.hasRestartableFailedTeleportRequest()) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - } // End of special handling for "TeleportEntryAccessBlocked" - else - { // Normal case, no message munging - gAgent.clearTeleportRequest(); - if (LLNotifications::getInstance()->templateExists(notificationID)) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); - } - else - { - llsdBlock["MESSAGE"] = defaultMessage; - tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); - } - returnValue = true; - } - - if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored()) - { - // Given a simple notification if no tp_failure_notification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); - } - } - - handle_trusted_experiences_notification(llsdBlock); - return returnValue; -} + if ( + (notificationID == "RegionEntryAccessBlocked") || + (notificationID == "LandClaimAccessBlocked") || + (notificationID == "LandBuyAccessBlocked") -bool attempt_standard_notification(LLMessageSystem* msgsystem) -{ - // if we have additional alert data - if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) - { - // notification was specified using the new mechanism, so we can just handle it here - std::string notificationID; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); - - //SL-13824 skip notification when both joining a group and leaving a group - //remove this after server stops sending these messages - if (notificationID == "JoinGroupSuccess" || - notificationID == "GroupDepart") - { - return true; - } - - if (!LLNotifications::getInstance()->templateExists(notificationID)) - { - return false; - } - - std::string llsdRaw; - LLSD llsdBlock; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); - if (llsdRaw.length()) - { - std::istringstream llsdData(llsdRaw); - if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length())) - { - LL_WARNS() << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; - } - } - - - handle_trusted_experiences_notification(llsdBlock); - - if ( - (notificationID == "RegionEntryAccessBlocked") || - (notificationID == "LandClaimAccessBlocked") || - (notificationID == "LandBuyAccessBlocked") - - ) - { - /*--------------------------------------------------------------------- - (Commented so a grep will find the notification strings, since - we construct them on the fly; if you add additional notifications, - please update the comment.) - - Could throw any of the following notifications: - - RegionEntryAccessBlocked - RegionEntryAccessBlocked_Notify - RegionEntryAccessBlocked_NotifyAdultsOnly - RegionEntryAccessBlocked_Change - RegionEntryAccessBlocked_AdultsOnlyContent - RegionEntryAccessBlocked_ChangeAndReTeleport - LandClaimAccessBlocked - LandClaimAccessBlocked_Notify - LandClaimAccessBlocked_NotifyAdultsOnly - LandClaimAccessBlocked_Change - LandClaimAccessBlocked_AdultsOnlyContent - LandBuyAccessBlocked - LandBuyAccessBlocked_Notify - LandBuyAccessBlocked_NotifyAdultsOnly - LandBuyAccessBlocked_Change - LandBuyAccessBlocked_AdultsOnlyContent - - -----------------------------------------------------------------------*/ + ) + { + /*--------------------------------------------------------------------- + (Commented so a grep will find the notification strings, since + we construct them on the fly; if you add additional notifications, + please update the comment.) + + Could throw any of the following notifications: + + RegionEntryAccessBlocked + RegionEntryAccessBlocked_Notify + RegionEntryAccessBlocked_NotifyAdultsOnly + RegionEntryAccessBlocked_Change + RegionEntryAccessBlocked_AdultsOnlyContent + RegionEntryAccessBlocked_ChangeAndReTeleport + LandClaimAccessBlocked + LandClaimAccessBlocked_Notify + LandClaimAccessBlocked_NotifyAdultsOnly + LandClaimAccessBlocked_Change + LandClaimAccessBlocked_AdultsOnlyContent + LandBuyAccessBlocked + LandBuyAccessBlocked_Notify + LandBuyAccessBlocked_NotifyAdultsOnly + LandBuyAccessBlocked_Change + LandBuyAccessBlocked_AdultsOnlyContent + + -----------------------------------------------------------------------*/ static LLCachedControl<S32> ban_lines_mode(gSavedSettings , "ShowBanLines" , LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION); if (ban_lines_mode == LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION) { LLViewerParcelMgr::getInstance()->resetCollisionTimer(); } - if (handle_special_notification(notificationID, llsdBlock)) - { - return true; - } - } - // HACK -- handle callbacks for specific alerts. - if( notificationID == "HomePositionSet" ) - { - // save the home location image to disk - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenHomeFilename(); + if (handle_special_notification(notificationID, llsdBlock)) + { + return true; + } + } + // HACK -- handle callbacks for specific alerts. + if( notificationID == "HomePositionSet" ) + { + // save the home location image to disk + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenHomeFilename(); gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), @@ -5222,44 +5222,44 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - } - - if (notificationID == "RegionRestartMinutes" || - notificationID == "RegionRestartSeconds") - { - S32 seconds; - if (notificationID == "RegionRestartMinutes") - { - seconds = 60 * static_cast<S32>(llsdBlock["MINUTES"].asInteger()); - } - else - { - seconds = static_cast<S32>(llsdBlock["SECONDS"].asInteger()); - } - - LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance<LLFloaterRegionRestarting>("region_restarting"); - - if (floaterp) - { - LLFloaterRegionRestarting::updateTime(seconds); - } - else - { - LLSD params; - params["NAME"] = llsdBlock["NAME"]; - params["SECONDS"] = (LLSD::Integer)seconds; - LLFloaterRegionRestarting* restarting_floater = dynamic_cast<LLFloaterRegionRestarting*>(LLFloaterReg::showInstance("region_restarting", params)); - if(restarting_floater) - { - restarting_floater->center(); - } - } - - make_ui_sound("UISndRestart"); - } - + } + + if (notificationID == "RegionRestartMinutes" || + notificationID == "RegionRestartSeconds") + { + S32 seconds; + if (notificationID == "RegionRestartMinutes") + { + seconds = 60 * static_cast<S32>(llsdBlock["MINUTES"].asInteger()); + } + else + { + seconds = static_cast<S32>(llsdBlock["SECONDS"].asInteger()); + } + + LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance<LLFloaterRegionRestarting>("region_restarting"); + + if (floaterp) + { + LLFloaterRegionRestarting::updateTime(seconds); + } + else + { + LLSD params; + params["NAME"] = llsdBlock["NAME"]; + params["SECONDS"] = (LLSD::Integer)seconds; + LLFloaterRegionRestarting* restarting_floater = dynamic_cast<LLFloaterRegionRestarting*>(LLFloaterReg::showInstance("region_restarting", params)); + if(restarting_floater) + { + restarting_floater->center(); + } + } + + make_ui_sound("UISndRestart"); + } + // Special Marketplace update notification - if (notificationID == "SLM_UPDATE_FOLDER") + if (notificationID == "SLM_UPDATE_FOLDER") { std::string state = llsdBlock["state"].asString(); if (state == "deleted") @@ -5298,28 +5298,28 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } - LLNotificationsUtil::add(notificationID, llsdBlock); - return true; - } - return false; + LLNotificationsUtil::add(notificationID, llsdBlock); + return true; + } + return false; } static void process_special_alert_messages(const std::string & message) { - // Do special handling for alert messages. This is a legacy hack, and any actual displayed - // text should be altered in the notifications.xml files. - if ( message == "You died and have been teleported to your home location") - { - add(LLStatViewer::KILLED, 1); - } - else if( message == "Home position set." ) - { - // save the home location image to disk - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenHomeFilename(); - gViewerWindow->saveSnapshot(snap_filename, + // Do special handling for alert messages. This is a legacy hack, and any actual displayed + // text should be altered in the notifications.xml files. + if ( message == "You died and have been teleported to your home location") + { + add(LLStatViewer::KILLED, 1); + } + else if( message == "Home position set." ) + { + // save the home location image to disk + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenHomeFilename(); + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, @@ -5327,28 +5327,28 @@ static void process_special_alert_messages(const std::string & message) FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - } + } } void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) { - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - std::string message; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); - process_special_alert_messages(message); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + + process_special_alert_messages(message); - if (!attempt_standard_notification(msgsystem)) - { - BOOL modal = FALSE; - msgsystem->getBOOL("AlertData", "Modal", modal); - process_alert_core(message, modal); - } + if (!attempt_standard_notification(msgsystem)) + { + BOOL modal = FALSE; + msgsystem->getBOOL("AlertData", "Modal", modal); + process_alert_core(message, modal); + } } // The only difference between this routine and the previous is the fact that @@ -5358,18 +5358,18 @@ void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) // So we can't handle the messages with the same handler. void process_alert_message(LLMessageSystem *msgsystem, void **user_data) { - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - std::string message; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); - process_special_alert_messages(message); + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); - if (!attempt_standard_notification(msgsystem)) - { - BOOL modal = FALSE; - process_alert_core(message, modal); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + process_special_alert_messages(message); + + if (!attempt_standard_notification(msgsystem)) + { + BOOL modal = FALSE; + process_alert_core(message, modal); static LLCachedControl<S32> ban_lines_mode(gSavedSettings , "ShowBanLines" , LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION); if (ban_lines_mode == LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION @@ -5377,289 +5377,289 @@ void process_alert_message(LLMessageSystem *msgsystem, void **user_data) { LLViewerParcelMgr::getInstance()->resetCollisionTimer(); } - } + } } bool handle_not_age_verified_alert(const std::string &pAlertName) { - LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); - if ((notification == NULL) || notification->isIgnored()) - { - LLNotificationsUtil::add(pAlertName + "_Notify"); - } + LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); + if ((notification == NULL) || notification->isIgnored()) + { + LLNotificationsUtil::add(pAlertName + "_Notify"); + } - return true; + return true; } bool handle_special_alerts(const std::string &pAlertName) { - bool isHandled = false; - if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) - { - - isHandled = handle_not_age_verified_alert(pAlertName); - } + bool isHandled = false; + if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) + { + + isHandled = handle_not_age_verified_alert(pAlertName); + } - return isHandled; + return isHandled; } void process_alert_core(const std::string& message, BOOL modal) { - const std::string ALERT_PREFIX("ALERT: "); - const std::string NOTIFY_PREFIX("NOTIFY: "); - if (message.find(ALERT_PREFIX) == 0) - { - // Allow the server to spawn a named alert so that server alerts can be - // translated out of English. - std::string alert_name(message.substr(ALERT_PREFIX.length())); - if (!handle_special_alerts(alert_name)) - { - LLNotificationsUtil::add(alert_name); - } - } - else if (message.find(NOTIFY_PREFIX) == 0) - { - // Allow the server to spawn a named notification so that server notifications can be - // translated out of English. - std::string notify_name(message.substr(NOTIFY_PREFIX.length())); - LLNotificationsUtil::add(notify_name); - } - else if (message[0] == '/') - { - // System message is important, show in upper-right box not tip - std::string text(message.substr(1)); - LLSD args; - - // *NOTE: If the text from the server ever changes this line will need to be adjusted. - std::string restart_cancelled = "Region restart cancelled."; - if (text.substr(0, restart_cancelled.length()) == restart_cancelled) - { - LLFloaterRegionRestarting::close(); - } - - std::string new_msg =LLNotifications::instance().getGlobalString(text); - args["MESSAGE"] = new_msg; - LLNotificationsUtil::add("SystemMessage", args); - } - else if (modal) - { - LLSD args; - std::string new_msg =LLNotifications::instance().getGlobalString(message); - args["ERROR_MESSAGE"] = new_msg; - LLNotificationsUtil::add("ErrorMessage", args); - } - else - { - // Hack fix for EXP-623 (blame fix on RN :)) to avoid a sim deploy - const std::string AUTOPILOT_CANCELED_MSG("Autopilot canceled"); - if (message.find(AUTOPILOT_CANCELED_MSG) == std::string::npos ) - { - LLSD args; - std::string new_msg =LLNotifications::instance().getGlobalString(message); - - std::string localized_msg; - bool is_message_localized = LLTrans::findString(localized_msg, new_msg); - - args["MESSAGE"] = is_message_localized ? localized_msg : new_msg; - LLNotificationsUtil::add("SystemMessageTip", args); - } - } -} - -mean_collision_list_t gMeanCollisionList; -time_t gLastDisplayedTime = 0; + const std::string ALERT_PREFIX("ALERT: "); + const std::string NOTIFY_PREFIX("NOTIFY: "); + if (message.find(ALERT_PREFIX) == 0) + { + // Allow the server to spawn a named alert so that server alerts can be + // translated out of English. + std::string alert_name(message.substr(ALERT_PREFIX.length())); + if (!handle_special_alerts(alert_name)) + { + LLNotificationsUtil::add(alert_name); + } + } + else if (message.find(NOTIFY_PREFIX) == 0) + { + // Allow the server to spawn a named notification so that server notifications can be + // translated out of English. + std::string notify_name(message.substr(NOTIFY_PREFIX.length())); + LLNotificationsUtil::add(notify_name); + } + else if (message[0] == '/') + { + // System message is important, show in upper-right box not tip + std::string text(message.substr(1)); + LLSD args; + + // *NOTE: If the text from the server ever changes this line will need to be adjusted. + std::string restart_cancelled = "Region restart cancelled."; + if (text.substr(0, restart_cancelled.length()) == restart_cancelled) + { + LLFloaterRegionRestarting::close(); + } + + std::string new_msg =LLNotifications::instance().getGlobalString(text); + args["MESSAGE"] = new_msg; + LLNotificationsUtil::add("SystemMessage", args); + } + else if (modal) + { + LLSD args; + std::string new_msg =LLNotifications::instance().getGlobalString(message); + args["ERROR_MESSAGE"] = new_msg; + LLNotificationsUtil::add("ErrorMessage", args); + } + else + { + // Hack fix for EXP-623 (blame fix on RN :)) to avoid a sim deploy + const std::string AUTOPILOT_CANCELED_MSG("Autopilot canceled"); + if (message.find(AUTOPILOT_CANCELED_MSG) == std::string::npos ) + { + LLSD args; + std::string new_msg =LLNotifications::instance().getGlobalString(message); + + std::string localized_msg; + bool is_message_localized = LLTrans::findString(localized_msg, new_msg); + + args["MESSAGE"] = is_message_localized ? localized_msg : new_msg; + LLNotificationsUtil::add("SystemMessageTip", args); + } + } +} + +mean_collision_list_t gMeanCollisionList; +time_t gLastDisplayedTime = 0; void handle_show_mean_events(void *) { - LLFloaterReg::showInstance("bumps"); - //LLFloaterBump::showInstance(); + LLFloaterReg::showInstance("bumps"); + //LLFloaterBump::showInstance(); } void mean_name_callback(const LLUUID &id, const LLAvatarName& av_name) { - static const U32 max_collision_list_size = 20; - if (gMeanCollisionList.size() > max_collision_list_size) - { - mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (U32 i=0; i<max_collision_list_size; i++) iter++; - for_each(iter, gMeanCollisionList.end(), DeletePointer()); - gMeanCollisionList.erase(iter, gMeanCollisionList.end()); - } - - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) - { - LLMeanCollisionData *mcd = *iter; - if (mcd->mPerp == id) - { - mcd->mFullName = av_name.getUserName(); - } - } + static const U32 max_collision_list_size = 20; + if (gMeanCollisionList.size() > max_collision_list_size) + { + mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); + for (U32 i=0; i<max_collision_list_size; i++) iter++; + for_each(iter, gMeanCollisionList.end(), DeletePointer()); + gMeanCollisionList.erase(iter, gMeanCollisionList.end()); + } + + for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); + iter != gMeanCollisionList.end(); ++iter) + { + LLMeanCollisionData *mcd = *iter; + if (mcd->mPerp == id) + { + mcd->mFullName = av_name.getUserName(); + } + } } void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data) { - if (gAgent.inPrelude()) - { - // In prelude, bumping is OK. This dialog is rather confusing to - // newbies, so we don't show it. Drop the packet on the floor. - return; - } - - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - LLUUID perp; - U32 time; - U8 u8type; - EMeanCollisionType type; - F32 mag; - - S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision); - - for (i = 0; i < num; i++) - { - msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp); - msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time); - msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag); - msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type); - - type = (EMeanCollisionType)u8type; - - BOOL b_found = FALSE; - - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) - { - LLMeanCollisionData *mcd = *iter; - if ((mcd->mPerp == perp) && (mcd->mType == type)) - { - mcd->mTime = time; - mcd->mMag = mag; - b_found = TRUE; - break; - } - } - - if (!b_found) - { - LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); - gMeanCollisionList.push_front(mcd); - LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); - } - } - LLFloaterBump* bumps_floater = LLFloaterBump::getInstance(); - if(bumps_floater && bumps_floater->isInVisibleChain()) - { - bumps_floater->populateCollisionList(); - } + if (gAgent.inPrelude()) + { + // In prelude, bumping is OK. This dialog is rather confusing to + // newbies, so we don't show it. Drop the packet on the floor. + return; + } + + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); + + LLUUID perp; + U32 time; + U8 u8type; + EMeanCollisionType type; + F32 mag; + + S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision); + + for (i = 0; i < num; i++) + { + msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp); + msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time); + msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag); + msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type); + + type = (EMeanCollisionType)u8type; + + BOOL b_found = FALSE; + + for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); + iter != gMeanCollisionList.end(); ++iter) + { + LLMeanCollisionData *mcd = *iter; + if ((mcd->mPerp == perp) && (mcd->mType == type)) + { + mcd->mTime = time; + mcd->mMag = mag; + b_found = TRUE; + break; + } + } + + if (!b_found) + { + LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); + gMeanCollisionList.push_front(mcd); + LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); + } + } + LLFloaterBump* bumps_floater = LLFloaterBump::getInstance(); + if(bumps_floater && bumps_floater->isInVisibleChain()) + { + bumps_floater->populateCollisionList(); + } } void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) { - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - BOOL b_frozen; - - msgsystem->getBOOL("FrozenData", "Data", b_frozen); + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); + BOOL b_frozen; + + msgsystem->getBOOL("FrozenData", "Data", b_frozen); - // TODO: make being frozen change view - if (b_frozen) - { - } - else - { - } + // TODO: make being frozen change view + if (b_frozen) + { + } + else + { + } } // do some extra stuff once we get our economy data void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) { - LL_DEBUGS("Benefits") << "Received economy data, not currently used" << LL_ENDL; + LL_DEBUGS("Benefits") << "Received economy data, not currently used" << LL_ENDL; } void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) { - // only continue if at least some permissions were requested - if (orig_questions) - { - // check to see if the person we are asking - - // "'[OBJECTNAME]', an object owned by '[OWNERNAME]', - // located in [REGIONNAME] at [REGIONPOS], - // has been <granted|denied> permission to: [PERMISSIONS]." - - LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); - - // always include the object name and owner name - notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); - notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString()); - - // try to lookup viewerobject that corresponds to the object that - // requested permissions (here, taskid->requesting object id) - BOOL foundpos = FALSE; - LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); - if (viewobj) - { - // found the viewerobject, get it's position in its region - LLVector3 objpos(viewobj->getPosition()); - - // try to lookup the name of the region the object is in - LLViewerRegion* viewregion = viewobj->getRegion(); - if (viewregion) - { - // got the region, so include the region and 3d coordinates of the object - notice.setArg("[REGIONNAME]", viewregion->getName()); - std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); - notice.setArg("[REGIONPOS]", formatpos); - - foundpos = TRUE; - } - } - - if (!foundpos) - { - // unable to determine location of the object - notice.setArg("[REGIONNAME]", "(unknown region)"); - notice.setArg("[REGIONPOS]", "(unknown position)"); - } - - // check each permission that was requested, and list each - // permission that has been flagged as a caution permission - BOOL caution = FALSE; - S32 count = 0; - std::string perms; - for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) - { - if ((orig_questions & script_perm.permbit) - && script_perm.caution) - { - count++; - caution = TRUE; - - // add a comma before the permission description if it is not the first permission - // added to the list or the last permission to check - if (count > 1) - { - perms.append(", "); - } - - perms.append(LLTrans::getString(script_perm.question)); - } - } - - notice.setArg("[PERMISSIONS]", perms); - - // log a chat message as long as at least one requested permission - // is a caution permission - if (caution) - { - LLChat chat(notice.getString()); - // LLFloaterChat::addChat(chat, FALSE, FALSE); - } - } + // only continue if at least some permissions were requested + if (orig_questions) + { + // check to see if the person we are asking + + // "'[OBJECTNAME]', an object owned by '[OWNERNAME]', + // located in [REGIONNAME] at [REGIONPOS], + // has been <granted|denied> permission to: [PERMISSIONS]." + + LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); + + // always include the object name and owner name + notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); + notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString()); + + // try to lookup viewerobject that corresponds to the object that + // requested permissions (here, taskid->requesting object id) + BOOL foundpos = FALSE; + LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); + if (viewobj) + { + // found the viewerobject, get it's position in its region + LLVector3 objpos(viewobj->getPosition()); + + // try to lookup the name of the region the object is in + LLViewerRegion* viewregion = viewobj->getRegion(); + if (viewregion) + { + // got the region, so include the region and 3d coordinates of the object + notice.setArg("[REGIONNAME]", viewregion->getName()); + std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); + notice.setArg("[REGIONPOS]", formatpos); + + foundpos = TRUE; + } + } + + if (!foundpos) + { + // unable to determine location of the object + notice.setArg("[REGIONNAME]", "(unknown region)"); + notice.setArg("[REGIONPOS]", "(unknown position)"); + } + + // check each permission that was requested, and list each + // permission that has been flagged as a caution permission + BOOL caution = FALSE; + S32 count = 0; + std::string perms; + for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) + { + if ((orig_questions & script_perm.permbit) + && script_perm.caution) + { + count++; + caution = TRUE; + + // add a comma before the permission description if it is not the first permission + // added to the list or the last permission to check + if (count > 1) + { + perms.append(", "); + } + + perms.append(LLTrans::getString(script_perm.question)); + } + } + + notice.setArg("[PERMISSIONS]", perms); + + // log a chat message as long as at least one requested permission + // is a caution permission + if (caution) + { + LLChat chat(notice.getString()); + // LLFloaterChat::addChat(chat, FALSE, FALSE); + } + } } void script_question_mute(const LLUUID& item_id, const std::string& object_name); @@ -5676,97 +5676,97 @@ void experiencePermissionBlock(LLUUID experience, LLSD result) bool script_question_cb(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem *msg = gMessageSystem; - S32 orig = notification["payload"]["questions"].asInteger(); - S32 new_questions = orig; - - if (response["Details"]) - { - // respawn notification... - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); - - // ...with description on top - LLNotificationsUtil::add("DebitPermissionDetails"); - return false; - } - - LLUUID experience; - if(notification["payload"].has("experience")) - { - experience = notification["payload"]["experience"].asUUID(); - } - - // check whether permissions were granted or denied - BOOL allowed = TRUE; - // the "yes/accept" button is the first button in the template, making it button 0 - // if any other button was clicked, the permissions were denied - if (option != 0) - { - new_questions = 0; - allowed = FALSE; - } - else if(experience.notNull()) - { - LLSD permission; - LLSD data; - permission["permission"]="Allow"; - - data[experience.asString()]=permission; - data["experience"]=experience; - LLEventPumps::instance().obtain("experience_permission").post(data); - } - - LLUUID task_id = notification["payload"]["task_id"].asUUID(); - LLUUID item_id = notification["payload"]["item_id"].asUUID(); - - // reply with the permissions granted or denied - msg->newMessageFast(_PREHASH_ScriptAnswerYes); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_TaskID, task_id); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - msg->addS32Fast(_PREHASH_Questions, new_questions); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - - // only log a chat message if caution prompts are enabled - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - // log a chat message, if appropriate - notify_cautioned_script_question(notification, response, orig, allowed); - } - - if ( response["Mute"] ) // mute - { - script_question_mute(task_id,notification["payload"]["object_name"].asString()); - } - if ( response["BlockExperience"] ) - { - if(experience.notNull()) - { - LLViewerRegion* region = gAgent.getRegion(); - if (!region) - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLMessageSystem *msg = gMessageSystem; + S32 orig = notification["payload"]["questions"].asInteger(); + S32 new_questions = orig; + + if (response["Details"]) + { + // respawn notification... + LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); + + // ...with description on top + LLNotificationsUtil::add("DebitPermissionDetails"); + return false; + } + + LLUUID experience; + if(notification["payload"].has("experience")) + { + experience = notification["payload"]["experience"].asUUID(); + } + + // check whether permissions were granted or denied + BOOL allowed = TRUE; + // the "yes/accept" button is the first button in the template, making it button 0 + // if any other button was clicked, the permissions were denied + if (option != 0) + { + new_questions = 0; + allowed = FALSE; + } + else if(experience.notNull()) + { + LLSD permission; + LLSD data; + permission["permission"]="Allow"; + + data[experience.asString()]=permission; + data["experience"]=experience; + LLEventPumps::instance().obtain("experience_permission").post(data); + } + + LLUUID task_id = notification["payload"]["task_id"].asUUID(); + LLUUID item_id = notification["payload"]["item_id"].asUUID(); + + // reply with the permissions granted or denied + msg->newMessageFast(_PREHASH_ScriptAnswerYes); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Data); + msg->addUUIDFast(_PREHASH_TaskID, task_id); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->addS32Fast(_PREHASH_Questions, new_questions); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + + // only log a chat message if caution prompts are enabled + if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) + { + // log a chat message, if appropriate + notify_cautioned_script_question(notification, response, orig, allowed); + } + + if ( response["Mute"] ) // mute + { + script_question_mute(task_id,notification["payload"]["object_name"].asString()); + } + if ( response["BlockExperience"] ) + { + if(experience.notNull()) + { + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return false; LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), boost::bind(&experiencePermissionBlock, experience, _1)); - } + } } - return false; + return false; } void script_question_mute(const LLUUID& task_id, const std::string& object_name) { - LLMuteList::getInstance()->add(LLMute(task_id, object_name, LLMute::OBJECT)); + LLMuteList::getInstance()->add(LLMute(task_id, object_name, LLMute::OBJECT)); // purge the message queue of any previously queued requests from the same source. DEV-4879 class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher { public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} + bool matches(const LLNotificationPtr notification) const { if (notification->getName() == "ScriptQuestionCaution" || notification->getName() == "ScriptQuestion") @@ -5789,178 +5789,178 @@ static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestio void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload) { - if(experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID) - { - args["GRID_WIDE"] = LLTrans::getString("Grid-Scope"); - } - else - { - args["GRID_WIDE"] = LLTrans::getString("Land-Scope"); - } - args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString(); + if(experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID) + { + args["GRID_WIDE"] = LLTrans::getString("Grid-Scope"); + } + else + { + args["GRID_WIDE"] = LLTrans::getString("Land-Scope"); + } + args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString(); - LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); + LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); } void process_script_question(LLMessageSystem *msg, void **user_data) { - // *TODO: Translate owner name -> [FIRST] [LAST] - - LLHost sender = msg->getSender(); - - LLUUID taskid; - LLUUID itemid; - S32 questions; - std::string object_name; - std::string owner_name; - LLUUID experienceid; - - // taskid -> object key of object requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); - // itemid -> script asset key of script requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); - msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); - msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); - - if(msg->has(_PREHASH_Experience)) - { - msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid); - } - - // Special case. If the objects are owned by this agent, throttle per-object instead - // of per-owner. It's common for residents to reset a ton of scripts that re-request - // permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa, - // so we'll reuse the same namespace for both throttle types. - std::string throttle_name = owner_name; - std::string self_name; - LLAgentUI::buildFullname( self_name ); // does not include ' Resident' - std::string clean_owner_name = LLCacheName::cleanFullName(owner_name); // removes ' Resident' - if( clean_owner_name == self_name ) - { - throttle_name = taskid.getString(); - } - - // don't display permission requests if this object is muted - if (LLMuteList::getInstance()->isMuted(taskid)) return; - - // throttle excessive requests from any specific user's scripts - typedef LLKeyThrottle<std::string> LLStringThrottle; - static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); - - switch (question_throttle.noteAction(throttle_name)) - { - case LLStringThrottle::THROTTLE_NEWLY_BLOCKED: - LL_INFOS("Messaging") << "process_script_question throttled" - << " owner_name:" << owner_name - << LL_ENDL; - // Fall through - - case LLStringThrottle::THROTTLE_BLOCKED: - // Escape altogether until we recover - return; - - case LLStringThrottle::THROTTLE_OK: - break; - } - - std::string script_question; - if (questions) - { - bool caution = false; - S32 count = 0; - LLSD args; - args["OBJECTNAME"] = object_name; - args["NAME"] = clean_owner_name; - S32 known_questions = 0; - bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; - // check the received permission flags against each permission - for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) - { - if (questions & script_perm.permbit) - { - count++; - known_questions |= script_perm.permbit; - // check whether permission question should cause special caution dialog - caution |= (script_perm.caution); - - if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) - continue; + // *TODO: Translate owner name -> [FIRST] [LAST] + + LLHost sender = msg->getSender(); + + LLUUID taskid; + LLUUID itemid; + S32 questions; + std::string object_name; + std::string owner_name; + LLUUID experienceid; + + // taskid -> object key of object requesting permissions + msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); + // itemid -> script asset key of script requesting permissions + msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); + msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); + msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); + + if(msg->has(_PREHASH_Experience)) + { + msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid); + } + + // Special case. If the objects are owned by this agent, throttle per-object instead + // of per-owner. It's common for residents to reset a ton of scripts that re-request + // permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa, + // so we'll reuse the same namespace for both throttle types. + std::string throttle_name = owner_name; + std::string self_name; + LLAgentUI::buildFullname( self_name ); // does not include ' Resident' + std::string clean_owner_name = LLCacheName::cleanFullName(owner_name); // removes ' Resident' + if( clean_owner_name == self_name ) + { + throttle_name = taskid.getString(); + } + + // don't display permission requests if this object is muted + if (LLMuteList::getInstance()->isMuted(taskid)) return; + + // throttle excessive requests from any specific user's scripts + typedef LLKeyThrottle<std::string> LLStringThrottle; + static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); + + switch (question_throttle.noteAction(throttle_name)) + { + case LLStringThrottle::THROTTLE_NEWLY_BLOCKED: + LL_INFOS("Messaging") << "process_script_question throttled" + << " owner_name:" << owner_name + << LL_ENDL; + // Fall through + + case LLStringThrottle::THROTTLE_BLOCKED: + // Escape altogether until we recover + return; + + case LLStringThrottle::THROTTLE_OK: + break; + } + + std::string script_question; + if (questions) + { + bool caution = false; + S32 count = 0; + LLSD args; + args["OBJECTNAME"] = object_name; + args["NAME"] = clean_owner_name; + S32 known_questions = 0; + bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; + // check the received permission flags against each permission + for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) + { + if (questions & script_perm.permbit) + { + count++; + known_questions |= script_perm.permbit; + // check whether permission question should cause special caution dialog + caution |= (script_perm.caution); + + if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) + continue; if (LLTrans::getString(script_perm.question).empty()) { continue; } - script_question += " " + LLTrans::getString(script_perm.question) + "\n"; - } - } - - args["QUESTIONS"] = script_question; - - if (known_questions != questions) - { - // This is in addition to the normal dialog. - // Viewer got a request for not supported/implemented permission - LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question - << " permission. Permission is unknown and can't be granted. Item id: " << itemid - << " taskid:" << taskid << LL_ENDL; - } - - if (known_questions) - { - LLSD payload; - payload["task_id"] = taskid; - payload["item_id"] = itemid; - payload["sender"] = sender.getIPandPort(); - payload["questions"] = known_questions; - payload["object_name"] = object_name; - payload["owner_name"] = owner_name; - - // check whether cautions are even enabled or not - const char* notification = "ScriptQuestion"; - - if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : ""; - notification = "ScriptQuestionCaution"; - } - else if(experienceid.notNull()) - { - payload["experience"]=experienceid; + script_question += " " + LLTrans::getString(script_perm.question) + "\n"; + } + } + + args["QUESTIONS"] = script_question; + + if (known_questions != questions) + { + // This is in addition to the normal dialog. + // Viewer got a request for not supported/implemented permission + LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question + << " permission. Permission is unknown and can't be granted. Item id: " << itemid + << " taskid:" << taskid << LL_ENDL; + } + + if (known_questions) + { + LLSD payload; + payload["task_id"] = taskid; + payload["item_id"] = itemid; + payload["sender"] = sender.getIPandPort(); + payload["questions"] = known_questions; + payload["object_name"] = object_name; + payload["owner_name"] = owner_name; + + // check whether cautions are even enabled or not + const char* notification = "ScriptQuestion"; + + if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) + { + args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : ""; + notification = "ScriptQuestionCaution"; + } + else if(experienceid.notNull()) + { + payload["experience"]=experienceid; LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); - return; - } + return; + } - LLNotificationsUtil::add(notification, args, payload); - } - } + LLNotificationsUtil::add(notification, args, payload); + } + } } void process_derez_container(LLMessageSystem *msg, void**) { - LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; + LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; } void container_inventory_arrived(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void* data) -{ - LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - } - - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - - if (inventory->size() > 2) - { - // create a new inventory category to put this in - LLUUID cat_id; - gInventory.createNewCategory( + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* data) +{ + LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; + if( gAgentCamera.cameraMouselook() ) + { + gAgentCamera.changeCameraToDefault(); + } + + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + + if (inventory->size() > 2) + { + // create a new inventory category to put this in + LLUUID cat_id; + gInventory.createNewCategory( gInventory.getRootFolderID(), LLFolderType::FT_NONE, LLTrans::getString("AcquiredItems"), @@ -6001,532 +6001,532 @@ void container_inventory_arrived(LLViewerObject* object, active_panel->setSelection(new_cat_id, TAKE_FOCUS_NO); } }); - } - else if (inventory->size() == 2) - { - // we're going to get one fake root category as well as the - // one actual object - LLInventoryObject::object_list_t::iterator it = inventory->begin(); - - if ((*it)->getType() == LLAssetType::AT_CATEGORY) - { - ++it; - } - - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); - - LLUUID item_id; - item_id.generate(); - time_t creation_date_utc = time_corrected(); - LLPointer<LLViewerInventoryItem> new_item - = new LLViewerInventoryItem(item_id, category, - item->getPermissions(), - item->getAssetUUID(), - item->getType(), - item->getInventoryType(), - item->getName(), - item->getDescription(), - LLSaleInfo::DEFAULT, - item->getFlags(), - creation_date_utc); - new_item->updateServer(TRUE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - if(active_panel) - { - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - } - } - - // we've got the inventory, now delete this object if this was a take - BOOL delete_object = (BOOL)(intptr_t)data; - LLViewerRegion *region = gAgent.getRegion(); - if (delete_object && region) - { - gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - const U8 NO_FORCE = 0; - gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - gMessageSystem->sendReliable(region->getHost()); - } + } + else if (inventory->size() == 2) + { + // we're going to get one fake root category as well as the + // one actual object + LLInventoryObject::object_list_t::iterator it = inventory->begin(); + + if ((*it)->getType() == LLAssetType::AT_CATEGORY) + { + ++it; + } + + LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); + const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); + + LLUUID item_id; + item_id.generate(); + time_t creation_date_utc = time_corrected(); + LLPointer<LLViewerInventoryItem> new_item + = new LLViewerInventoryItem(item_id, category, + item->getPermissions(), + item->getAssetUUID(), + item->getType(), + item->getInventoryType(), + item->getName(), + item->getDescription(), + LLSaleInfo::DEFAULT, + item->getFlags(), + creation_date_utc); + new_item->updateServer(TRUE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + if(active_panel) + { + active_panel->setSelection(item_id, TAKE_FOCUS_NO); + } + } + + // we've got the inventory, now delete this object if this was a take + BOOL delete_object = (BOOL)(intptr_t)data; + LLViewerRegion *region = gAgent.getRegion(); + if (delete_object && region) + { + gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + const U8 NO_FORCE = 0; + gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); + gMessageSystem->sendReliable(region->getHost()); + } } // method to format the time. std::string formatted_time(const time_t& the_time) { - std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] [" - +LLTrans::getString("LTimeMonth")+"] [" - +LLTrans::getString("LTimeDay")+"] [" - +LLTrans::getString("LTimeHour")+"]:[" - +LLTrans::getString("LTimeMin")+"]:[" - +LLTrans::getString("LTimeSec")+"] [" - +LLTrans::getString("LTimeYear")+"]"; + std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] [" + +LLTrans::getString("LTimeMonth")+"] [" + +LLTrans::getString("LTimeDay")+"] [" + +LLTrans::getString("LTimeHour")+"]:[" + +LLTrans::getString("LTimeMin")+"]:[" + +LLTrans::getString("LTimeSec")+"] [" + +LLTrans::getString("LTimeYear")+"]"; - LLSD substitution; - substitution["datetime"] = (S32) the_time; - LLStringUtil::format (dateStr, substitution); - return dateStr; + LLSD substitution; + substitution["datetime"] = (S32) the_time; + LLStringUtil::format (dateStr, substitution); + return dateStr; } void process_teleport_failed(LLMessageSystem *msg, void**) { - LL_WARNS("Teleport","Messaging") << "Received TeleportFailed message" << LL_ENDL; - - std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" - std::string big_reason; // Actual message to display - LLSD args; - - // Let the interested parties know that teleport failed. - LLViewerParcelMgr::getInstance()->onTeleportFailed(); - - // if we have additional alert data - if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) - { - // Get the message ID - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); - big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() <= 0 ) - { - // Nothing found in the map - use what the server returned in the original message block - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); - } - LL_WARNS("Teleport") << "AlertInfo message_id " << message_id << " reason: " << big_reason << LL_ENDL; - - LLSD llsd_block; - std::string llsd_raw; - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); - if (llsd_raw.length()) - { - std::istringstream llsd_data(llsd_raw); - if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) - { - LL_WARNS("Teleport") << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; - } - else - { - LL_WARNS("Teleport") << "AlertInfo llsd block received: " << llsd_block << LL_ENDL; - if(llsd_block.has("REGION_NAME")) - { - std::string region_name = llsd_block["REGION_NAME"].asString(); - if(!region_name.empty()) - { - LLStringUtil::format_map_t name_args; - name_args["[REGION_NAME]"] = region_name; - LLStringUtil::format(big_reason, name_args); - } - } - // change notification name in this special case - if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) - { - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - LL_WARNS("Teleport") << "called handle_teleport_access_blocked, setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - return; - } - } - } - args["REASON"] = big_reason; - } - else - { // Extra message payload not found - use what the simulator sent - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); - - big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() > 0 ) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned - args["REASON"] = message_id; - } - } - LL_WARNS("Teleport") << "Displaying CouldNotTeleportReason string, REASON= " << args["REASON"] << LL_ENDL; - - LLNotificationsUtil::add("CouldNotTeleportReason", args); - - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - LL_WARNS("Teleport") << "End of process_teleport_failed(). Reason message arg is " << args["REASON"] - << ". Setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } + LL_WARNS("Teleport","Messaging") << "Received TeleportFailed message" << LL_ENDL; + + std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" + std::string big_reason; // Actual message to display + LLSD args; + + // Let the interested parties know that teleport failed. + LLViewerParcelMgr::getInstance()->onTeleportFailed(); + + // if we have additional alert data + if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) + { + // Get the message ID + msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); + big_reason = LLAgent::sTeleportErrorMessages[message_id]; + if ( big_reason.size() <= 0 ) + { + // Nothing found in the map - use what the server returned in the original message block + msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); + } + LL_WARNS("Teleport") << "AlertInfo message_id " << message_id << " reason: " << big_reason << LL_ENDL; + + LLSD llsd_block; + std::string llsd_raw; + msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); + if (llsd_raw.length()) + { + std::istringstream llsd_data(llsd_raw); + if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) + { + LL_WARNS("Teleport") << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; + } + else + { + LL_WARNS("Teleport") << "AlertInfo llsd block received: " << llsd_block << LL_ENDL; + if(llsd_block.has("REGION_NAME")) + { + std::string region_name = llsd_block["REGION_NAME"].asString(); + if(!region_name.empty()) + { + LLStringUtil::format_map_t name_args; + name_args["[REGION_NAME]"] = region_name; + LLStringUtil::format(big_reason, name_args); + } + } + // change notification name in this special case + if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) + { + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + { + LL_WARNS("Teleport") << "called handle_teleport_access_blocked, setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } + return; + } + } + } + args["REASON"] = big_reason; + } + else + { // Extra message payload not found - use what the simulator sent + msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); + + big_reason = LLAgent::sTeleportErrorMessages[message_id]; + if ( big_reason.size() > 0 ) + { // Substitute verbose reason from the local map + args["REASON"] = big_reason; + } + else + { // Nothing found in the map - use what the server returned + args["REASON"] = message_id; + } + } + LL_WARNS("Teleport") << "Displaying CouldNotTeleportReason string, REASON= " << args["REASON"] << LL_ENDL; + + LLNotificationsUtil::add("CouldNotTeleportReason", args); + + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + { + LL_WARNS("Teleport") << "End of process_teleport_failed(). Reason message arg is " << args["REASON"] + << ". Setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } } void process_teleport_local(LLMessageSystem *msg,void**) { - LL_INFOS("Teleport","Messaging") << "Received TeleportLocal message" << LL_ENDL; - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Teleport", "Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; - return; - } - - U32 location_id; - LLVector3 pos, look_at; - U32 teleport_flags; - msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); - msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); - msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); - msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - LL_INFOS("Teleport") << "Message params are location_id " << location_id << " teleport_flags " << teleport_flags << LL_ENDL; - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) - { - // To prevent TeleportStart messages re-activating the progress screen right - // after tp, keep the teleport state and let progress screen clear it after a short delay - // (progress screen is active but not visible) *TODO: remove when SVC-5290 is fixed - gTeleportDisplayTimer.reset(); - gTeleportDisplay = TRUE; - } - else - { - LL_WARNS("Teleport") << "State is not TELEPORT_LOCAL: " << gAgent.getTeleportStateName() - << ", setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - } - - // Sim tells us whether the new position is off the ground - if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) - { - gAgent.setFlying(TRUE); - } - else - { - gAgent.setFlying(FALSE); - } - - gAgent.setPositionAgent(pos); - gAgentCamera.slamLookAt(look_at); - - if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) ) - { - gAgentCamera.resetView(TRUE, TRUE); - } - - // send camera update to new region - gAgentCamera.updateCamera(); - - send_agent_update(TRUE, TRUE); - - // Let the interested parties know we've teleported. - // Vadim *HACK: Agent position seems to get reset (to render position?) - // on each frame, so we have to pass the new position manually. - LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos)); + LL_INFOS("Teleport","Messaging") << "Received TeleportLocal message" << LL_ENDL; + + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS("Teleport", "Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; + return; + } + + U32 location_id; + LLVector3 pos, look_at; + U32 teleport_flags; + msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); + msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); + msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); + msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + + LL_INFOS("Teleport") << "Message params are location_id " << location_id << " teleport_flags " << teleport_flags << LL_ENDL; + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + { + if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) + { + // To prevent TeleportStart messages re-activating the progress screen right + // after tp, keep the teleport state and let progress screen clear it after a short delay + // (progress screen is active but not visible) *TODO: remove when SVC-5290 is fixed + gTeleportDisplayTimer.reset(); + gTeleportDisplay = TRUE; + } + else + { + LL_WARNS("Teleport") << "State is not TELEPORT_LOCAL: " << gAgent.getTeleportStateName() + << ", setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } + } + + // Sim tells us whether the new position is off the ground + if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) + { + gAgent.setFlying(TRUE); + } + else + { + gAgent.setFlying(FALSE); + } + + gAgent.setPositionAgent(pos); + gAgentCamera.slamLookAt(look_at); + + if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) ) + { + gAgentCamera.resetView(TRUE, TRUE); + } + + // send camera update to new region + gAgentCamera.updateCamera(); + + send_agent_update(TRUE, TRUE); + + // Let the interested parties know we've teleported. + // Vadim *HACK: Agent position seems to get reset (to render position?) + // on each frame, so we have to pass the new position manually. + LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos)); } void send_simple_im(const LLUUID& to_id, - const std::string& message, - EInstantMessage dialog, - const LLUUID& id) -{ - std::string my_name; - LLAgentUI::buildFullname(my_name); - send_improved_im(to_id, - my_name, - message, - IM_ONLINE, - dialog, - id, - NO_TIMESTAMP, - (U8*)EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); + const std::string& message, + EInstantMessage dialog, + const LLUUID& id) +{ + std::string my_name; + LLAgentUI::buildFullname(my_name); + send_improved_im(to_id, + my_name, + message, + IM_ONLINE, + dialog, + id, + NO_TIMESTAMP, + (U8*)EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); } void send_group_notice(const LLUUID& group_id, - const std::string& subject, - const std::string& message, - const LLInventoryItem* item) -{ - // Put this notice into an instant message form. - // This will mean converting the item to a binary bucket, - // and the subject/message into a single field. - std::string my_name; - LLAgentUI::buildFullname(my_name); - - // Combine subject + message into a single string. - std::ostringstream subject_and_message; - // TODO: turn all existing |'s into ||'s in subject and message. - subject_and_message << subject << "|" << message; - - // Create an empty binary bucket. - U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE]; - U8* bucket_to_send = bin_bucket; - bin_bucket[0] = '\0'; - S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE; - // If there is an item being sent, pack it into the binary bucket. - if (item) - { - LLSD item_def; - item_def["item_id"] = item->getUUID(); - item_def["owner_id"] = item->getPermissions().getOwner(); - std::ostringstream ostr; - LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML); - bin_bucket_size = ostr.str().copy( - (char*)bin_bucket, ostr.str().size()); - bin_bucket[bin_bucket_size] = '\0'; - } - else - { - bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; - } - - - send_improved_im( - group_id, - my_name, - subject_and_message.str(), - IM_ONLINE, - IM_GROUP_NOTICE, - LLUUID::null, - NO_TIMESTAMP, - bucket_to_send, - bin_bucket_size); + const std::string& subject, + const std::string& message, + const LLInventoryItem* item) +{ + // Put this notice into an instant message form. + // This will mean converting the item to a binary bucket, + // and the subject/message into a single field. + std::string my_name; + LLAgentUI::buildFullname(my_name); + + // Combine subject + message into a single string. + std::ostringstream subject_and_message; + // TODO: turn all existing |'s into ||'s in subject and message. + subject_and_message << subject << "|" << message; + + // Create an empty binary bucket. + U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE]; + U8* bucket_to_send = bin_bucket; + bin_bucket[0] = '\0'; + S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE; + // If there is an item being sent, pack it into the binary bucket. + if (item) + { + LLSD item_def; + item_def["item_id"] = item->getUUID(); + item_def["owner_id"] = item->getPermissions().getOwner(); + std::ostringstream ostr; + LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML); + bin_bucket_size = ostr.str().copy( + (char*)bin_bucket, ostr.str().size()); + bin_bucket[bin_bucket_size] = '\0'; + } + else + { + bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; + } + + + send_improved_im( + group_id, + my_name, + subject_and_message.str(), + IM_ONLINE, + IM_GROUP_NOTICE, + LLUUID::null, + NO_TIMESTAMP, + bucket_to_send, + bin_bucket_size); } void send_lures(const LLSD& notification, const LLSD& response) { - std::string text = response["message"].asString(); - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - text.append("\r\n").append(slurl.getSLURLString()); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_StartLure); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Info); - msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in. - msg->addStringFast(_PREHASH_Message, text); - for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); - it != notification["payload"]["ids"].endArray(); - ++it) - { - LLUUID target_id = it->asUUID(); - - msg->nextBlockFast(_PREHASH_TargetData); - msg->addUUIDFast(_PREHASH_TargetID, target_id); - - // Record the offer. - { - LLAvatarName av_name; - LLAvatarNameCache::get(target_id, &av_name); // for im log filenames - LLSD args; - args["TO_NAME"] = LLSLURL("agent", target_id, "completename").getSLURLString();; - - LLSD payload; - - //*TODO please rewrite all keys to the same case, lower or upper - payload["from_id"] = target_id; - payload["SUPPRESS_TOAST"] = true; - LLNotificationsUtil::add("TeleportOfferSent", args, payload); - - // Add the recepient to the recent people list. - LLRecentPeople::instance().add(target_id); - } - } - gAgent.sendReliableMessage(); + std::string text = response["message"].asString(); + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + text.append("\r\n").append(slurl.getSLURLString()); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_StartLure); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Info); + msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in. + msg->addStringFast(_PREHASH_Message, text); + for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); + it != notification["payload"]["ids"].endArray(); + ++it) + { + LLUUID target_id = it->asUUID(); + + msg->nextBlockFast(_PREHASH_TargetData); + msg->addUUIDFast(_PREHASH_TargetID, target_id); + + // Record the offer. + { + LLAvatarName av_name; + LLAvatarNameCache::get(target_id, &av_name); // for im log filenames + LLSD args; + args["TO_NAME"] = LLSLURL("agent", target_id, "completename").getSLURLString();; + + LLSD payload; + + //*TODO please rewrite all keys to the same case, lower or upper + payload["from_id"] = target_id; + payload["SUPPRESS_TOAST"] = true; + LLNotificationsUtil::add("TeleportOfferSent", args, payload); + + // Add the recepient to the recent people list. + LLRecentPeople::instance().add(target_id); + } + } + gAgent.sendReliableMessage(); } bool handle_lure_callback(const LLSD& notification, const LLSD& response) { - static const unsigned OFFER_RECIPIENT_LIMIT = 250; - if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) - { - // More than OFFER_RECIPIENT_LIMIT targets will overload the message - // producing an llerror. - LLSD args; - args["OFFERS"] = LLSD::Integer(notification["payload"]["ids"].size()); - args["LIMIT"] = static_cast<int>(OFFER_RECIPIENT_LIMIT); - LLNotificationsUtil::add("TooManyTeleportOffers", args); - return false; - } + static const unsigned OFFER_RECIPIENT_LIMIT = 250; + if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) + { + // More than OFFER_RECIPIENT_LIMIT targets will overload the message + // producing an llerror. + LLSD args; + args["OFFERS"] = LLSD::Integer(notification["payload"]["ids"].size()); + args["LIMIT"] = static_cast<int>(OFFER_RECIPIENT_LIMIT); + LLNotificationsUtil::add("TooManyTeleportOffers", args); + return false; + } - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(0 == option) - { - send_lures(notification, response); - } + if(0 == option) + { + send_lures(notification, response); + } - return false; + return false; } void handle_lure(const LLUUID& invitee) { - std::vector<LLUUID> ids; - ids.push_back(invitee); - handle_lure(ids); + std::vector<LLUUID> ids; + ids.push_back(invitee); + handle_lure(ids); } // Prompt for a message to the invited user. void handle_lure(const uuid_vec_t& ids) { - if (ids.empty()) return; + if (ids.empty()) return; - if (!gAgent.getRegion()) return; + if (!gAgent.getRegion()) return; - LLSD edit_args; - edit_args["REGION"] = gAgent.getRegion()->getName(); + LLSD edit_args; + edit_args["REGION"] = gAgent.getRegion()->getName(); - LLSD payload; - for (std::vector<LLUUID>::const_iterator it = ids.begin(); - it != ids.end(); - ++it) - { - payload["ids"].append(*it); - } - if (gAgent.isGodlike()) - { - LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); - } - else - { - LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback); - } + LLSD payload; + for (std::vector<LLUUID>::const_iterator it = ids.begin(); + it != ids.end(); + ++it) + { + payload["ids"].append(*it); + } + if (gAgent.isGodlike()) + { + LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); + } + else + { + LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback); + } } bool teleport_request_callback(const LLSD& notification, const LLSD& response) { - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - if(from_id.isNull()) - { - LL_WARNS() << "from_id is NULL" << LL_ENDL; - return false; - } - - LLAvatarName av_name; - LLAvatarNameCache::get(from_id, &av_name); - - if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::isLinden(av_name.getUserName())) - { - return false; - } - - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - switch(option) - { - // Yes - case 0: - { - LLSD dummy_notification; - dummy_notification["payload"]["ids"][0] = from_id; - - LLSD dummy_response; - dummy_response["message"] = response["message"]; - - send_lures(dummy_notification, dummy_response); - } - break; - - // No - case 1: - default: - break; - } - - return false; + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + if(from_id.isNull()) + { + LL_WARNS() << "from_id is NULL" << LL_ENDL; + return false; + } + + LLAvatarName av_name; + LLAvatarNameCache::get(from_id, &av_name); + + if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::isLinden(av_name.getUserName())) + { + return false; + } + + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + switch(option) + { + // Yes + case 0: + { + LLSD dummy_notification; + dummy_notification["payload"]["ids"][0] = from_id; + + LLSD dummy_response; + dummy_response["message"] = response["message"]; + + send_lures(dummy_notification, dummy_response); + } + break; + + // No + case 1: + default: + break; + } + + return false; } static LLNotificationFunctorRegistration teleport_request_callback_reg("TeleportRequest", teleport_request_callback); void send_improved_im(const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline, - EInstantMessage dialog, - const LLUUID& id, - U32 timestamp, - const U8* binary_bucket, - S32 binary_bucket_size) -{ - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - to_id, - name, - message, - offline, - dialog, - id, - 0, - LLUUID::null, - gAgent.getPositionAgent(), - timestamp, - binary_bucket, - binary_bucket_size); - gAgent.sendReliableMessage(); + const std::string& name, + const std::string& message, + U8 offline, + EInstantMessage dialog, + const LLUUID& id, + U32 timestamp, + const U8* binary_bucket, + S32 binary_bucket_size) +{ + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + to_id, + name, + message, + offline, + dialog, + id, + 0, + LLUUID::null, + gAgent.getPositionAgent(), + timestamp, + binary_bucket, + binary_bucket_size); + gAgent.sendReliableMessage(); } void send_places_query(const LLUUID& query_id, - const LLUUID& trans_id, - const std::string& query_text, - U32 query_flags, - S32 category, - const std::string& sim_name) -{ - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage("PlacesQuery"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUID("QueryID", query_id); - msg->nextBlock("TransactionData"); - msg->addUUID("TransactionID", trans_id); - msg->nextBlock("QueryData"); - msg->addString("QueryText", query_text); - msg->addU32("QueryFlags", query_flags); - msg->addS8("Category", (S8)category); - msg->addString("SimName", sim_name); - gAgent.sendReliableMessage(); + const LLUUID& trans_id, + const std::string& query_text, + U32 query_flags, + S32 category, + const std::string& sim_name) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage("PlacesQuery"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUID("QueryID", query_id); + msg->nextBlock("TransactionData"); + msg->addUUID("TransactionID", trans_id); + msg->nextBlock("QueryData"); + msg->addString("QueryText", query_text); + msg->addU32("QueryFlags", query_flags); + msg->addS8("Category", (S8)category); + msg->addString("SimName", sim_name); + gAgent.sendReliableMessage(); } // Deprecated in favor of cap "UserInfo" void process_user_info_reply(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "process_user_info_reply - " - << "wrong agent id." << LL_ENDL; - } - - std::string email; - msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); - std::string dir_visibility; - msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS("Messaging") << "process_user_info_reply - " + << "wrong agent id." << LL_ENDL; + } - LLFloaterPreference::updateUserInfo(dir_visibility); - LLFloaterSnapshot::setAgentEmail(email); + std::string email; + msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); + std::string dir_visibility; + msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + + LLFloaterPreference::updateUserInfo(dir_visibility); + LLFloaterSnapshot::setAgentEmail(email); } @@ -6539,133 +6539,133 @@ const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n"; bool callback_script_dialog(const LLSD& notification, const LLSD& response) { - LLNotificationForm form(notification["form"]); - - std::string rtn_text; - S32 button_idx; - button_idx = LLNotification::getSelectedOption(notification, response); - if (response[TEXTBOX_MAGIC_TOKEN].isDefined()) - { - if (response[TEXTBOX_MAGIC_TOKEN].isString()) - rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString(); - else - rtn_text.clear(); // bool marks empty string - } - else - { - rtn_text = LLNotification::getSelectedOptionName(response); - } - - // Button -2 = Mute - // Button -1 = Ignore - no processing needed for this button - // Buttons 0 and above = dialog choices - - if (-2 == button_idx) - { - std::string object_name = notification["payload"]["object_name"].asString(); - LLUUID object_id = notification["payload"]["object_id"].asUUID(); - LLMute mute(object_id, object_name, LLMute::OBJECT); - if (LLMuteList::getInstance()->add(mute)) - { - // This call opens the sidebar, displays the block list, and highlights the newly blocked - // object in the list so the user can see that their block click has taken effect. - LLPanelBlockedList::showPanelAndSelect(object_id); - } - } - - if (0 <= button_idx) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("ScriptDialogReply"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); - msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); - msg->addS32("ButtonIndex", button_idx); - msg->addString("ButtonLabel", rtn_text); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - } - - return false; + LLNotificationForm form(notification["form"]); + + std::string rtn_text; + S32 button_idx; + button_idx = LLNotification::getSelectedOption(notification, response); + if (response[TEXTBOX_MAGIC_TOKEN].isDefined()) + { + if (response[TEXTBOX_MAGIC_TOKEN].isString()) + rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString(); + else + rtn_text.clear(); // bool marks empty string + } + else + { + rtn_text = LLNotification::getSelectedOptionName(response); + } + + // Button -2 = Mute + // Button -1 = Ignore - no processing needed for this button + // Buttons 0 and above = dialog choices + + if (-2 == button_idx) + { + std::string object_name = notification["payload"]["object_name"].asString(); + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLMute mute(object_id, object_name, LLMute::OBJECT); + if (LLMuteList::getInstance()->add(mute)) + { + // This call opens the sidebar, displays the block list, and highlights the newly blocked + // object in the list so the user can see that their block click has taken effect. + LLPanelBlockedList::showPanelAndSelect(object_id); + } + } + + if (0 <= button_idx) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("ScriptDialogReply"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); + msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); + msg->addS32("ButtonIndex", button_idx); + msg->addString("ButtonLabel", rtn_text); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + } + + return false; } static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); void process_script_dialog(LLMessageSystem* msg, void**) { - S32 i; - LLSD payload; + S32 i; + LLSD payload; - LLUUID object_id; - msg->getUUID("Data", "ObjectID", object_id); + LLUUID object_id; + msg->getUUID("Data", "ObjectID", object_id); -// For compability with OS grids first check for presence of extended packet before fetching data. +// For compability with OS grids first check for presence of extended packet before fetching data. LLUUID owner_id; - if (gMessageSystem->getNumberOfBlocks("OwnerData") > 0) - { + if (gMessageSystem->getNumberOfBlocks("OwnerData") > 0) + { msg->getUUID("OwnerData", "OwnerID", owner_id); - } - - if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id)) - { - return; - } - - std::string message; - std::string first_name; - std::string last_name; - std::string object_name; - - S32 chat_channel; - msg->getString("Data", "FirstName", first_name); - msg->getString("Data", "LastName", last_name); - msg->getString("Data", "ObjectName", object_name); - msg->getString("Data", "Message", message); - msg->getS32("Data", "ChatChannel", chat_channel); - - // unused for now - LLUUID image_id; - msg->getUUID("Data", "ImageID", image_id); - - payload["sender"] = msg->getSender().getIPandPort(); - payload["object_id"] = object_id; - payload["chat_channel"] = chat_channel; - payload["object_name"] = object_name; - - // build up custom form - S32 button_count = msg->getNumberOfBlocks("Buttons"); - if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) - { - LL_WARNS() << "Too many script dialog buttons - omitting some" << LL_ENDL; - button_count = SCRIPT_DIALOG_MAX_BUTTONS; - } - - LLNotificationForm form; - for (i = 0; i < button_count; i++) - { - std::string tdesc; - msg->getString("Buttons", "ButtonLabel", tdesc, i); - form.addElement("button", std::string(tdesc)); - } - - LLSD args; - args["TITLE"] = object_name; - args["MESSAGE"] = message; - LLNotificationPtr notification; - if (!first_name.empty()) - { - args["NAME"] = LLCacheName::buildFullName(first_name, last_name); - notification = LLNotifications::instance().add( - LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); - } - else - { - args["GROUPNAME"] = last_name; - notification = LLNotifications::instance().add( - LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD())); - } + } + + if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id)) + { + return; + } + + std::string message; + std::string first_name; + std::string last_name; + std::string object_name; + + S32 chat_channel; + msg->getString("Data", "FirstName", first_name); + msg->getString("Data", "LastName", last_name); + msg->getString("Data", "ObjectName", object_name); + msg->getString("Data", "Message", message); + msg->getS32("Data", "ChatChannel", chat_channel); + + // unused for now + LLUUID image_id; + msg->getUUID("Data", "ImageID", image_id); + + payload["sender"] = msg->getSender().getIPandPort(); + payload["object_id"] = object_id; + payload["chat_channel"] = chat_channel; + payload["object_name"] = object_name; + + // build up custom form + S32 button_count = msg->getNumberOfBlocks("Buttons"); + if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) + { + LL_WARNS() << "Too many script dialog buttons - omitting some" << LL_ENDL; + button_count = SCRIPT_DIALOG_MAX_BUTTONS; + } + + LLNotificationForm form; + for (i = 0; i < button_count; i++) + { + std::string tdesc; + msg->getString("Buttons", "ButtonLabel", tdesc, i); + form.addElement("button", std::string(tdesc)); + } + + LLSD args; + args["TITLE"] = object_name; + args["MESSAGE"] = message; + LLNotificationPtr notification; + if (!first_name.empty()) + { + args["NAME"] = LLCacheName::buildFullName(first_name, last_name); + notification = LLNotifications::instance().add( + LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); + } + else + { + args["GROUPNAME"] = last_name; + notification = LLNotifications::instance().add( + LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD())); + } } //--------------------------------------------------------------------------- @@ -6675,14 +6675,14 @@ std::vector<LLSD> gLoadUrlList; bool callback_load_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"].asString()); + } - return false; + return false; } static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); @@ -6690,42 +6690,42 @@ static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", ca // Display confirmation dialog. void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group) { - std::vector<LLSD>::iterator it; - for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) - { - LLSD load_url_info = *it; - if (load_url_info["owner_id"].asUUID() == id) - { - it = gLoadUrlList.erase(it); - - std::string owner_name; - if (is_group) - { - owner_name = full_name + LLTrans::getString("Group"); - } - else - { - owner_name = full_name; - } - - // For legacy name-only mutes. - if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name)) - { - continue; - } - LLSD args; - args["URL"] = load_url_info["url"].asString(); - args["MESSAGE"] = load_url_info["message"].asString();; - args["OBJECTNAME"] = load_url_info["object_name"].asString(); - args["NAME_SLURL"] = LLSLURL(is_group ? "group" : "agent", id, "about").getSLURLString(); - - LLNotificationsUtil::add("LoadWebPage", args, load_url_info); - } - else - { - ++it; - } - } + std::vector<LLSD>::iterator it; + for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) + { + LLSD load_url_info = *it; + if (load_url_info["owner_id"].asUUID() == id) + { + it = gLoadUrlList.erase(it); + + std::string owner_name; + if (is_group) + { + owner_name = full_name + LLTrans::getString("Group"); + } + else + { + owner_name = full_name; + } + + // For legacy name-only mutes. + if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name)) + { + continue; + } + LLSD args; + args["URL"] = load_url_info["url"].asString(); + args["MESSAGE"] = load_url_info["message"].asString();; + args["OBJECTNAME"] = load_url_info["object_name"].asString(); + args["NAME_SLURL"] = LLSLURL(is_group ? "group" : "agent", id, "about").getSLURLString(); + + LLNotificationsUtil::add("LoadWebPage", args, load_url_info); + } + else + { + ++it; + } + } } // We've got the name of the person who owns the object hurling the url. @@ -6736,296 +6736,296 @@ void callback_load_url_avatar_name(const LLUUID& id, const LLAvatarName& av_name void process_load_url(LLMessageSystem* msg, void**) { - LLUUID object_id; - LLUUID owner_id; - BOOL owner_is_group; - char object_name[256]; /* Flawfinder: ignore */ - char message[256]; /* Flawfinder: ignore */ - char url[256]; /* Flawfinder: ignore */ - - msg->getString("Data", "ObjectName", 256, object_name); - msg->getUUID( "Data", "ObjectID", object_id); - msg->getUUID( "Data", "OwnerID", owner_id); - msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); - msg->getString("Data", "Message", 256, message); - msg->getString("Data", "URL", 256, url); - - LLSD payload; - payload["object_id"] = object_id; - payload["owner_id"] = owner_id; - payload["owner_is_group"] = owner_is_group; - payload["object_name"] = object_name; - payload["message"] = message; - payload["url"] = url; - - // URL is safety checked in load_url above - - // Check if object or owner is muted - if (LLMuteList::getInstance()->isMuted(object_id, object_name) || - LLMuteList::getInstance()->isMuted(owner_id)) - { - LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<<LL_ENDL; - return; - } - - // Add to list of pending name lookups - gLoadUrlList.push_back(payload); - - if (owner_is_group) - { - gCacheName->getGroup(owner_id, boost::bind(&callback_load_url_name, _1, _2, _3)); - } - else - { - LLAvatarNameCache::get(owner_id, boost::bind(&callback_load_url_avatar_name, _1, _2)); - } + LLUUID object_id; + LLUUID owner_id; + BOOL owner_is_group; + char object_name[256]; /* Flawfinder: ignore */ + char message[256]; /* Flawfinder: ignore */ + char url[256]; /* Flawfinder: ignore */ + + msg->getString("Data", "ObjectName", 256, object_name); + msg->getUUID( "Data", "ObjectID", object_id); + msg->getUUID( "Data", "OwnerID", owner_id); + msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); + msg->getString("Data", "Message", 256, message); + msg->getString("Data", "URL", 256, url); + + LLSD payload; + payload["object_id"] = object_id; + payload["owner_id"] = owner_id; + payload["owner_is_group"] = owner_is_group; + payload["object_name"] = object_name; + payload["message"] = message; + payload["url"] = url; + + // URL is safety checked in load_url above + + // Check if object or owner is muted + if (LLMuteList::getInstance()->isMuted(object_id, object_name) || + LLMuteList::getInstance()->isMuted(owner_id)) + { + LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<<LL_ENDL; + return; + } + + // Add to list of pending name lookups + gLoadUrlList.push_back(payload); + + if (owner_is_group) + { + gCacheName->getGroup(owner_id, boost::bind(&callback_load_url_name, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(owner_id, boost::bind(&callback_load_url_avatar_name, _1, _2)); + } } void callback_download_complete(void** data, S32 result, LLExtStat ext_status) { - std::string* filepath = (std::string*)data; - LLSD args; - args["DOWNLOAD_PATH"] = *filepath; - LLNotificationsUtil::add("FinishedRawDownload", args); - delete filepath; + std::string* filepath = (std::string*)data; + LLSD args; + args["DOWNLOAD_PATH"] = *filepath; + LLNotificationsUtil::add("FinishedRawDownload", args); + delete filepath; } void process_initiate_download(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL; - return; - } - - std::string sim_filename; - std::string viewer_filename; - msg->getString("FileData", "SimFilename", sim_filename); - msg->getString("FileData", "ViewerFilename", viewer_filename); - - if (!gXferManager->validateFileForRequest(viewer_filename)) - { - LL_WARNS() << "SECURITY: Unauthorized download to local file " << viewer_filename << LL_ENDL; - return; - } - gXferManager->requestFile(viewer_filename, - sim_filename, - LL_PATH_NONE, - msg->getSender(), - FALSE, // don't delete remote - callback_download_complete, - (void**)new std::string(viewer_filename)); + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL; + return; + } + + std::string sim_filename; + std::string viewer_filename; + msg->getString("FileData", "SimFilename", sim_filename); + msg->getString("FileData", "ViewerFilename", viewer_filename); + + if (!gXferManager->validateFileForRequest(viewer_filename)) + { + LL_WARNS() << "SECURITY: Unauthorized download to local file " << viewer_filename << LL_ENDL; + return; + } + gXferManager->requestFile(viewer_filename, + sim_filename, + LL_PATH_NONE, + msg->getSender(), + FALSE, // don't delete remote + callback_download_complete, + (void**)new std::string(viewer_filename)); } void process_script_teleport_request(LLMessageSystem* msg, void**) { - if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return; + if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return; + + std::string object_name; + std::string sim_name; + LLVector3 pos; + LLVector3 look_at; - std::string object_name; - std::string sim_name; - LLVector3 pos; - LLVector3 look_at; + msg->getString("Data", "ObjectName", object_name); + msg->getString("Data", "SimName", sim_name); + msg->getVector3("Data", "SimPosition", pos); + msg->getVector3("Data", "LookAt", look_at); - msg->getString("Data", "ObjectName", object_name); - msg->getString("Data", "SimName", sim_name); - msg->getVector3("Data", "SimPosition", pos); - msg->getVector3("Data", "LookAt", look_at); + LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); + if(instance) + { + LL_INFOS() << "Object named " << object_name + << " is offering TP to region " + << sim_name << " position " << pos + << LL_ENDL; + + instance->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); + LLFloaterReg::showInstance("world_map", "center"); + } - LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); - if(instance) - { - LL_INFOS() << "Object named " << object_name - << " is offering TP to region " - << sim_name << " position " << pos - << LL_ENDL; + // remove above two lines and replace with below line + // to re-enable parcel browser for llMapDestination() + // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); - instance->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); - LLFloaterReg::showInstance("world_map", "center"); - } - - // remove above two lines and replace with below line - // to re-enable parcel browser for llMapDestination() - // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); - } void process_covenant_reply(LLMessageSystem* msg, void**) { - LLUUID covenant_id, estate_owner_id; - std::string estate_name; - U32 covenant_timestamp; - msg->getUUID("Data", "CovenantID", covenant_id); - msg->getU32("Data", "CovenantTimestamp", covenant_timestamp); - msg->getString("Data", "EstateName", estate_name); - msg->getUUID("Data", "EstateOwnerID", estate_owner_id); - - LLPanelEstateCovenant::updateEstateName(estate_name); - LLPanelLandCovenant::updateEstateName(estate_name); - LLPanelEstateInfo::updateEstateName(estate_name); - LLFloaterBuyLand::updateEstateName(estate_name); - - std::string owner_name = - LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); - LLPanelEstateCovenant::updateEstateOwnerName(owner_name); - LLPanelLandCovenant::updateEstateOwnerName(owner_name); - LLPanelEstateInfo::updateEstateOwnerName(owner_name); - LLFloaterBuyLand::updateEstateOwnerName(owner_name); - - LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile"); - if (panel) - { - panel->updateEstateName(estate_name); - panel->updateEstateOwnerName(owner_name); - } - - // standard message, not from system - std::string last_modified; - if (covenant_timestamp == 0) - { - last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text"); - } - else - { - last_modified = LLTrans::getString("covenant_last_modified")+"[" - +LLTrans::getString("LTimeWeek")+"] [" - +LLTrans::getString("LTimeMonth")+"] [" - +LLTrans::getString("LTimeDay")+"] [" - +LLTrans::getString("LTimeHour")+"]:[" - +LLTrans::getString("LTimeMin")+"]:[" - +LLTrans::getString("LTimeSec")+"] [" - +LLTrans::getString("LTimeYear")+"]"; - LLSD substitution; - substitution["datetime"] = (S32) covenant_timestamp; - LLStringUtil::format (last_modified, substitution); - } - - LLPanelEstateCovenant::updateLastModified(last_modified); - LLPanelLandCovenant::updateLastModified(last_modified); - LLFloaterBuyLand::updateLastModified(last_modified); - - // load the actual covenant asset data - const BOOL high_priority = TRUE; - if (covenant_id.notNull()) - { - gAssetStorage->getEstateAsset(gAgent.getRegionHost(), - gAgent.getID(), - gAgent.getSessionID(), - covenant_id, + LLUUID covenant_id, estate_owner_id; + std::string estate_name; + U32 covenant_timestamp; + msg->getUUID("Data", "CovenantID", covenant_id); + msg->getU32("Data", "CovenantTimestamp", covenant_timestamp); + msg->getString("Data", "EstateName", estate_name); + msg->getUUID("Data", "EstateOwnerID", estate_owner_id); + + LLPanelEstateCovenant::updateEstateName(estate_name); + LLPanelLandCovenant::updateEstateName(estate_name); + LLPanelEstateInfo::updateEstateName(estate_name); + LLFloaterBuyLand::updateEstateName(estate_name); + + std::string owner_name = + LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); + LLPanelEstateCovenant::updateEstateOwnerName(owner_name); + LLPanelLandCovenant::updateEstateOwnerName(owner_name); + LLPanelEstateInfo::updateEstateOwnerName(owner_name); + LLFloaterBuyLand::updateEstateOwnerName(owner_name); + + LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile"); + if (panel) + { + panel->updateEstateName(estate_name); + panel->updateEstateOwnerName(owner_name); + } + + // standard message, not from system + std::string last_modified; + if (covenant_timestamp == 0) + { + last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text"); + } + else + { + last_modified = LLTrans::getString("covenant_last_modified")+"[" + +LLTrans::getString("LTimeWeek")+"] [" + +LLTrans::getString("LTimeMonth")+"] [" + +LLTrans::getString("LTimeDay")+"] [" + +LLTrans::getString("LTimeHour")+"]:[" + +LLTrans::getString("LTimeMin")+"]:[" + +LLTrans::getString("LTimeSec")+"] [" + +LLTrans::getString("LTimeYear")+"]"; + LLSD substitution; + substitution["datetime"] = (S32) covenant_timestamp; + LLStringUtil::format (last_modified, substitution); + } + + LLPanelEstateCovenant::updateLastModified(last_modified); + LLPanelLandCovenant::updateLastModified(last_modified); + LLFloaterBuyLand::updateLastModified(last_modified); + + // load the actual covenant asset data + const BOOL high_priority = TRUE; + if (covenant_id.notNull()) + { + gAssetStorage->getEstateAsset(gAgent.getRegionHost(), + gAgent.getID(), + gAgent.getSessionID(), + covenant_id, LLAssetType::AT_NOTECARD, - ET_Covenant, + ET_Covenant, onCovenantLoadComplete, - NULL, - high_priority); - } - else - { - std::string covenant_text; - if (estate_owner_id.isNull()) - { - // mainland - covenant_text = LLTrans::getString("RegionNoCovenant"); - } - else - { - covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner"); - } - LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id); - if (panel) - { - panel->updateCovenantText(covenant_text); - } - } + NULL, + high_priority); + } + else + { + std::string covenant_text; + if (estate_owner_id.isNull()) + { + // mainland + covenant_text = LLTrans::getString("RegionNoCovenant"); + } + else + { + covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner"); + } + LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); + LLPanelLandCovenant::updateCovenantText(covenant_text); + LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id); + if (panel) + { + panel->updateCovenantText(covenant_text); + } + } } void onCovenantLoadComplete(const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) -{ - LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; - std::string covenant_text; - if(0 == status) - { - LLFileSystem file(asset_uuid, type, LLFileSystem::READ); - - S32 file_length = file.getSize(); - - std::vector<char> buffer(file_length+1); - file.read((U8*)&buffer[0], file_length); - // put a EOS at the end - buffer[file_length] = '\0'; - - if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) - { - LLViewerTextEditor::Params params; - params.name("temp"); - params.max_text_length(file_length+1); - LLViewerTextEditor * editor = LLUICtrlFactory::create<LLViewerTextEditor> (params); - if( !editor->importBuffer( &buffer[0], file_length+1 ) ) - { - LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; - covenant_text = "Problem importing estate covenant."; - } - else - { - // Version 0 (just text, doesn't include version number) - covenant_text = editor->getText(); - } - delete editor; - } - else - { - LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL; - covenant_text = "Problem importing estate covenant: Covenant file format error."; - } - } - else - { - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || - LL_ERR_FILE_EMPTY == status) - { - covenant_text = "Estate covenant notecard is missing from database."; - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) - { - covenant_text = "Insufficient permissions to view estate covenant."; - } - else - { - covenant_text = "Unable to load estate covenant at this time."; - } - - LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL; - } - LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); - - LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile"); - if (panel) - { - panel->updateCovenantText(covenant_text); - } + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; + std::string covenant_text; + if(0 == status) + { + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); + + S32 file_length = file.getSize(); + + std::vector<char> buffer(file_length+1); + file.read((U8*)&buffer[0], file_length); + // put a EOS at the end + buffer[file_length] = '\0'; + + if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) + { + LLViewerTextEditor::Params params; + params.name("temp"); + params.max_text_length(file_length+1); + LLViewerTextEditor * editor = LLUICtrlFactory::create<LLViewerTextEditor> (params); + if( !editor->importBuffer( &buffer[0], file_length+1 ) ) + { + LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; + covenant_text = "Problem importing estate covenant."; + } + else + { + // Version 0 (just text, doesn't include version number) + covenant_text = editor->getText(); + } + delete editor; + } + else + { + LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL; + covenant_text = "Problem importing estate covenant: Covenant file format error."; + } + } + else + { + if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + covenant_text = "Estate covenant notecard is missing from database."; + } + else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + { + covenant_text = "Insufficient permissions to view estate covenant."; + } + else + { + covenant_text = "Unable to load estate covenant at this time."; + } + + LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL; + } + LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); + LLPanelLandCovenant::updateCovenantText(covenant_text); + LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); + + LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile"); + if (panel) + { + panel->updateCovenantText(covenant_text); + } } void process_feature_disabled_message(LLMessageSystem* msg, void**) { - // Handle Blacklisted feature simulator response... - LLUUID agentID; - LLUUID transactionID; - std::string messageText; - msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); - - LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; + // Handle Blacklisted feature simulator response... + LLUUID agentID; + LLUUID transactionID; + std::string messageText; + msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); + msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); + msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); + + LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; } // ------------------------------------------------------------ @@ -7033,8 +7033,8 @@ void process_feature_disabled_message(LLMessageSystem* msg, void**) // ------------------------------------------------------------ void invalid_message_callback(LLMessageSystem* msg, - void*, - EMessageException exception) + void*, + EMessageException exception) { LLAppViewer::instance()->badNetworkHandler(); } @@ -7044,8 +7044,8 @@ void invalid_message_callback(LLMessageSystem* msg, void LLOfferInfo::forceResponse(InventoryOfferResponse response) { - LLNotification::Params params("UserGiveItem"); - params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); - LLNotifications::instance().forceResponse(params, response); + LLNotification::Params params("UserGiveItem"); + params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); + LLNotifications::instance().forceResponse(params, response); } diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index 8cf86910e7..d9575e0b2b 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,11 +46,11 @@ const F32 AUTOPLAY_SIZE = 24*24; // how big the texture must be (pixel are const F32 AUTOPLAY_SPEED = 0.1f; // how slow should the agent be moving to autoplay LLViewerParcelMediaAutoPlay::LLViewerParcelMediaAutoPlay() : - LLEventTimer(1), - - mLastParcelID(-1), - mPlayed(FALSE), - mTimeInParcel(0) + LLEventTimer(1), + + mLastParcelID(-1), + mPlayed(FALSE), + mTimeInParcel(0) { } @@ -62,101 +62,101 @@ void LLViewerParcelMediaAutoPlay::playStarted() bool LLViewerParcelMediaAutoPlay::tick() { - LLParcel *this_parcel = NULL; - LLViewerRegion *this_region = NULL; - std::string this_media_url; - std::string this_media_type; - LLUUID this_media_texture_id; - S32 this_parcel_id = 0; - LLUUID this_region_id; - - this_region = gAgent.getRegion(); - - if (this_region) - { - this_region_id = this_region->getRegionID(); - } - - this_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - - if (this_parcel) - { - this_media_url = this_parcel->getMediaURL(); - - this_media_type = this_parcel->getMediaType(); - - this_media_texture_id = this_parcel->getMediaID(); - - this_parcel_id = this_parcel->getLocalID(); - } - - if (this_parcel_id != mLastParcelID || - this_region_id != mLastRegionID) - { - // we've entered a new parcel - mPlayed = FALSE; // we haven't autoplayed yet - mTimeInParcel = 0; // reset our timer - mLastParcelID = this_parcel_id; - mLastRegionID = this_region_id; - } - - mTimeInParcel += mPeriod; // increase mTimeInParcel by the amount of time between ticks - - if ((!mPlayed) && // if we've never played - (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds - (!this_media_url.empty()) && // and if the parcel has media - (stricmp(this_media_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) && - (!LLViewerParcelMedia::getInstance()->hasParcelMedia())) // and if the media is not already playing - { - if (this_media_texture_id.notNull()) // and if the media texture is good - { - LLViewerMediaTexture *image = LLViewerTextureManager::getMediaTexture(this_media_texture_id, FALSE) ; - - F32 image_size = 0; - - if (image) - { - image_size = image->getMaxVirtualSize() ; - } - - if (gAgent.getVelocity().magVec() < AUTOPLAY_SPEED) // and if the agent is stopped (slow enough) - { - if (image_size > AUTOPLAY_SIZE) // and if the target texture is big enough on screen - { - if (this_parcel) - { - static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); - - switch (autoplay_mode()) - { - case 0: - // Disabled - break; - case 1: - // Play, default value for ParcelMediaAutoPlayEnable - LLViewerParcelMedia::getInstance()->play(this_parcel); - break; - case 2: - default: - { - // Ask - LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), - this_parcel->getLocalID(), - this_parcel->getMediaURL(), - onStartMediaResponse); - break; - } - } - } - - mPlayed = TRUE; - } - } - } - } - - - return false; // continue ticking forever please. + LLParcel *this_parcel = NULL; + LLViewerRegion *this_region = NULL; + std::string this_media_url; + std::string this_media_type; + LLUUID this_media_texture_id; + S32 this_parcel_id = 0; + LLUUID this_region_id; + + this_region = gAgent.getRegion(); + + if (this_region) + { + this_region_id = this_region->getRegionID(); + } + + this_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + if (this_parcel) + { + this_media_url = this_parcel->getMediaURL(); + + this_media_type = this_parcel->getMediaType(); + + this_media_texture_id = this_parcel->getMediaID(); + + this_parcel_id = this_parcel->getLocalID(); + } + + if (this_parcel_id != mLastParcelID || + this_region_id != mLastRegionID) + { + // we've entered a new parcel + mPlayed = FALSE; // we haven't autoplayed yet + mTimeInParcel = 0; // reset our timer + mLastParcelID = this_parcel_id; + mLastRegionID = this_region_id; + } + + mTimeInParcel += mPeriod; // increase mTimeInParcel by the amount of time between ticks + + if ((!mPlayed) && // if we've never played + (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds + (!this_media_url.empty()) && // and if the parcel has media + (stricmp(this_media_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) && + (!LLViewerParcelMedia::getInstance()->hasParcelMedia())) // and if the media is not already playing + { + if (this_media_texture_id.notNull()) // and if the media texture is good + { + LLViewerMediaTexture *image = LLViewerTextureManager::getMediaTexture(this_media_texture_id, FALSE) ; + + F32 image_size = 0; + + if (image) + { + image_size = image->getMaxVirtualSize() ; + } + + if (gAgent.getVelocity().magVec() < AUTOPLAY_SPEED) // and if the agent is stopped (slow enough) + { + if (image_size > AUTOPLAY_SIZE) // and if the target texture is big enough on screen + { + if (this_parcel) + { + static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); + + switch (autoplay_mode()) + { + case 0: + // Disabled + break; + case 1: + // Play, default value for ParcelMediaAutoPlayEnable + LLViewerParcelMedia::getInstance()->play(this_parcel); + break; + case 2: + default: + { + // Ask + LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), + this_parcel->getLocalID(), + this_parcel->getMediaURL(), + onStartMediaResponse); + break; + } + } + } + + mPlayed = TRUE; + } + } + } + } + + + return false; // continue ticking forever please. } //static diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index 9367c2a629..506fb38901 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,20 +33,20 @@ // timer to automatically play media class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerParcelMediaAutoPlay> { - LLSINGLETON(LLViewerParcelMediaAutoPlay); + LLSINGLETON(LLViewerParcelMediaAutoPlay); public: - bool tick() override; - static void playStarted(); + bool tick() override; + static void playStarted(); private: // for askToPlay - static void onStartMediaResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + static void onStartMediaResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); private: - S32 mLastParcelID; - LLUUID mLastRegionID; - BOOL mPlayed; - F32 mTimeInParcel; + S32 mLastParcelID; + LLUUID mLastRegionID; + BOOL mPlayed; + F32 mTimeInParcel; }; -- cgit v1.2.3 From 2f25f87ee719a79efc8316079f3c881eddb4d266 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Wed, 15 May 2024 19:10:17 +0200 Subject: secondlife/jira-archive-internal#70713 Combine recently and frequently used --- indra/newview/llfloateremojipicker.cpp | 59 ++-------------------- indra/newview/llfloateremojipicker.h | 1 - .../skins/default/xui/en/floater_emoji_picker.xml | 1 - 3 files changed, 4 insertions(+), 57 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index baad75ed8e..c9d14c45f8 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -57,8 +57,7 @@ static const S32 USED_EMOJIS_IMAGE_INDEX = 0x23F2; // https://www.compart.com/en/unicode/U+1F6D1 static const S32 EMPTY_LIST_IMAGE_INDEX = 0x1F6D1; // The following categories should follow the required alphabetic order -static const std::string RECENTLY_USED_CATEGORY = "1 recently used"; -static const std::string FREQUENTLY_USED_CATEGORY = "2 frequently used"; +static const std::string FREQUENTLY_USED_CATEGORY = "frequently used"; // Floater state related variables static std::list<llwchar> sRecentlyUsed; @@ -445,11 +444,10 @@ void LLFloaterEmojiPicker::fillGroups() // Create button for "All categories" createGroupButton(params, rect, ALL_EMOJIS_IMAGE_INDEX); - // Create group and button for "Recently used" and/or "Frequently used" - if (!sRecentlyUsed.empty() || !sFrequentlyUsed.empty()) + // Create group and button for "Frequently used" + if (!sFrequentlyUsed.empty()) { std::map<std::string, std::vector<LLEmojiSearchResult>> cats; - fillCategoryRecentlyUsed(cats); fillCategoryFrequentlyUsed(cats); if (!cats.empty()) @@ -480,40 +478,6 @@ void LLFloaterEmojiPicker::fillGroups() resizeGroupButtons(); } -void LLFloaterEmojiPicker::fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats) -{ - if (sRecentlyUsed.empty()) - return; - - std::vector<LLEmojiSearchResult> emojis; - - // In case of empty mFilterPattern we'd use sRecentlyUsed directly - if (!mFilterPattern.empty()) - { - // List all emojis in "Recently used" - const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr(); - std::size_t begin, end; - for (llwchar emoji : sRecentlyUsed) - { - auto e2d = emoji2descr.find(emoji); - if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty()) - { - for (const std::string& shortcode : e2d->second->ShortCodes) - { - if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) - { - emojis.emplace_back(emoji, shortcode, begin, end); - } - } - } - } - if (emojis.empty()) - return; - } - - cats.emplace(std::make_pair(RECENTLY_USED_CATEGORY, emojis)); -} - void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats) { if (sFrequentlyUsed.empty()) @@ -755,7 +719,6 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes { // Place the category title std::string title = - category == RECENTLY_USED_CATEGORY ? getString("title_for_recently_used") : category == FREQUENTLY_USED_CATEGORY ? getString("title_for_frequently_used") : isupper(category.front()) ? category : LLStringUtil::capitalize(category); LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, title); @@ -768,21 +731,7 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes { const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr(); LLEmojiSearchResult emoji { 0, "", 0, 0 }; - if (category == RECENTLY_USED_CATEGORY) - { - for (llwchar code : sRecentlyUsed) - { - const LLEmojiDictionary::emoji2descr_map_t::const_iterator& e2d = emoji2descr.find(code); - if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty()) - { - emoji.Character = code; - emoji.String = e2d->second->ShortCodes.front(); - createEmojiIcon(emoji, category, row_panel_params, row_list_params, icon_params, - icon_rect, max_icons, bg, row, icon_index); - } - } - } - else if (category == FREQUENTLY_USED_CATEGORY) + if (category == FREQUENTLY_USED_CATEGORY) { for (const auto& code : sFrequentlyUsed) { diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h index 05b4826e37..bc64cb1f35 100644 --- a/indra/newview/llfloateremojipicker.h +++ b/indra/newview/llfloateremojipicker.h @@ -60,7 +60,6 @@ public: private: void initialize(); void fillGroups(); - void fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats); void fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats); void fillGroupEmojis(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats, U32 index); void createGroupButton(LLButton::Params& params, const LLRect& rect, llwchar emoji); diff --git a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml index e4b8f13df7..f642ca93b7 100644 --- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml @@ -13,7 +13,6 @@ chrome="true" height="350" width="304"> - <floater.string name="title_for_recently_used" value="Recently used"/> <floater.string name="title_for_frequently_used" value="Frequently used"/> <floater.string name="text_no_emoji_for_filter" value="No emoji found for '[FILTER]'"/> <scroll_container -- cgit v1.2.3 From c808d849aa6aa17db95a7814e6eb6bc5162ba816 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 16 May 2024 02:29:52 +0300 Subject: adjust the flag to be untrusted block/allow/throttle --- indra/newview/lllocationinputctrl.cpp | 2 +- indra/newview/lluilistener.cpp | 15 ++++++++++++++- indra/newview/llviewermenu.cpp | 34 ++++++++++++++++++---------------- 3 files changed, 33 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 9fa35e3bd9..629b21e264 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -378,7 +378,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) addChild(mParcelIcon[SEE_AVATARS_ICON]); // Register callbacks and load the location field context menu (NB: the order matters). - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2)); + LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add("Navbar.Action", LLUICtrl::LLCommitCallbackInfo(boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2))); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2)); setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index c9e5cf00d6..938ef95b5c 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -38,6 +38,7 @@ #include "lluictrl.h" #include "llerror.h" +#define THROTTLE_PERIOD 1 // required seconds between throttled functions LLUIListener::LLUIListener(): LLEventAPI("UI", @@ -59,6 +60,7 @@ LLUIListener::LLUIListener(): void LLUIListener::call(const LLSD& event) const { + static F64 last_throttle_time = 0.0; Response response(LLSD(), event); LLUICtrl::LLCommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(event["function"]); if (!info ) @@ -66,11 +68,22 @@ void LLUIListener::call(const LLSD& event) const response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << "was not found")); return; } - if (!info->mAllowUntrusted) + if (info->mHandleUntrusted == LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK) { response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << " is not allowed to be called from the script")); return; } + if (info->mHandleUntrusted == LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_THROTTLE) + { + F64 cur_time = LLTimer::getElapsedSeconds(); + if (cur_time < last_throttle_time + THROTTLE_PERIOD) + { + LL_WARNS("LLUIListener") << "Throttled function " << std::quoted(event["function"].asString()) << LL_ENDL; + return; + } + last_throttle_time = cur_time; + } + LLUICtrl::commit_callback_t func = info->callback_func; if (info->callback_func) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 756e002540..513a804d97 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9361,8 +9361,10 @@ void initialize_edit_menu() view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); } -#define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func, true)) -#define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func)) +const LLUICtrl::LLCommitCallbackInfo::EUntrustedCall UNTRUSTED_BLOCK = LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK; +#define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func)) +#define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func, UNTRUSTED_BLOCK)) + void initialize_spellcheck_menu() { LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); @@ -9676,7 +9678,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); // Advanced > Cache - view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache", false); + view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache", UNTRUSTED_BLOCK); // Advanced > Recorder view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); @@ -9685,19 +9687,19 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); // Advanced > Debugging - view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint", false); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror", false); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg", false); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess", false); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro", false); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop", false); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException", false); - view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException", false); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro", false); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash", false); - view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash", false); - view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash", false); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer", false); + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer", UNTRUSTED_BLOCK); // Advanced (toplevel) view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); -- cgit v1.2.3 From 83d91c82f42f6c024e7e4dc6d6a64b067ad6117a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 16 May 2024 04:16:29 +0300 Subject: set UNTRUSTED_ALLOW as default; some LLCommitCallbackInfo clean up --- indra/newview/llviewermenu.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 5602b5bfda..83ffa2ae59 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9395,9 +9395,9 @@ void initialize_edit_menu() } -const LLUICtrl::LLCommitCallbackInfo::EUntrustedCall UNTRUSTED_BLOCK = LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK; -#define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func)) -#define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, LLUICtrl::LLCommitCallbackInfo(func, UNTRUSTED_BLOCK)) +typedef LLUICtrl::LLCommitCallbackInfo cb_info; +#define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func)) +#define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_BLOCK)) void initialize_spellcheck_menu() { @@ -9617,7 +9617,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); - view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache", cb_info::UNTRUSTED_BLOCK); #ifdef TOGGLE_HACKED_GODLIKE_VIEWER view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); @@ -9712,7 +9712,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); // Advanced > Cache - view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache", cb_info::UNTRUSTED_BLOCK); // Advanced > Recorder view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); @@ -9721,19 +9721,19 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder"); // Advanced > Debugging - view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash", UNTRUSTED_BLOCK); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer", UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash", cb_info::UNTRUSTED_BLOCK); + view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer", cb_info::UNTRUSTED_BLOCK); // Advanced (toplevel) view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); -- cgit v1.2.3 From 0f00dc2f658869cc73a18b03b024a6cc88964e0b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 22 May 2024 20:29:55 +0300 Subject: Add support for sending messages to Nearby chat from Lua script --- indra/newview/llchathistory.cpp | 39 +++++++++++++++++-------- indra/newview/llchathistory.h | 3 +- indra/newview/llchatitemscontainerctrl.cpp | 5 ++-- indra/newview/llchatitemscontainerctrl.h | 6 +++- indra/newview/llfloaterimnearbychat.cpp | 3 ++ indra/newview/llfloaterimnearbychathandler.cpp | 12 ++++++-- indra/newview/llfloaterimnearbychatlistener.cpp | 9 +++--- indra/newview/llfloaterimnearbychatlistener.h | 4 +-- indra/newview/llviewerchat.cpp | 9 ++++-- indra/newview/llviewermessage.cpp | 4 ++- indra/newview/scripts/lua/LLChat.lua | 17 +++++++++++ indra/newview/skins/default/xui/en/strings.xml | 4 ++- 12 files changed, 84 insertions(+), 31 deletions(-) create mode 100644 indra/newview/scripts/lua/LLChat.lua (limited to 'indra/newview') diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 4a08eace62..6f02a08020 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -125,6 +125,7 @@ public: mUserNameTextBox(NULL), mTimeBoxTextBox(NULL), mNeedsTimeBox(true), + mIsFromScript(false), mAvatarNameCacheConnection() {} @@ -658,11 +659,12 @@ public: const LLUUID& getAvatarId () const { return mAvatarID;} - void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args) + void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args, bool is_script) { mAvatarID = chat.mFromID; mSessionID = chat.mSessionID; mSourceType = chat.mSourceType; + mIsFromScript = is_script; // To be able to report a message, we need a copy of it's text // and it's easier to store text directly than trying to get @@ -732,7 +734,7 @@ public: username_end == (chat.mFromName.length() - 1)) { mFrom = chat.mFromName.substr(0, username_start); - user_name->setValue(mFrom); + user_name->setValue(mIsFromScript ? LLTrans::getString("ScriptBy") + mFrom : mFrom); if (gSavedSettings.getBOOL("NameTagShowUsernames")) { @@ -774,7 +776,7 @@ public: switch (mSourceType) { case CHAT_SOURCE_AGENT: - icon->setValue(chat.mFromID); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : chat.mFromID); break; case CHAT_SOURCE_OBJECT: icon->setValue(LLSD("OBJECT_Icon")); @@ -787,7 +789,7 @@ public: icon->setValue(LLSD("Command_Destinations_Icon")); break; case CHAT_SOURCE_UNKNOWN: - icon->setValue(LLSD("Unknown_Icon")); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : chat.mFromID); } // In case the message came from an object, save the object info @@ -1029,7 +1031,14 @@ private: mFrom = av_name.getDisplayName(); LLTextBox* user_name = getChild<LLTextBox>("user_name"); - user_name->setValue( LLSD(av_name.getDisplayName() ) ); + if(mIsFromScript) + { + user_name->setValue(LLSD(LLTrans::getString("ScriptBy") + av_name.getDisplayName())); + } + else + { + user_name->setValue(LLSD(av_name.getDisplayName())); + } user_name->setToolTip( av_name.getUserName() ); if (gSavedSettings.getBOOL("NameTagShowUsernames") && @@ -1071,6 +1080,8 @@ protected: bool mNeedsTimeBox; + bool mIsFromScript; + private: boost::signals2::connection mAvatarNameCacheConnection; }; @@ -1088,6 +1099,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p) mTopHeaderPad(p.top_header_pad), mBottomHeaderPad(p.bottom_header_pad), mIsLastMessageFromLog(false), + mIsLastFromScript(false), mNotifyAboutUnreadMsg(p.notify_unread_msg) { LLTextEditor::Params editor_params(p); @@ -1185,11 +1197,11 @@ LLView* LLChatHistory::getSeparator() return separator; } -LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args) +LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args, bool is_script) { LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); if (header) - header->setup(chat, style_params, args); + header->setup(chat, style_params, args, is_script); return header; } @@ -1258,8 +1270,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL name_params.color(name_color); name_params.readonly_color(name_color); - std::string prefix = chat.mText.substr(0, 4); - + bool is_lua = (chat.mText.substr(0, LUA_PREFIX.size()) == LUA_PREFIX); + std::string prefix = chat.mText.substr(is_lua ? LUA_PREFIX.size() : 0, 4); //IRC styled /me messages. bool irc_me = prefix == "/me " || prefix == "/me'"; @@ -1393,7 +1405,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL && mLastFromID == chat.mFromID && mLastMessageTime.notNull() && (new_message_time.secondsSinceEpoch() - mLastMessageTime.secondsSinceEpoch()) < 60.0 - && mIsLastMessageFromLog == message_from_log) //distinguish between current and previous chat session's histories + && mIsLastMessageFromLog == message_from_log //distinguish between current and previous chat session's histories + && mIsLastFromScript == is_lua) { view = getSeparator(); if (!view) @@ -1408,7 +1421,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL } else { - view = getHeader(chat, name_params, args); + view = getHeader(chat, name_params, args, is_lua); if (!view) { LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL; @@ -1437,6 +1450,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL mLastFromID = chat.mFromID; mLastMessageTime = new_message_time; mIsLastMessageFromLog = message_from_log; + mIsLastFromScript = is_lua; } // body of the message processing @@ -1491,7 +1505,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // usual messages showing else if (!teleport_separator) { - std::string message = irc_me ? chat.mText.substr(3) : chat.mText; + std::string message = is_lua ? chat.mText.substr(LUA_PREFIX.size()) : chat.mText; + message = irc_me ? message.substr(3) : message; //MESSAGE TEXT PROCESSING //*HACK getting rid of redundant sender names in system notifications sent using sender name (see EXT-5010) diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index b8364ff860..8acbea6ed5 100644 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -101,7 +101,7 @@ class LLChatHistory : public LLUICtrl * Builds a message header. * @return pointer to LLView header object. */ - LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args); + LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args, bool is_script = false); public: ~LLChatHistory(); LLSD getValue() const; @@ -127,6 +127,7 @@ class LLChatHistory : public LLUICtrl LLDate mLastMessageTime; bool mIsLastMessageFromLog; bool mNotifyAboutUnreadMsg; + bool mIsLastFromScript; //std::string mLastMessageTimeStr; std::string mMessageHeaderFilename; diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 2b875c708d..8eabe3d222 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -187,6 +187,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) int sType = notification["source"].asInteger(); mSourceType = (EChatSourceType)sType; + mIsFromScript = notification["is_lua"].asBoolean(); std::string color_name = notification["text_color"].asString(); @@ -214,7 +215,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) { std::string str_sender; - str_sender = fromName; + str_sender = mIsFromScript ? LLTrans::getString("ScriptBy") + fromName : fromName; str_sender+=" "; @@ -401,7 +402,7 @@ void LLFloaterIMNearbyChatToastPanel::draw() else if(mSourceType == CHAT_SOURCE_SYSTEM) icon->setValue(LLSD("SL_Logo")); else if(mSourceType == CHAT_SOURCE_AGENT) - icon->setValue(mFromID); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : mFromID); else if(!mFromID.isNull()) icon->setValue(mFromID); } diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index d041615060..7df00e8fd9 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -48,7 +48,8 @@ protected: LLFloaterIMNearbyChatToastPanel() : mIsDirty(false), - mSourceType(CHAT_SOURCE_OBJECT) + mSourceType(CHAT_SOURCE_OBJECT), + mIsFromScript(false) {}; public: ~LLFloaterIMNearbyChatToastPanel(){} @@ -58,6 +59,8 @@ public: const LLUUID& getFromID() const { return mFromID;} const std::string& getFromName() const { return mFromName; } + bool isFromScript() { return mIsFromScript; } + //void addText (const std::string& message , const LLStyle::Params& input_params = LLStyle::Params()); //void setMessage (const LLChat& msg); void snapToMessageHeight (); @@ -88,6 +91,7 @@ private: std::string mFromName; EChatSourceType mSourceType; LLChatMsgBox* mMsgText; + bool mIsFromScript; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index e64f468cbe..6b817c7cf1 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -52,6 +52,7 @@ #include "llfirstuse.h" #include "llfloaterimnearbychat.h" +#include "llfloaterimnearbychatlistener.h" #include "llagent.h" // gAgent #include "llgesturemgr.h" #include "llmultigesture.h" @@ -71,6 +72,8 @@ S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; +static LLFloaterIMNearbyChatListener sChatListener; + const S32 EXPANDED_HEIGHT = 266; const S32 COLLAPSED_HEIGHT = 60; const S32 EXPANDED_MIN_HEIGHT = 150; diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 77ceea19af..91d9cd56cf 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -301,12 +301,13 @@ void LLFloaterIMNearbyChatScreenChannel::addChat(LLSD& chat) { LLUUID fromID = chat["from_id"].asUUID(); // agent id or object id std::string from = chat["from"].asString(); + bool is_lua = chat["is_lua"].asBoolean(); LLToast* toast = m_active_toasts[0].get(); if (toast) { LLFloaterIMNearbyChatToastPanel* panel = dynamic_cast<LLFloaterIMNearbyChatToastPanel*>(toast->getPanel()); - if(panel && panel->messageID() == fromID && panel->getFromName() == from && panel->canAddText()) + if(panel && panel->messageID() == fromID && panel->getFromName() == from && panel->isFromScript() == is_lua && panel->canAddText()) { panel->addMessage(chat); toast->reshapeToPanel(); @@ -600,15 +601,19 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, std::string toast_msg; if (chat_msg.mChatStyle == CHAT_STYLE_IRC) { + if (chat_msg.mIsScript) + { + toast_msg += LLTrans::getString("ScriptStr"); + } if (!chat_msg.mFromName.empty()) { toast_msg += chat_msg.mFromName; } - toast_msg += chat_msg.mText.substr(3); + toast_msg += chat_msg.mText.substr(chat_msg.mIsScript ? LUA_PREFIX.size() + 3 : 3); } else { - toast_msg = chat_msg.mText; + toast_msg = chat_msg.mIsScript ? chat_msg.mText.substr(LUA_PREFIX.size()) : chat_msg.mText; } bool chat_overlaps = false; @@ -658,6 +663,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, chat["color_alpha"] = r_color_alpha; chat["font_size"] = (S32)LLViewerChat::getChatFontSize() ; chat["message"] = toast_msg; + chat["is_lua"] = chat_msg.mIsScript; channel->addChat(chat); } diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index 616acf0eae..d6dfe42639 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -36,10 +36,9 @@ #include "llviewercontrol.h" -LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar) +LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() : LLEventAPI("LLChatBar", - "LLChatBar listener to (e.g.) sendChat, etc."), - mChatbar(chatbar) + "LLChatBar listener to (e.g.) sendChat, etc.") { add("sendChat", "Send chat to the simulator:\n" @@ -54,7 +53,7 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyCh void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const { // Extract the data - std::string chat_text = chat_data["message"].asString(); + std::string chat_text = LUA_PREFIX + chat_data["message"].asString(); S32 channel = 0; if (chat_data.has("channel")) @@ -95,6 +94,6 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const } // Send it as if it was typed in - mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, ((BOOL)(channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); + LLFloaterIMNearbyChat::sendChatFromViewer(chat_to_send, type_o_chat, ((BOOL) (channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); } diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index 96184d95b3..0df0341d36 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -38,12 +38,10 @@ class LLFloaterIMNearbyChat; class LLFloaterIMNearbyChatListener : public LLEventAPI { public: - LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar); + LLFloaterIMNearbyChatListener(); private: void sendChat(LLSD const & chat_data) const; - - LLFloaterIMNearbyChat & mChatbar; }; #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 597cf3c98c..70c426740b 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -30,6 +30,7 @@ // newview includes #include "llagent.h" // gAgent #include "llslurl.h" +#include "lltrans.h" #include "lluicolor.h" #include "lluicolortable.h" #include "llviewercontrol.h" // gSavedSettings @@ -216,8 +217,7 @@ S32 LLViewerChat::getChatFontSize() //static void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg) { - std::string tmpmsg = chat.mText; - + std::string tmpmsg = chat.mIsScript ? chat.mText.substr(LUA_PREFIX.size()) : chat.mText; if(chat.mChatStyle == CHAT_STYLE_IRC) { formated_msg = chat.mFromName + tmpmsg.substr(3); @@ -227,6 +227,11 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg) formated_msg = tmpmsg; } + if (chat.mIsScript) + { + formated_msg = LLTrans::getString("ScriptStr") + formated_msg; + } + } //static diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 52bc2d9654..4fe5beceae 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2600,8 +2600,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) BOOL ircstyle = FALSE; + chat.mIsScript = (mesg.substr(0, LUA_PREFIX.size()) == LUA_PREFIX); + // Look for IRC-style emotes here so chatbubbles work - std::string prefix = mesg.substr(0, 4); + std::string prefix = mesg.substr(chat.mIsScript ? LUA_PREFIX.size() : 0, 4); if (prefix == "/me " || prefix == "/me'") { ircstyle = TRUE; diff --git a/indra/newview/scripts/lua/LLChat.lua b/indra/newview/scripts/lua/LLChat.lua new file mode 100644 index 0000000000..7db538e837 --- /dev/null +++ b/indra/newview/scripts/lua/LLChat.lua @@ -0,0 +1,17 @@ +leap = require 'leap' + +local LLChat = {} + +function LLChat.sendNearby(msg) + leap.send('LLChatBar', {op='sendChat', message=msg}) +end + +function LLChat.sendWhisper(msg) + leap.send('LLChatBar', {op='sendChat', type='whisper', message=msg}) +end + +function LLChat.sendShout(msg) + leap.send('LLChatBar', {op='sendChat', type='shout', message=msg}) +end + +return LLChat diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index bee58da6b0..76a2660dbb 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -534,7 +534,9 @@ http://secondlife.com/support for help fixing this problem. <string name="ChangeYourDefaultAnimations">Change your default animations</string> <string name="ForceSitAvatar">Force your avatar to sit</string> <string name="ChangeEnvSettings">Change your environment settings</string> - + <string name="ScriptBy" value="Script by "/> + <string name="ScriptStr" value="Script: "/> + <string name="NotConnected">Not Connected</string> <string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name --> <string name="JoinAnExperience"/><!-- intentionally blank --> -- cgit v1.2.3 From 85664b011e37c6c9926924f6fb72ceeb10d07833 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 22 May 2024 21:03:45 +0300 Subject: add throttle for sending messages; add simple demo script --- indra/newview/llfloaterimnearbychatlistener.cpp | 11 +++++++++++ indra/newview/scripts/lua/test_LLChat.lua | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 indra/newview/scripts/lua/test_LLChat.lua (limited to 'indra/newview') diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index d6dfe42639..e8fb510111 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -35,6 +35,7 @@ #include "llchat.h" #include "llviewercontrol.h" +static const F32 CHAT_THROTTLE_PERIOD = 1.f; LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() : LLEventAPI("LLChatBar", @@ -52,6 +53,16 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() // "sendChat" command void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const { + static F64 last_throttle_time = 0.0; + F64 cur_time = LLTimer::getElapsedSeconds(); + + if (cur_time < last_throttle_time + CHAT_THROTTLE_PERIOD) + { + LL_DEBUGS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL; + return; + } + last_throttle_time = cur_time; + // Extract the data std::string chat_text = LUA_PREFIX + chat_data["message"].asString(); diff --git a/indra/newview/scripts/lua/test_LLChat.lua b/indra/newview/scripts/lua/test_LLChat.lua new file mode 100644 index 0000000000..95bd218baa --- /dev/null +++ b/indra/newview/scripts/lua/test_LLChat.lua @@ -0,0 +1,18 @@ +LLChat = require 'LLChat' + +function generateRandomWord(length) + local alphabet = "abcdefghijklmnopqrstuvwxyz" + local word = "" + for i = 1, length do + local randomIndex = math.random(1, #alphabet) + word = word .. alphabet:sub(randomIndex, randomIndex) + end + return word +end + +local msg = "" +math.randomseed(os.time()) +for i = 1, math.random(1, 10) do + msg = msg .. " ".. generateRandomWord(math.random(1, 8)) +end +LLChat.sendNearby(msg) -- cgit v1.2.3 From c38e71411080af9e03646bbe34f766201d942afd Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Thu, 23 May 2024 13:13:47 +0300 Subject: mac build fix --- indra/newview/llchathistory.cpp | 4 ++-- indra/newview/llchatitemscontainerctrl.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 6f02a08020..54b0c171f1 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -776,7 +776,7 @@ public: switch (mSourceType) { case CHAT_SOURCE_AGENT: - icon->setValue(mIsFromScript ? LLSD("Inv_Script") : chat.mFromID); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(chat.mFromID)); break; case CHAT_SOURCE_OBJECT: icon->setValue(LLSD("OBJECT_Icon")); @@ -789,7 +789,7 @@ public: icon->setValue(LLSD("Command_Destinations_Icon")); break; case CHAT_SOURCE_UNKNOWN: - icon->setValue(mIsFromScript ? LLSD("Inv_Script") : chat.mFromID); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(chat.mFromID)); } // In case the message came from an object, save the object info diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 8eabe3d222..0561d56fe1 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -402,7 +402,7 @@ void LLFloaterIMNearbyChatToastPanel::draw() else if(mSourceType == CHAT_SOURCE_SYSTEM) icon->setValue(LLSD("SL_Logo")); else if(mSourceType == CHAT_SOURCE_AGENT) - icon->setValue(mIsFromScript ? LLSD("Inv_Script") : mFromID); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(mFromID)); else if(!mFromID.isNull()) icon->setValue(mFromID); } -- cgit v1.2.3 From 91a549fb1fca4924dec33a6206990b7d098cfd4e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 23 May 2024 13:26:38 -0400 Subject: More vestigial whitespace fixes --- indra/newview/lllocalgltfmaterials.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp index 91753349c8..8019be6f42 100644 --- a/indra/newview/lllocalgltfmaterials.cpp +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lllocalrendermaterials.cpp * @brief Local GLTF materials source * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,14 +51,14 @@ /*=======================================*/ /* Formal declarations, constants, etc. */ -/*=======================================*/ +/*=======================================*/ static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; static const S32 LL_LOCAL_UPDATE_RETRIES = 5; /*=======================================*/ /* LLLocalGLTFMaterial: unit class */ -/*=======================================*/ +/*=======================================*/ LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename, S32 index) : mFilename(filename) , mShortName(gDirUtilp->getBaseFileName(filename, true)) @@ -298,7 +298,7 @@ void LLLocalGLTFMaterialTimer::stopTimer() bool LLLocalGLTFMaterialTimer::tick() { - // todo: do on idle? No point in timer + // todo: do on idle? No point in timer LLLocalGLTFMaterialMgr::getInstance()->doUpdates(); return false; } -- cgit v1.2.3 From e2f179b9edebca1557ce3f774781bb9b9350b781 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 23 May 2024 15:02:12 -0400 Subject: Remove commented-out methods in a couple LLEventTimer subclasses. --- indra/newview/llappearancemgr.cpp | 3 --- indra/newview/lltoast.cpp | 9 --------- indra/newview/lltoast.h | 2 -- 3 files changed, 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 734ee277bf..30f07a873b 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -127,10 +127,7 @@ public: LLAppearanceMgr::instance().setOutfitLocked(false); return false; } -// void reset() { mEventTimer.reset(); } bool getStarted() { return isRunning(); } - -// LLTimer& getEventTimer() { return mEventTimer;} }; // support for secondlife:///app/appearance SLapps diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 5fc0ea855e..2041d86fc6 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -65,15 +65,6 @@ void LLToastLifeTimer::setPeriod(F32 period) mPeriod = period; } -/*==========================================================================*| -F32 LLToastLifeTimer::getRemainingTimeF32() -{ - F32 et = mEventTimer.getElapsedTimeF32(); - if (!getStarted() || et > mPeriod) return 0.0f; - return mPeriod - et; -} -|*==========================================================================*/ - //-------------------------------------------------------------------------- LLToast::Params::Params() : can_fade("can_fade", true), diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 460317aaa9..bb5bd981e2 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -57,9 +57,7 @@ public: void restart(); bool getStarted(); void setPeriod(F32 period); -// F32 getRemainingTimeF32(); -// LLTimer& getEventTimer() { return mEventTimer;} private : LLToast* mToast; }; -- cgit v1.2.3 From e4b7d2f463d19cab28985414365fd8415e3dc700 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 24 May 2024 15:24:50 +0300 Subject: Mark script messages in compact mode too; code clean up --- indra/newview/llchathistory.cpp | 28 ++++++++++++------------- indra/newview/llfloaterimnearbychathandler.cpp | 2 +- indra/newview/llfloaterimnearbychatlistener.cpp | 12 +++++------ indra/newview/llfloaterimnearbychatlistener.h | 4 +++- indra/newview/llviewerchat.cpp | 2 +- indra/newview/scripts/lua/test_LLChat.lua | 8 +++---- 6 files changed, 28 insertions(+), 28 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 54b0c171f1..7ee0f3dd7a 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -665,6 +665,7 @@ public: mSessionID = chat.mSessionID; mSourceType = chat.mSourceType; mIsFromScript = is_script; + mPrefix = mIsFromScript ? LLTrans::getString("ScriptBy") : ""; // To be able to report a message, we need a copy of it's text // and it's easier to store text directly than trying to get @@ -734,7 +735,7 @@ public: username_end == (chat.mFromName.length() - 1)) { mFrom = chat.mFromName.substr(0, username_start); - user_name->setValue(mIsFromScript ? LLTrans::getString("ScriptBy") + mFrom : mFrom); + user_name->setValue(mPrefix + mFrom); if (gSavedSettings.getBOOL("NameTagShowUsernames")) { @@ -789,7 +790,7 @@ public: icon->setValue(LLSD("Command_Destinations_Icon")); break; case CHAT_SOURCE_UNKNOWN: - icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(chat.mFromID)); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD("Unknown_Icon")); } // In case the message came from an object, save the object info @@ -1031,14 +1032,7 @@ private: mFrom = av_name.getDisplayName(); LLTextBox* user_name = getChild<LLTextBox>("user_name"); - if(mIsFromScript) - { - user_name->setValue(LLSD(LLTrans::getString("ScriptBy") + av_name.getDisplayName())); - } - else - { - user_name->setValue(LLSD(av_name.getDisplayName())); - } + user_name->setValue(LLSD(mPrefix + av_name.getDisplayName())); user_name->setToolTip( av_name.getUserName() ); if (gSavedSettings.getBOOL("NameTagShowUsernames") && @@ -1081,6 +1075,7 @@ protected: bool mNeedsTimeBox; bool mIsFromScript; + std::string mPrefix; private: boost::signals2::connection mAvatarNameCacheConnection; @@ -1270,8 +1265,11 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL name_params.color(name_color); name_params.readonly_color(name_color); - bool is_lua = (chat.mText.substr(0, LUA_PREFIX.size()) == LUA_PREFIX); - std::string prefix = chat.mText.substr(is_lua ? LUA_PREFIX.size() : 0, 4); + bool is_lua = LLStringUtil::startsWith(chat.mText, LUA_PREFIX); + + std::string message = remove_LUA_PREFIX(chat.mText, is_lua); + std::string prefix = message.substr(0, 4); + //IRC styled /me messages. bool irc_me = prefix == "/me " || prefix == "/me'"; @@ -1347,6 +1345,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // names showing if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size()) { + std::string script_prefix = is_lua ? LLTrans::getString("ScriptBy") : ""; // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. if (chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull()) { @@ -1371,7 +1370,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID)); // Add link to avatar's inspector and delimiter to message. - mEditor->appendText(std::string(link_params.link_href) + delimiter, + mEditor->appendText(script_prefix + std::string(link_params.link_href) + delimiter, prependNewLineState, link_params); prependNewLineState = false; } @@ -1384,7 +1383,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL } else { - mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter, + mEditor->appendText(script_prefix + "<nolink>" + chat.mFromName + "</nolink>" + delimiter, prependNewLineState, body_message_params); prependNewLineState = false; } @@ -1505,7 +1504,6 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // usual messages showing else if (!teleport_separator) { - std::string message = is_lua ? chat.mText.substr(LUA_PREFIX.size()) : chat.mText; message = irc_me ? message.substr(3) : message; //MESSAGE TEXT PROCESSING diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 91d9cd56cf..0c7cd3aec4 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -613,7 +613,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, } else { - toast_msg = chat_msg.mIsScript ? chat_msg.mText.substr(LUA_PREFIX.size()) : chat_msg.mText; + toast_msg = remove_LUA_PREFIX(chat_msg.mText, chat_msg.mIsScript); } bool chat_overlaps = false; diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index e8fb510111..e1be6f7281 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -39,7 +39,8 @@ static const F32 CHAT_THROTTLE_PERIOD = 1.f; LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() : LLEventAPI("LLChatBar", - "LLChatBar listener to (e.g.) sendChat, etc.") + "LLChatBar listener to (e.g.) sendChat, etc."), + mLastThrottleTime(0) { add("sendChat", "Send chat to the simulator:\n" @@ -51,17 +52,16 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() // "sendChat" command -void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const +void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) { - static F64 last_throttle_time = 0.0; F64 cur_time = LLTimer::getElapsedSeconds(); - if (cur_time < last_throttle_time + CHAT_THROTTLE_PERIOD) + if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD) { LL_DEBUGS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL; return; } - last_throttle_time = cur_time; + mLastThrottleTime = cur_time; // Extract the data std::string chat_text = LUA_PREFIX + chat_data["message"].asString(); @@ -105,6 +105,6 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const } // Send it as if it was typed in - LLFloaterIMNearbyChat::sendChatFromViewer(chat_to_send, type_o_chat, ((BOOL) (channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); + LLFloaterIMNearbyChat::sendChatFromViewer(chat_to_send, type_o_chat, ((channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); } diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index 0df0341d36..2d7c851f2c 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -41,7 +41,9 @@ public: LLFloaterIMNearbyChatListener(); private: - void sendChat(LLSD const & chat_data) const; + void sendChat(LLSD const & chat_data); + + F64 mLastThrottleTime; }; #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 70c426740b..ce29ceac1a 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -217,7 +217,7 @@ S32 LLViewerChat::getChatFontSize() //static void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg) { - std::string tmpmsg = chat.mIsScript ? chat.mText.substr(LUA_PREFIX.size()) : chat.mText; + std::string tmpmsg = remove_LUA_PREFIX(chat.mText, chat.mIsScript); if(chat.mChatStyle == CHAT_STYLE_IRC) { formated_msg = chat.mFromName + tmpmsg.substr(3); diff --git a/indra/newview/scripts/lua/test_LLChat.lua b/indra/newview/scripts/lua/test_LLChat.lua index 95bd218baa..883b82fafb 100644 --- a/indra/newview/scripts/lua/test_LLChat.lua +++ b/indra/newview/scripts/lua/test_LLChat.lua @@ -2,15 +2,15 @@ LLChat = require 'LLChat' function generateRandomWord(length) local alphabet = "abcdefghijklmnopqrstuvwxyz" - local word = "" + local wordTable = {} for i = 1, length do local randomIndex = math.random(1, #alphabet) - word = word .. alphabet:sub(randomIndex, randomIndex) + table.insert(wordTable, alphabet:sub(randomIndex, randomIndex)) end - return word + return table.concat(wordTable) end -local msg = "" +local msg = "AI says:" math.randomseed(os.time()) for i = 1, math.random(1, 10) do msg = msg .. " ".. generateRandomWord(math.random(1, 8)) -- cgit v1.2.3 From b0ef843fe0702482e843379b4975b2dda4d58935 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 24 May 2024 09:22:40 -0400 Subject: Nat's ideas from PR #1547 --- indra/newview/llchathistory.cpp | 22 ++++++++-------------- indra/newview/llfloaterimnearbychathandler.cpp | 5 +++-- indra/newview/llfloaterimnearbychatlistener.cpp | 24 +++++++++--------------- indra/newview/llfloaterimnearbychatlistener.h | 4 +++- indra/newview/llviewerchat.cpp | 2 +- indra/newview/llviewermessage.cpp | 5 +++-- indra/newview/scripts/lua/test_LLChat.lua | 12 ++++++------ 7 files changed, 33 insertions(+), 41 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 54b0c171f1..f16377d7e3 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -665,6 +665,7 @@ public: mSessionID = chat.mSessionID; mSourceType = chat.mSourceType; mIsFromScript = is_script; + mScriptPrefix = is_script? LLTrans::getString("ScriptBy") : ""; // To be able to report a message, we need a copy of it's text // and it's easier to store text directly than trying to get @@ -734,7 +735,7 @@ public: username_end == (chat.mFromName.length() - 1)) { mFrom = chat.mFromName.substr(0, username_start); - user_name->setValue(mIsFromScript ? LLTrans::getString("ScriptBy") + mFrom : mFrom); + user_name->setValue(mScriptPrefix + mFrom); if (gSavedSettings.getBOOL("NameTagShowUsernames")) { @@ -789,7 +790,7 @@ public: icon->setValue(LLSD("Command_Destinations_Icon")); break; case CHAT_SOURCE_UNKNOWN: - icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(chat.mFromID)); + icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD("Unknown_Icon")); } // In case the message came from an object, save the object info @@ -1031,14 +1032,7 @@ private: mFrom = av_name.getDisplayName(); LLTextBox* user_name = getChild<LLTextBox>("user_name"); - if(mIsFromScript) - { - user_name->setValue(LLSD(LLTrans::getString("ScriptBy") + av_name.getDisplayName())); - } - else - { - user_name->setValue(LLSD(av_name.getDisplayName())); - } + user_name->setValue(LLSD(mScriptPrefix + av_name.getDisplayName())); user_name->setToolTip( av_name.getUserName() ); if (gSavedSettings.getBOOL("NameTagShowUsernames") && @@ -1070,6 +1064,7 @@ protected: std::string mFrom; LLUUID mSessionID; std::string mText; + std::string mScriptPrefix; F64 mTime; // IM's frame time time_t mCreationTime; // Views's time @@ -1080,7 +1075,7 @@ protected: bool mNeedsTimeBox; - bool mIsFromScript; + bool mIsFromScript; private: boost::signals2::connection mAvatarNameCacheConnection; @@ -1270,8 +1265,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL name_params.color(name_color); name_params.readonly_color(name_color); - bool is_lua = (chat.mText.substr(0, LUA_PREFIX.size()) == LUA_PREFIX); - std::string prefix = chat.mText.substr(is_lua ? LUA_PREFIX.size() : 0, 4); + auto [message, is_lua] = LLStringUtil::withoutPrefix(chat.mText, LUA_PREFIX); + std::string prefix = message.substr(0, 4); //IRC styled /me messages. bool irc_me = prefix == "/me " || prefix == "/me'"; @@ -1505,7 +1500,6 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // usual messages showing else if (!teleport_separator) { - std::string message = is_lua ? chat.mText.substr(LUA_PREFIX.size()) : chat.mText; message = irc_me ? message.substr(3) : message; //MESSAGE TEXT PROCESSING diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 91d9cd56cf..cda71f97d4 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -599,6 +599,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, { // Handle IRC styled messages. std::string toast_msg; + std::string msg_text = without_LUA_PREFIX(chat_msg.mText, chat_msg.mIsScript); if (chat_msg.mChatStyle == CHAT_STYLE_IRC) { if (chat_msg.mIsScript) @@ -609,11 +610,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, { toast_msg += chat_msg.mFromName; } - toast_msg += chat_msg.mText.substr(chat_msg.mIsScript ? LUA_PREFIX.size() + 3 : 3); + toast_msg += msg_text.substr(3); } else { - toast_msg = chat_msg.mIsScript ? chat_msg.mText.substr(LUA_PREFIX.size()) : chat_msg.mText; + toast_msg = msg_text; } bool chat_overlaps = false; diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index e8fb510111..9093db282a 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -34,6 +34,7 @@ #include "llagent.h" #include "llchat.h" #include "llviewercontrol.h" +#include "stringize.h" static const F32 CHAT_THROTTLE_PERIOD = 1.f; @@ -51,17 +52,16 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() // "sendChat" command -void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const +void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) { - static F64 last_throttle_time = 0.0; F64 cur_time = LLTimer::getElapsedSeconds(); - if (cur_time < last_throttle_time + CHAT_THROTTLE_PERIOD) + if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD) { LL_DEBUGS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL; return; } - last_throttle_time = cur_time; + mLastThrottleTime = cur_time; // Extract the data std::string chat_text = LUA_PREFIX + chat_data["message"].asString(); @@ -91,20 +91,14 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const } // Have to prepend /42 style channel numbers - std::string chat_to_send; - if (channel == 0) + if (channel) { - chat_to_send = chat_text; - } - else - { - chat_to_send += "/"; - chat_to_send += chat_data["channel"].asString(); - chat_to_send += " "; - chat_to_send += chat_text; + chat_text = stringize("/", chat_data["channel"].asString(), " ", chat_text); } // Send it as if it was typed in - LLFloaterIMNearbyChat::sendChatFromViewer(chat_to_send, type_o_chat, ((BOOL) (channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); + LLFloaterIMNearbyChat::sendChatFromViewer(chat_text, type_o_chat, + (channel == 0) && + gSavedSettings.getBOOL("PlayChatAnim")); } diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index 0df0341d36..34d4effd48 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -41,7 +41,9 @@ public: LLFloaterIMNearbyChatListener(); private: - void sendChat(LLSD const & chat_data) const; + F64 mLastThrottleTime{ 0.0 }; + + void sendChat(LLSD const & chat_data); }; #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 70c426740b..00520f100e 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -217,7 +217,7 @@ S32 LLViewerChat::getChatFontSize() //static void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg) { - std::string tmpmsg = chat.mIsScript ? chat.mText.substr(LUA_PREFIX.size()) : chat.mText; + std::string tmpmsg = without_LUA_PREFIX(chat.mText, chat.mIsScript); if(chat.mChatStyle == CHAT_STYLE_IRC) { formated_msg = chat.mFromName + tmpmsg.substr(3); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 4fe5beceae..d1c773171b 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2600,10 +2600,11 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) BOOL ircstyle = FALSE; - chat.mIsScript = (mesg.substr(0, LUA_PREFIX.size()) == LUA_PREFIX); + auto [message, is_script] = LLStringUtil::withoutPrefix(mesg, LUA_PREFIX); + chat.mIsScript = is_script; // Look for IRC-style emotes here so chatbubbles work - std::string prefix = mesg.substr(chat.mIsScript ? LUA_PREFIX.size() : 0, 4); + std::string prefix = message.substr(0, 4); if (prefix == "/me " || prefix == "/me'") { ircstyle = TRUE; diff --git a/indra/newview/scripts/lua/test_LLChat.lua b/indra/newview/scripts/lua/test_LLChat.lua index 95bd218baa..3c5cbeeeb2 100644 --- a/indra/newview/scripts/lua/test_LLChat.lua +++ b/indra/newview/scripts/lua/test_LLChat.lua @@ -2,17 +2,17 @@ LLChat = require 'LLChat' function generateRandomWord(length) local alphabet = "abcdefghijklmnopqrstuvwxyz" - local word = "" + local word = {} for i = 1, length do local randomIndex = math.random(1, #alphabet) - word = word .. alphabet:sub(randomIndex, randomIndex) + table.insert(word, alphabet:sub(randomIndex, randomIndex)) end - return word + return table.concat(word) end -local msg = "" +local msg = {'AI says:'} math.randomseed(os.time()) for i = 1, math.random(1, 10) do - msg = msg .. " ".. generateRandomWord(math.random(1, 8)) + table.insert(msg, generateRandomWord(math.random(1, 8))) end -LLChat.sendNearby(msg) +LLChat.sendNearby(table.concat(msg, ' ')) -- cgit v1.2.3 From 94cac4c443b5acc189b5223c78eb278648846338 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 24 May 2024 10:15:24 -0400 Subject: Fix merge glitches --- indra/newview/llchathistory.cpp | 11 ----------- indra/newview/llfloaterimnearbychathandler.cpp | 4 ---- 2 files changed, 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index e5878a9a24..d549f372e3 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1265,19 +1265,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL name_params.color(name_color); name_params.readonly_color(name_color); -<<<<<<< variant A auto [message, is_lua] = LLStringUtil::withoutPrefix(chat.mText, LUA_PREFIX); std::string prefix = message.substr(0, 4); ->>>>>>> variant B - bool is_lua = LLStringUtil::startsWith(chat.mText, LUA_PREFIX); - - std::string message = remove_LUA_PREFIX(chat.mText, is_lua); - std::string prefix = message.substr(0, 4); - -####### Ancestor - bool is_lua = (chat.mText.substr(0, LUA_PREFIX.size()) == LUA_PREFIX); - std::string prefix = chat.mText.substr(is_lua ? LUA_PREFIX.size() : 0, 4); -======= end //IRC styled /me messages. bool irc_me = prefix == "/me " || prefix == "/me'"; diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 6a9dccf2f4..cda71f97d4 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -614,11 +614,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, } else { -<<<<<<< HEAD toast_msg = msg_text; -======= - toast_msg = remove_LUA_PREFIX(chat_msg.mText, chat_msg.mIsScript); ->>>>>>> release/luau-scripting } bool chat_overlaps = false; -- cgit v1.2.3 From 71d777ea126e7f02cb46c11bdb606094ca06f75c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 24 May 2024 17:34:04 -0400 Subject: Promote seh_catcher() et al. to llexception.{h,cpp} for general use. --- indra/newview/llappviewerwin32.cpp | 36 ++++-------------------------------- indra/newview/llfeaturemanager.cpp | 36 ++++-------------------------------- 2 files changed, 8 insertions(+), 64 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 4c90a82fcb..a13e4de308 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -400,17 +400,10 @@ void ll_nvapi_init(NvDRSSessionHandle hSession) } } -//#define DEBUGGING_SEH_FILTER 1 -#if DEBUGGING_SEH_FILTER -# define WINMAIN DebuggingWinMain -#else -# define WINMAIN wWinMain -#endif - -int APIENTRY WINMAIN(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - PWSTR pCmdLine, - int nCmdShow) +int APIENTRY wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + PWSTR pCmdLine, + int nCmdShow) { // Call Tracy first thing to have it allocate memory // https://github.com/wolfpld/tracy/issues/196 @@ -559,27 +552,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, return 0; } -#if DEBUGGING_SEH_FILTER -// The compiler doesn't like it when you use __try/__except blocks -// in a method that uses object destructors. Go figure. -// This winmain just calls the real winmain inside __try. -// The __except calls our exception filter function. For debugging purposes. -int APIENTRY wWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - PWSTR lpCmdLine, - int nCmdShow) -{ - __try - { - WINMAIN(hInstance, hPrevInstance, lpCmdLine, nCmdShow); - } - __except( viewer_windows_exception_handler( GetExceptionInformation() ) ) - { - _tprintf( _T("Exception handled.\n") ); - } -} -#endif - void LLAppViewerWin32::disableWinErrorReporting() { std::string executable_name = gDirUtilp->getExecutableFilename(); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 99139e6528..1f2ebd5092 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -40,6 +40,7 @@ #include "llappviewer.h" #include "llbufferstream.h" +#include "llexception.h" #include "llnotificationsutil.h" #include "llviewercontrol.h" #include "llworld.h" @@ -377,33 +378,6 @@ bool LLFeatureManager::parseFeatureTable(std::string filename) F32 gpu_benchmark(); -#if LL_WINDOWS - -F32 logExceptionBenchmark() -{ - // FIXME: gpu_benchmark uses many C++ classes on the stack to control state. - // SEH exceptions with our current exception handling options do not call - // destructors for these classes, resulting in an undefined state should - // this handler be invoked. - F32 gbps = -1; - __try - { - gbps = gpu_benchmark(); - } - __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) - { - // HACK - ensure that profiling is disabled - LLGLSLShader::finishProfile(false); - - // convert to C++ styled exception - char integer_string[32]; - sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); - throw std::exception(integer_string); - } - return gbps; -} -#endif - bool LLFeatureManager::loadGPUClass() { if (!gSavedSettings.getBOOL("SkipBenchmark")) @@ -413,14 +387,12 @@ bool LLFeatureManager::loadGPUClass() F32 gbps; try { -#if LL_WINDOWS - gbps = logExceptionBenchmark(); -#else - gbps = gpu_benchmark(); -#endif + gbps = seh_catcher(gpu_benchmark); } catch (const std::exception& e) { + // HACK - ensure that profiling is disabled + LLGLSLShader::finishProfile(false); gbps = -1.f; LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL; } -- cgit v1.2.3 From bdf46af9aff96a749dcf2612a2bdc6e8e394971e Mon Sep 17 00:00:00 2001 From: AiraYumi <aira.youme@airanyumi.net> Date: Tue, 21 May 2024 20:52:38 -0400 Subject: fix "lines starting with tabs found" --- indra/newview/llviewermedia.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 5d58e0b0b2..c8b7a9c29b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1766,8 +1766,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled || clean_browser); #if LL_LINUX - bool media_plugin_pipewire_volume_catcher = gSavedSettings.getBOOL("MediaPluginPipeWireVolumeCatcher"); - media_source->enablePipeWireVolumeCatcher( media_plugin_pipewire_volume_catcher ); + bool media_plugin_pipewire_volume_catcher = gSavedSettings.getBOOL("MediaPluginPipeWireVolumeCatcher"); + media_source->enablePipeWireVolumeCatcher( media_plugin_pipewire_volume_catcher ); #endif // need to set agent string here before instance created -- cgit v1.2.3 From 5ed8df22cd59680a685c4ada7daa5555bf59d4fe Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 28 May 2024 13:22:05 -0400 Subject: Fix up llexception.h's cross-platform SEH wrapper. Introduce AlwaysReturn<void> specialization, which always discards any result of calling the specified callable with specified args. Derive new Windows_SEH_exception from LLException, not std::runtime_error. Put the various SEH functions in LL::seh nested namespace, e.g. LL::seh::catcher() as the primary API. Break out more levels of Windows SEH handler to work around the restrictions on functions containing __try/__except. The triadic catcher() overload now does little save declare a std::string stacktrace before forwarding the call to catcher_inner(), passing a reference to stacktrace along with the trycode, filter and handler functions. catcher_inner() accepts the stacktrace and the three function template arguments. It contains the __try/__except logic. It calls a new filter_() wrapper template, which calls fill_stacktrace() before forwarding the call to the caller's filter function. fill_stacktrace(), in the .cpp file, contains the logic to populate the stacktrace string -- unless the Structured Exception is stack overflow, in which case it puts an explanatory string instead. catcher_inner()'s __except clause passes not only the code, but also the stacktrace string, to the caller's handler function. It wraps the caller's handler function in always_return<rtype>(), where rtype is the type returned by the trycode function. This allows a handler to return a value, while also supporting the void handler case, e.g. one that throws a C++ exception. (This is why we need AlwaysReturn<void>: some trycode() functions are themselves void.) For the dyadic catcher() overload, introduce common_filter() containing the logic to distinguish a C++ exception from any other kind of Structured Exception. The fact that the stacktrace is captured before the filter function is called should permit capturing a stacktrace for a C++ exception as well as for most other Structured Exceptions. As before, the monadic catcher() overload supplies the rethrow() handler, in the .cpp file. Change existing calls from seh_catcher() to LL::seh::catcher(). --- indra/newview/llfeaturemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 1f2ebd5092..765599bb82 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -387,7 +387,7 @@ bool LLFeatureManager::loadGPUClass() F32 gbps; try { - gbps = seh_catcher(gpu_benchmark); + gbps = LL::seh::catcher(gpu_benchmark); } catch (const std::exception& e) { -- cgit v1.2.3 From 4189cb74421794ba123bf8724caa843c9d9d1c78 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 29 May 2024 18:50:29 +0300 Subject: viewer#1577 Attachments cannot be detached in performance floater attachment list gets filled with object ids, not attachment ids --- indra/newview/llfloaterperformance.cpp | 12 ++++++++---- indra/newview/llfloaterperformance.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 97ae97dafc..ba655ab760 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -115,12 +115,12 @@ BOOL LLFloaterPerformance::postBuild() mHUDList = mHUDsPanel->getChild<LLNameListCtrl>("hud_list"); mHUDList->setNameListType(LLNameListCtrl::SPECIAL); mHUDList->setHoverIconName("StopReload_Off"); - mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); + mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachObject, this, _1)); mObjectList = mComplexityPanel->getChild<LLNameListCtrl>("obj_list"); mObjectList->setNameListType(LLNameListCtrl::SPECIAL); mObjectList->setHoverIconName("StopReload_Off"); - mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); + mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachObject, this, _1)); mSettingsPanel->getChild<LLButton>("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this)); mSettingsPanel->getChild<LLButton>("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickDefaults, this)); @@ -524,9 +524,13 @@ void LLFloaterPerformance::setFPSText() getChild<LLTextBox>("fps_lbl")->setValue(fps_text); } -void LLFloaterPerformance::detachItem(const LLUUID& item_id) +void LLFloaterPerformance::detachObject(const LLUUID& obj_id) { - LLAppearanceMgr::instance().removeItemFromAvatar(item_id); + LLViewerObject* obj = gObjectList.findObject(obj_id); + if (obj) + { + LLAppearanceMgr::instance().removeItemFromAvatar(obj->getAttachmentItemID()); + } } void LLFloaterPerformance::onClickAdvanced() diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index d2f45a9e2e..03fa9e8184 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -46,7 +46,7 @@ public: void hidePanels(); void showAutoadjustmentsPanel(); - void detachItem(const LLUUID& item_id); + void detachObject(const LLUUID& obj_id); void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y); -- cgit v1.2.3 From 3fc2aa78f371f7f3da4a3c485293492c68e9b2c8 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 30 May 2024 21:48:31 +0300 Subject: Add separate minor throttle period for UNTRUSTED_ALLOW funcs --- indra/newview/lluilistener.cpp | 34 ++++++++++++++++++++++------------ indra/newview/lluilistener.h | 6 +++++- indra/newview/llviewermenu.cpp | 38 +++++++++++++++++++------------------- 3 files changed, 46 insertions(+), 32 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 938ef95b5c..40f276b478 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -38,7 +38,8 @@ #include "lluictrl.h" #include "llerror.h" -#define THROTTLE_PERIOD 1 // required seconds between throttled functions +#define THROTTLE_PERIOD 1.5 // required seconds between throttled functions +#define MIN_THROTTLE 0.5 LLUIListener::LLUIListener(): LLEventAPI("UI", @@ -58,9 +59,9 @@ LLUIListener::LLUIListener(): LLSDMap("path", LLSD())("reply", LLSD())); } -void LLUIListener::call(const LLSD& event) const +typedef LLUICtrl::LLCommitCallbackInfo cb_info; +void LLUIListener::call(const LLSD& event) { - static F64 last_throttle_time = 0.0; Response response(LLSD(), event); LLUICtrl::LLCommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(event["function"]); if (!info ) @@ -68,21 +69,30 @@ void LLUIListener::call(const LLSD& event) const response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << "was not found")); return; } - if (info->mHandleUntrusted == LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK) + if (info->mHandleUntrusted == cb_info::UNTRUSTED_BLOCK) { response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << " is not allowed to be called from the script")); return; } - if (info->mHandleUntrusted == LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_THROTTLE) + F64 cur_time = LLTimer::getElapsedSeconds(); + bool is_untrusted_throttle = info->mHandleUntrusted == cb_info::UNTRUSTED_THROTTLE; + + //Separate UNTRUSTED_THROTTLE and UNTRUSTED_ALLOW functions to have different timeout + F64 time_delta = is_untrusted_throttle ? mLastUntrustedThrottle + THROTTLE_PERIOD : mLastMinThrottle + MIN_THROTTLE; + if (cur_time < time_delta) + { + LL_WARNS("LLUIListener") << "Throttled function " << std::quoted(event["function"].asString()) << LL_ENDL; + return; + } + if (is_untrusted_throttle) { - F64 cur_time = LLTimer::getElapsedSeconds(); - if (cur_time < last_throttle_time + THROTTLE_PERIOD) - { - LL_WARNS("LLUIListener") << "Throttled function " << std::quoted(event["function"].asString()) << LL_ENDL; - return; - } - last_throttle_time = cur_time; + mLastUntrustedThrottle = cur_time; } + else + { + mLastMinThrottle = cur_time; + } + LLUICtrl::commit_callback_t func = info->callback_func; diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index e53984dae2..790284a27a 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -41,8 +41,12 @@ public: // FIXME These fields are intended to be private, changed here to support very hacky code in llluamanager.cpp public: - void call(const LLSD& event) const; + void call(const LLSD& event); void getValue(const LLSD&event) const; + + private: + F64 mLastUntrustedThrottle {0.f}; + F64 mLastMinThrottle {0.f}; }; #endif /* ! defined(LL_LLUILISTENER_H) */ diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 83ffa2ae59..4452f0ebda 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9398,6 +9398,7 @@ void initialize_edit_menu() typedef LLUICtrl::LLCommitCallbackInfo cb_info; #define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func)) #define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_BLOCK)) +#define COMMIT_ADD_THROTTLE(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_THROTTLE)) void initialize_spellcheck_menu() { @@ -9553,8 +9554,8 @@ void initialize_menus() view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); COMMIT_ADD("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - COMMIT_ADD("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - COMMIT_ADD("Tools.TakeCopy", boost::bind(&handle_take_copy)); + COMMIT_ADD_THROTTLE("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); + COMMIT_ADD_THROTTLE("Tools.TakeCopy", boost::bind(&handle_take_copy)); view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); @@ -9642,7 +9643,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - COMMIT_ADD("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); + COMMIT_ADD_THROTTLE("Advanced.DumpTimers", boost::bind(&handle_dump_timers)); COMMIT_ADD("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); @@ -9668,7 +9669,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - COMMIT_ADD("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); + COMMIT_ADD_TRUSTED("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); // Advanced > Character > Grab Baked Texture view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); @@ -9739,7 +9740,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); - view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest"); + view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest", cb_info::UNTRUSTED_BLOCK); view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); @@ -9754,11 +9755,11 @@ void initialize_menus() view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); //Develop (clear cache immediately) - COMMIT_ADD("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + COMMIT_ADD_TRUSTED("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); // Develop (Fonts debugging) - COMMIT_ADD("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); - COMMIT_ADD("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); + COMMIT_ADD_THROTTLE("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); + COMMIT_ADD_THROTTLE("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); // Admin >Object view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); @@ -9802,13 +9803,13 @@ void initialize_menus() COMMIT_ADD("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); COMMIT_ADD("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); - view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); + view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call", cb_info::UNTRUSTED_BLOCK); enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); - view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); + view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse", cb_info::UNTRUSTED_THROTTLE); view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); - view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton", cb_info::UNTRUSTED_THROTTLE); view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); @@ -9830,14 +9831,13 @@ void initialize_menus() view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); COMMIT_ADD("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); + view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse", cb_info::UNTRUSTED_THROTTLE); view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - COMMIT_ADD("Object.Buy", boost::bind(&handle_buy)); - COMMIT_ADD("Object.Edit", boost::bind(&handle_object_edit)); + COMMIT_ADD_THROTTLE("Object.Buy", boost::bind(&handle_buy)); COMMIT_ADD("Object.Edit", boost::bind(&handle_object_edit)); COMMIT_ADD("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); COMMIT_ADD("Object.Inspect", boost::bind(&handle_object_inspect)); @@ -9884,14 +9884,14 @@ void initialize_menus() view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - COMMIT_ADD("Land.Buy", boost::bind(&handle_buy_land)); + COMMIT_ADD_THROTTLE("Land.Buy", boost::bind(&handle_buy_land)); // Generic actions - COMMIT_ADD("ReportAbuse", boost::bind(&handle_report_abuse)); - COMMIT_ADD("BuyCurrency", boost::bind(&handle_buy_currency)); + COMMIT_ADD_THROTTLE("ReportAbuse", boost::bind(&handle_report_abuse)); + COMMIT_ADD_THROTTLE("BuyCurrency", boost::bind(&handle_buy_currency)); view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); - view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); + view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak", cb_info::UNTRUSTED_BLOCK); view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks"); @@ -9902,7 +9902,7 @@ void initialize_menus() view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); COMMIT_ADD("PayObject", boost::bind(&handle_give_money_dialog)); - COMMIT_ADD("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); + COMMIT_ADD_THROTTLE("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); enable.add("EnablePayObject", boost::bind(&enable_pay_object)); enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); -- cgit v1.2.3 From d61831cabb8c63677e3684c8ba12b24b66923aa9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 31 May 2024 11:17:48 -0400 Subject: Don't check if printf(format) arg is a string. --- indra/newview/scripts/lua/printf.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/printf.lua b/indra/newview/scripts/lua/printf.lua index 584cd4f391..e84b2024df 100644 --- a/indra/newview/scripts/lua/printf.lua +++ b/indra/newview/scripts/lua/printf.lua @@ -2,7 +2,7 @@ local inspect = require 'inspect' -local function printf(...) +local function printf(format, ...) -- string.format() only handles numbers and strings. -- Convert anything else to string using the inspect module. local args = {} @@ -13,7 +13,7 @@ local function printf(...) table.insert(args, inspect(arg)) end end - print(string.format(table.unpack(args))) + print(string.format(format, table.unpack(args))) end return printf -- cgit v1.2.3 From e352192045cfe23a681dcaba71d94311f42e230f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 31 May 2024 11:19:58 -0400 Subject: Add a bit more dbg() conditional diagnostic output. --- indra/newview/scripts/lua/fiber.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua index 9057e6c890..cae27b936b 100644 --- a/indra/newview/scripts/lua/fiber.lua +++ b/indra/newview/scripts/lua/fiber.lua @@ -17,8 +17,8 @@ -- or with an error). local printf = require 'printf' --- local dbg = printf local function dbg(...) end +-- local dbg = printf local coro = require 'coro' local fiber = {} @@ -303,6 +303,8 @@ function fiber.yield() end -- We're ready! Just return to caller. In this situation we don't care -- whether there are other ready fibers. + dbg('fiber.yield() returning to %s (%sothers are ready)', + fiber.get_name(), ((not others) and "no " or "")) end -- Run fibers until all but main have terminated: return nil. -- cgit v1.2.3 From c59f8bc59ad958d169a7626739b2b81439180537 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 31 May 2024 11:35:30 -0400 Subject: Add leap.eventstream() and cancelreq() functions. leap.eventstream() is used when we expect the viewer's LLEventAPI to send an immediate first response with the reqid from the request, followed by some number of subsequent responses bearing the same reqid. The difference between eventstream() and generate() is that generate() expects the caller to request each such response, whereas eventstream calls the caller's callback with each response. cancelreq() is for canceling the background fiber launched by eventstream() before the callback tells it to quit. Make WaitFor:close() remove the object from the waitfors list; similarly, make WaitForReqid:close() remove the object from the pending list. For this reason, cleanup() must iterate over a copy of each of the pending and waitfors lists. Instead of unregisterWaitFor() manually searching the waitfors list, use table.find(). --- indra/newview/scripts/lua/leap.lua | 106 ++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 13 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index cfb7377523..69cedb4c9e 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -40,6 +40,7 @@ local fiber = require('fiber') local ErrorQueue = require('ErrorQueue') +local inspect = require('inspect') local function dbg(...) end -- local dbg = require('printf') @@ -74,7 +75,7 @@ local reply, command = LL.get_event_pumps() -- pending is NOT a weak table because the caller of request() or generate() -- never sees the WaitForReqid object. pending holds the only reference, so -- it should NOT be garbage-collected. -pending = {} +local pending = {} -- Our consumer will instantiate some number of WaitFor subclass objects. -- As these are traversed in descending priority order, we must keep -- them in a list. @@ -82,7 +83,7 @@ pending = {} -- to it. Once the consuming script drops the reference, allow Lua to -- garbage-collect the WaitFor despite its entry in waitfors. local weak_values = {__mode='v'} -waitfors = setmetatable({}, weak_values) +local waitfors = setmetatable({}, weak_values) -- It has been suggested that we should use UUIDs as ["reqid"] values, -- since UUIDs are guaranteed unique. However, as the "namespace" for -- ["reqid"] values is our very own reply pump, we can get away with @@ -131,7 +132,7 @@ local function requestSetup(pump, data) local waitfor = leap.WaitForReqid:new(reqid) pending[reqid] = waitfor -- Pass reqid to send() to stamp it into (a copy of) the request data. - dbg('requestSetup(%s, %s)', pump, data) + dbg('requestSetup(%s, %s) storing %s', pump, data, waitfor.name) leap.send(pump, data, reqid) return reqid, waitfor end @@ -177,7 +178,7 @@ end -- -- If you pass checklast=<callable accepting(event)>, each response event is -- passed to that callable (after the yield). When the callable returns --- True, the generator terminates in the usual way. +-- true, the generator terminates in the usual way. -- -- See request() remarks about ["reqid"]. function leap.generate(pump, data, checklast) @@ -203,12 +204,80 @@ function leap.generate(pump, data, checklast) end end +-- Send the specified request LLSD, expecting an immediate reply followed by +-- an arbitrary number of subsequent replies with the same reqid. Block the +-- calling coroutine until the first (immediate) reply, but launch a separate +-- fiber on which to call the passed callback with later replies. +-- +-- Once the callback returns true, the background fiber terminates. +function leap.eventstream(pump, data, callback) + local reqid, waitfor = requestSetup(pump, data) + local response = waitfor:wait() + if response.error then + -- clean up our WaitForReqid + waitfor:close() + error(response.error) + end + -- No error, so far so good: + -- call the callback with the first response just in case + local ok, done = pcall(callback, response) + if not ok then + -- clean up our WaitForReqid + waitfor:close() + error(done) + end + if done then + return response + end + -- callback didn't throw an error, and didn't say stop, + -- so set up to handle subsequent events + -- TODO: distinguish "daemon" fibers that can be terminated even if waiting + fiber.launch( + pump, + function () + local ok, done + repeat + event = waitfor:wait() + if not event then + -- wait() returns nil once the queue is closed (e.g. cancelreq()) + ok, done = true, true + else + ok, done = pcall(callback, event) + end + -- not ok means callback threw an error (caught as 'done') + -- done means callback succeeded but wants to stop + until (not ok) or done + -- once we break this loop, clean up our WaitForReqid + waitfor:close() + if not ok then + -- can't reflect the error back to our caller + LL.print_warning(fiber.get_name() .. ': ' .. done) + end + end) + return response +end + +-- we might want to clean up after leap.eventstream() even if the callback has +-- not yet returned true +function leap.cancelreq(reqid) + dbg('cancelreq(%s)', reqid) + local waitfor = pending[reqid] + if waitfor ~= nil then + -- close() removes the pending entry and also closes the queue, + -- breaking the background fiber's wait loop. + dbg('cancelreq(%s) canceling %s', reqid, waitfor.name) + waitfor:close() + end +end + local function cleanup(message) - -- we're done: clean up all pending coroutines - for i, waitfor in pairs(pending) do + -- We're done: clean up all pending coroutines. + -- Iterate over copies of the pending and waitfors tables, since the + -- close() operation modifies the real tables. + for i, waitfor in pairs(table.clone(pending)) do waitfor:close() end - for i, waitfor in pairs(waitfors) do + for i, waitfor in pairs(table.clone(waitfors)) do waitfor:close() end end @@ -223,7 +292,8 @@ local function unsolicited(pump, data) return end end - LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', pump, data)) + LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', + pump, inspect(data))) end -- Route incoming (pump, data) event to the appropriate waiting coroutine. @@ -231,14 +301,17 @@ local function dispatch(pump, data) local reqid = data['reqid'] -- if the response has no 'reqid', it's not from request() or generate() if reqid == nil then +-- dbg('dispatch() found no reqid; calling unsolicited(%s, %s)', pump, data) return unsolicited(pump, data) end -- have reqid; do we have a WaitForReqid? local waitfor = pending[reqid] if waitfor == nil then +-- dbg('dispatch() found no WaitForReqid(%s); calling unsolicited(%s, %s)', reqid, pump, data) return unsolicited(pump, data) end -- found the right WaitForReqid object, let it handle the event +-- dbg('dispatch() calling %s.handle(%s, %s)', waitfor.name, pump, data) waitfor:handle(pump, data) end @@ -284,11 +357,9 @@ end -- called by WaitFor.disable() local function unregisterWaitFor(waitfor) - for i, w in pairs(waitfors) do - if w == waitfor then - waitfors[i] = nil - break - end + local i = table.find(waitfors, waitfor) + if i ~= nil then + waitfors[i] = nil end end @@ -417,6 +488,7 @@ end -- called by cleanup() at end function leap.WaitFor:close() + self:disable() self._queue:close() end @@ -437,6 +509,8 @@ function leap.WaitForReqid:new(reqid) setmetatable(obj, self) self.__index = self + obj.reqid = reqid + return obj end @@ -447,4 +521,10 @@ function leap.WaitForReqid:filter(pump, data) return data end +function leap.WaitForReqid:close() + -- remove this entry from pending table + pending[self.reqid] = nil + self._queue:close() +end + return leap -- cgit v1.2.3 From f08a3c80d61795bb1fc0e576948bca3362ef8e6c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 31 May 2024 20:03:13 +0300 Subject: Cherry-pick leap.lua changes; other clean up --- indra/newview/lllocationinputctrl.cpp | 2 +- indra/newview/lluilistener.cpp | 18 ++++++++---------- indra/newview/llviewermenu.cpp | 2 +- indra/newview/scripts/lua/LLDebugSettings.lua | 7 +++---- indra/newview/scripts/lua/UI.lua | 5 ++--- indra/newview/scripts/lua/leap.lua | 12 ++++++++---- indra/newview/scripts/lua/util.lua | 7 ------- 7 files changed, 23 insertions(+), 30 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index d31f4bbcfa..67ad63b7fb 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -377,7 +377,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) addChild(mParcelIcon[SEE_AVATARS_ICON]); // Register callbacks and load the location field context menu (NB: the order matters). - LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add("Navbar.Action", LLUICtrl::LLCommitCallbackInfo(boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2))); + LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add("Navbar.Action", LLUICtrl::CommitCallbackInfo(boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2))); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2)); setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 40f276b478..604f766ab2 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -50,32 +50,30 @@ LLUIListener::LLUIListener(): "Invoke the operation named by [\"function\"], passing [\"parameter\"],\n" "as if from a user gesture on a menu -- or a button click.", &LLUIListener::call, - LLSD().with("function", LLSD())); + llsd::map("function", LLSD(), "reply", LLSD())); add("getValue", "For the UI control identified by the path in [\"path\"], return the control's\n" "current value as [\"value\"] reply.", &LLUIListener::getValue, - LLSDMap("path", LLSD())("reply", LLSD())); + llsd::map("path", LLSD(), "reply", LLSD())); } -typedef LLUICtrl::LLCommitCallbackInfo cb_info; +typedef LLUICtrl::CommitCallbackInfo cb_info; void LLUIListener::call(const LLSD& event) { Response response(LLSD(), event); - LLUICtrl::LLCommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(event["function"]); + LLUICtrl::CommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(event["function"]); if (!info ) { - response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << "was not found")); - return; + return response.error(stringize("Function ", std::quoted(event["function"].asString()), " was not found")); } - if (info->mHandleUntrusted == cb_info::UNTRUSTED_BLOCK) + if (info->handle_untrusted == cb_info::UNTRUSTED_BLOCK) { - response.error(STRINGIZE("Function " << std::quoted(event["function"].asString()) << " is not allowed to be called from the script")); - return; + return response.error(stringize("Function ", std::quoted(event["function"].asString()), " is not allowed to be called from the script")); } F64 cur_time = LLTimer::getElapsedSeconds(); - bool is_untrusted_throttle = info->mHandleUntrusted == cb_info::UNTRUSTED_THROTTLE; + bool is_untrusted_throttle = info->handle_untrusted == cb_info::UNTRUSTED_THROTTLE; //Separate UNTRUSTED_THROTTLE and UNTRUSTED_ALLOW functions to have different timeout F64 time_delta = is_untrusted_throttle ? mLastUntrustedThrottle + THROTTLE_PERIOD : mLastMinThrottle + MIN_THROTTLE; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4452f0ebda..557197ccf0 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9395,7 +9395,7 @@ void initialize_edit_menu() } -typedef LLUICtrl::LLCommitCallbackInfo cb_info; +typedef LLUICtrl::CommitCallbackInfo cb_info; #define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func)) #define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_BLOCK)) #define COMMIT_ADD_THROTTLE(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_THROTTLE)) diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index 06a8a63727..c250019a00 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,18 +1,17 @@ leap = require 'leap' -util = require 'util' local LLDebugSettings = {} function LLDebugSettings.set(name, value) - util.check_response(leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value})) + leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value}) end function LLDebugSettings.toggle(name) - util.check_response(leap.request('LLViewerControl', {op='toggle', group='Global', key=name})) + leap.request('LLViewerControl', {op='toggle', group='Global', key=name}) end function LLDebugSettings.get(name) - return util.check_response(leap.request('LLViewerControl', {op='get', group='Global', key=name}))['value'] + return leap.request('LLViewerControl', {op='get', group='Global', key=name})['value'] end return LLDebugSettings diff --git a/indra/newview/scripts/lua/UI.lua b/indra/newview/scripts/lua/UI.lua index 6101c7a312..24f822bbd9 100644 --- a/indra/newview/scripts/lua/UI.lua +++ b/indra/newview/scripts/lua/UI.lua @@ -1,17 +1,16 @@ -- Engage the UI LLEventAPI leap = require 'leap' -util = require 'util' local UI = {} function UI.call(func, parameter) -- 'call' is fire-and-forget - util.check_response(leap.request('UI', {op='call', ['function']=func, parameter=parameter})) + leap.request('UI', {op='call', ['function']=func, parameter=parameter}) end function UI.getValue(path) - return util.check_response(leap.request('UI', {op='getValue', path=path}))['value'] + return leap.request('UI', {op='getValue', path=path})['value'] end return UI diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index ade91789f0..cfb7377523 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -161,10 +161,12 @@ function leap.request(pump, data) dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) -- kill off temporary WaitForReqid object, even if error pending[reqid] = nil - if ok then - return response - else + if not ok then error(response) + elseif response.error then + error(response.error) + else + return response end end @@ -186,7 +188,7 @@ function leap.generate(pump, data, checklast) local ok, response, resumed_with repeat ok, response = pcall(waitfor.wait, waitfor) - if not ok then + if (not ok) or response.error then break end -- can resume(false) to terminate generate() and clean up @@ -196,6 +198,8 @@ function leap.generate(pump, data, checklast) pending[reqid] = nil if not ok then error(response) + elseif response.error then + error(response.error) end end diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index 404efdf09e..a2191288f6 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -41,11 +41,4 @@ function util.equal(t1, t2) return util.empty(temp) end -function util.check_response(res) - if res.error then - error(res.error) - end - return res -end - return util -- cgit v1.2.3 From 854bed5c171c75c97df7e58286f2350879e5c0be Mon Sep 17 00:00:00 2001 From: Salad Dais <SaladDais@users.noreply.github.com> Date: Thu, 30 May 2024 16:29:58 +0000 Subject: Add support for RequestTaskInventory capability The viewer now prefers to load inventory via the capability rather than over the deprecated Xfer system, though both are still supported. --- indra/newview/llviewerobject.cpp | 160 ++++++++++++++++++++++++++++++++++++--- indra/newview/llviewerobject.h | 2 + indra/newview/llviewerregion.cpp | 1 + 3 files changed, 152 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index a53c9c3d23..ed2240ef5b 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3036,24 +3036,33 @@ void LLViewerObject::fetchInventoryFromServer() delete mInventory; mInventory = NULL; - // Results in processTaskInv - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RequestTaskInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addU32Fast(_PREHASH_LocalID, mLocalID); - msg->sendReliable(mRegionp->getHost()); - // This will get reset by doInventoryCallback or processTaskInv mInvRequestState = INVENTORY_REQUEST_PENDING; + + if (mRegionp && !mRegionp->getCapability("RequestTaskInventory").empty()) + { + LLCoros::instance().launch("LLViewerObject::fetchInventoryFromCapCoro()", + boost::bind(&LLViewerObject::fetchInventoryFromCapCoro, mID)); + } + else + { + LL_WARNS() << "Using old task inventory path!" << LL_ENDL; + // Results in processTaskInv + LLMessageSystem *msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RequestTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->sendReliable(mRegionp->getHost()); + } } } void LLViewerObject::fetchInventoryDelayed(const F64 &time_seconds) { - // unless already waiting, drop previous request and shedule an update + // unless already waiting, drop previous request and schedule an update if (mInvRequestState != INVENTORY_REQUEST_WAIT) { if (mInvRequestXFerId != 0) @@ -3084,6 +3093,80 @@ void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 } } +//static +void LLViewerObject::fetchInventoryFromCapCoro(const LLUUID task_inv) +{ + LLViewerObject *obj = gObjectList.findObject(task_inv); + if (obj) + { + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TaskInventoryRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + std::string url = obj->mRegionp->getCapability("RequestTaskInventory") + "?task_id=" + obj->mID.asString(); + // If we already have a copy of the inventory then add it so the server won't re-send something we already have. + // We expect this case to crop up in the case of failed inventory mutations, but it might happen otherwise as well. + if (obj->mInventorySerialNum && obj->mInventory) + url += "&inventory_serial=" + std::to_string(obj->mInventorySerialNum); + + obj->mInvRequestState = INVENTORY_XFER; + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + // Object may have gone away while we were suspended, double-check that it still exists + obj = gObjectList.findObject(task_inv); + if (!obj) + { + LL_WARNS() << "Object " << task_inv << " went away while fetching inventory, dropping result" << LL_ENDL; + return; + } + + bool potentially_stale = false; + if (status) + { + // Dealing with inventory serials is kind of funky. They're monotonically increasing and 16 bits, + // so we expect them to overflow, but we can use inv serial < expected serial as a signal that we may + // have mutated the task inventory since we kicked off the request, and those mutations may have not + // been taken into account yet. Of course, those mutations may have actually failed which would result + // in the inv serial never increasing. + // + // When we detect this case, set the expected inv serial to the inventory serial we actually received + // and kick off a re-request after a slight delay. + S16 serial = (S16)result["inventory_serial"].asInteger(); + potentially_stale = serial < obj->mExpectedInventorySerialNum; + LL_INFOS() << "Inventory loaded for " << task_inv << LL_ENDL; + obj->mInventorySerialNum = serial; + obj->mExpectedInventorySerialNum = serial; + obj->loadTaskInvLLSD(result); + } + else if (status.getType() == 304) + { + LL_INFOS() << "Inventory wasn't changed on server!" << LL_ENDL; + obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; + // Even though it wasn't necessary to send a response, we still may have mutated + // the inventory since we kicked off the request, check for that case. + potentially_stale = obj->mInventorySerialNum < obj->mExpectedInventorySerialNum; + // Set this to what we already have so that we don't re-request a second time. + obj->mExpectedInventorySerialNum = obj->mInventorySerialNum; + } + else + { + // Not sure that there's anything sensible we can do to recover here, retrying in a loop would be bad. + LL_WARNS() << "Error status while requesting task inventory: " << status.toString() << LL_ENDL; + obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; + } + + if (potentially_stale) + { + // Stale? I guess we can use what we got for now, but we'll have to re-request + LL_WARNS() << "Stale inv_serial? Re-requesting." << LL_ENDL; + obj->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED); + } + } +} + LLControlAvatar *LLViewerObject::getControlAvatar() { return getRootEdit()->mControlAvatar.get(); @@ -3259,6 +3342,20 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) S16 serial = 0; msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial); + if (object->mRegionp && !object->mRegionp->getCapability("RequestTaskInventory").empty()) + { + // It seems that simulator may ask us to re-download the task inventory if an update to the inventory + // happened out-of-band while we had the object selected (like if a script is saved.) + // + // If we're meant to use the HTTP capability, ignore the contents of the UDP message and fetch the + // inventory via the CAP so that we don't flow down the UDP inventory request path unconditionally here. + // We shouldn't need to wait, as any updates should already be ready to fetch by this point. + LL_INFOS() << "Handling unsolicited ReplyTaskInventory for " << task_id << LL_ENDL; + object->mExpectedInventorySerialNum = serial; + object->fetchInventoryFromServer(); + return; + } + if (serial == object->mInventorySerialNum && serial < object->mExpectedInventorySerialNum) { @@ -3466,6 +3563,47 @@ BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) return TRUE; } +void LLViewerObject::loadTaskInvLLSD(const LLSD& inv_result) +{ + if (inv_result.has("contents")) + { + if(mInventory) + { + mInventory->clear(); // will deref and delete it + } + else + { + mInventory = new LLInventoryObject::object_list_t; + } + + // Synthesize the "Contents" category, the viewer expects it, but it isn't sent. + LLPointer<LLInventoryObject> inv = new LLInventoryObject(mID, LLUUID::null, LLAssetType::AT_CATEGORY, "Contents"); + mInventory->push_front(inv); + + const LLSD& inventory = inv_result["contents"]; + for (const auto& inv_entry : llsd::inArray(inventory)) + { + if (inv_entry.has("item_id")) + { + LLPointer<LLViewerInventoryItem> inv = new LLViewerInventoryItem; + inv->unpackMessage(inv_entry); + mInventory->push_front(inv); + } + else + { + LL_WARNS_ONCE() << "Unknown inventory entry while reading from inventory file. Entry: '" + << inv_entry << "'" << LL_ENDL; + } + } + } + else + { + LL_WARNS() << "unable to load task inventory: " << inv_result << LL_ENDL; + return; + } + doInventoryCallback(); +} + void LLViewerObject::doInventoryCallback() { for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index fa2bbd0a15..783538fb13 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -662,6 +662,7 @@ private: // forms task inventory request after some time passed, marks request as pending void fetchInventoryDelayed(const F64 &time_seconds); static void fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds); + static void fetchInventoryFromCapCoro(const LLUUID task_inv); public: // @@ -791,6 +792,7 @@ protected: static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status); BOOL loadTaskInvFile(const std::string& filename); + void loadTaskInvLLSD(const LLSD &inv_result); void doInventoryCallback(); BOOL isOnMap(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index f98336240c..a0edfe5c81 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3098,6 +3098,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("FetchInventory2"); capabilityNames.append("FetchInventoryDescendents2"); capabilityNames.append("IncrementCOFVersion"); + capabilityNames.append("RequestTaskInventory"); AISAPI::getCapNames(capabilityNames); capabilityNames.append("InterestList"); -- cgit v1.2.3 From 894dd1937511df08fa57c5e586d40a7778473dae Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 31 May 2024 17:02:25 -0400 Subject: Tweak for current Lua dbg() convention. --- indra/newview/scripts/lua/ErrorQueue.lua | 2 +- indra/newview/scripts/lua/WaitQueue.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index 6ed1c10d5c..13e4e92941 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -3,8 +3,8 @@ -- raise that error. local WaitQueue = require('WaitQueue') --- local dbg = require('printf') local function dbg(...) end +-- local dbg = require('printf') local ErrorQueue = WaitQueue:new() diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index ad4fdecf43..6bcb9d62c2 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -5,8 +5,8 @@ local fiber = require('fiber') local Queue = require('Queue') --- local dbg = require('printf') local function dbg(...) end +-- local dbg = require('printf') local WaitQueue = Queue:new() -- cgit v1.2.3 From de719553fddc381e274d8bff218ab4e3f6691945 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 31 May 2024 17:15:06 -0400 Subject: Add timers.lua API module and test_timers.lua test program. Since timers presents a timers.Timer Lua class supporting queries and cancellation, make TimersListener::scheduleAfter() and scheduleEvery() respond immediately so the newly constructed Timer object has the reqid necessary to perform those subsequent operations. This requires that Lua invocations of these operations avoid calling the caller's callback with that initial response. Reinvent leap.generate() to return a Lua object supporting next() and done() methods. A plain Lua coroutine that (indirectly) calls fiber.wait() confuses the fiber scheduler, so avoid implementing generate() as a Lua coroutine. Add a bit more leap.lua diagnostic output. --- indra/newview/scripts/lua/leap.lua | 59 ++++++++++------- indra/newview/scripts/lua/test_timers.lua | 39 ++++++++++++ indra/newview/scripts/lua/timers.lua | 101 ++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 indra/newview/scripts/lua/test_timers.lua create mode 100644 indra/newview/scripts/lua/timers.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 69cedb4c9e..8caae24e94 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -172,36 +172,45 @@ function leap.request(pump, data) end -- Send the specified request LLSD, expecting an arbitrary number of replies. --- Each one is yielded on receipt. If you omit checklast, this is an infinite --- generator; it's up to the caller to recognize when the last reply has been --- received, and stop resuming for more. --- --- If you pass checklast=<callable accepting(event)>, each response event is --- passed to that callable (after the yield). When the callable returns --- true, the generator terminates in the usual way. +-- Each one is returned on request. +-- +-- Usage: +-- sequence = leap.generate(pump, data) +-- repeat +-- response = sequence.next() +-- until last(response) +-- (last() means whatever test the caller wants to perform on response) +-- sequence.done() -- -- See request() remarks about ["reqid"]. +-- +-- Note: this seems like a prime use case for Lua coroutines. But in a script +-- using fibers.lua, a "wild" coroutine confuses the fiber scheduler. If +-- generate() were itself a coroutine, it would call WaitForReqid:wait(), +-- which would yield -- thereby resuming generate() WITHOUT waiting. function leap.generate(pump, data, checklast) -- Invent a new, unique reqid. Arrange to handle incoming events -- bearing that reqid. Stamp the outbound request with that reqid, and -- send it. local reqid, waitfor = requestSetup(pump, data) - local ok, response, resumed_with - repeat - ok, response = pcall(waitfor.wait, waitfor) - if (not ok) or response.error then - break + return { + next = function() + dbg('leap.generate(%s).next() about to wait on %s', reqid, tostring(waitfor)) + local ok, response = pcall(waitfor.wait, waitfor) + dbg('leap.generate(%s).next() got %s: %s', reqid, ok, response) + if not ok then + error(response) + elseif response.error then + error(response.error) + else + return response + end + end, + done = function() + -- cleanup consists of removing our WaitForReqid from pending + pending[reqid] = nil end - -- can resume(false) to terminate generate() and clean up - resumed_with = coroutine.yield(response) - until (checklast and checklast(response)) or (resumed_with == false) - -- If we break the above loop, whether or not due to error, clean up. - pending[reqid] = nil - if not ok then - error(response) - elseif response.error then - error(response.error) - end + } end -- Send the specified request LLSD, expecting an immediate reply followed by @@ -220,7 +229,9 @@ function leap.eventstream(pump, data, callback) end -- No error, so far so good: -- call the callback with the first response just in case + dbg('leap.eventstream(%s): first callback', reqid) local ok, done = pcall(callback, response) + dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) if not ok then -- clean up our WaitForReqid waitfor:close() @@ -236,13 +247,17 @@ function leap.eventstream(pump, data, callback) pump, function () local ok, done + local nth = 1 repeat event = waitfor:wait() if not event then -- wait() returns nil once the queue is closed (e.g. cancelreq()) ok, done = true, true else + nth += 1 + dbg('leap.eventstream(%s): callback %d', reqid, nth) ok, done = pcall(callback, event) + dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) end -- not ok means callback threw an error (caught as 'done') -- done means callback succeeded but wants to stop diff --git a/indra/newview/scripts/lua/test_timers.lua b/indra/newview/scripts/lua/test_timers.lua new file mode 100644 index 0000000000..53a2dc83f2 --- /dev/null +++ b/indra/newview/scripts/lua/test_timers.lua @@ -0,0 +1,39 @@ +local timers = require 'timers' + +print('t0:new(10)') +start = os.clock() +t0 = timers.Timer:new(10, function() print('t0 fired at', os.clock() - start) end) +print('t0:isRunning(): ', t0:isRunning()) +print('t0:timeUntilCall(): ', t0:timeUntilCall()) +print('t0:cancel(): ', t0:cancel()) +print('t0:isRunning(): ', t0:isRunning()) +print('t0:timeUntilCall(): ', t0:timeUntilCall()) +print('t0:cancel(): ', t0:cancel()) + +print('t1:new(5)') +start = os.clock() +t1 = timers.Timer:new(5, function() print('t1 fired at', os.clock() - start) end) + +print('t2:new(2)') +start = os.clock() +t2 = timers.Timer:new(2) +function t2:tick() + print('t2 fired at', os.clock() - start) +end + +start = os.clock() +timers.Timer:new(5, 'wait') +print(string.format('Timer(5) waited %f seconds', os.clock() - start)) + +start = os.clock() +timers.Timer:new( + 2, + coroutine.wrap(function() + for i = 1,5 do + print('repeat(2) timer fired at ', os.clock() - start) + coroutine.yield(nil) -- keep running + end + print('repeat(2) timer fired last at ', os.clock() - start) + return true -- stop + end), + true) -- iterate diff --git a/indra/newview/scripts/lua/timers.lua b/indra/newview/scripts/lua/timers.lua new file mode 100644 index 0000000000..e0d27a680d --- /dev/null +++ b/indra/newview/scripts/lua/timers.lua @@ -0,0 +1,101 @@ +-- Access to the viewer's time-delay facilities + +local leap = require 'leap' + +local timers = {} + +local function dbg(...) end +-- local dbg = require 'printf' + +timers.Timer = {} + +-- delay: time in seconds until callback +-- callback: 'wait', or function to call when timer fires (self:tick if nil) +-- iterate: if non-nil, call callback repeatedly until it returns non-nil +-- (ignored if 'wait') +function timers.Timer:new(delay, callback, iterate) + local obj = setmetatable({}, self) + self.__index = self + + if callback == 'wait' then + dbg('scheduleAfter(%d):', delay) + sequence = leap.generate('Timers', {op='scheduleAfter', after=delay}) + -- ignore the immediate return + dbg('scheduleAfter(%d) -> %s', delay, + sequence.next()) + -- this call is where we wait for real + dbg('next():') + dbg('next() -> %s', + sequence.next()) + sequence.done() + return + end + + callback = callback or function() obj:tick() end + + local first = true + if iterate then + obj.id = leap.eventstream( + 'Timers', + {op='scheduleEvery', every=delay}, + function (event) + local reqid = event.reqid + if first then + first = false + dbg('timer(%s) first callback', reqid) + -- discard the first (immediate) response: don't call callback + return nil + else + dbg('timer(%s) nth callback', reqid) + return callback(event) + end + end + ).reqid + else + obj.id = leap.eventstream( + 'Timers', + {op='scheduleAfter', after=delay}, + function (event) + -- Arrange to return nil the first time, true the second. This + -- callback is called immediately with the response to + -- 'scheduleAfter', and if we immediately returned true, we'd + -- be done, and the subsequent timer event would be discarded. + if first then + first = false + -- Caller doesn't expect an immediate callback. + return nil + else + callback(event) + -- Since caller doesn't want to iterate, the value + -- returned by the callback is irrelevant: just stop after + -- this one and only call. + return true + end + end + ).reqid + end + + return obj +end + +function timers.Timer:tick() + error('Pass a callback to Timer:new(), or override Timer:tick()') +end + +function timers.Timer:cancel() + local ok = leap.request('Timers', {op='cancel', id=self.id}).ok + leap.cancelreq(self.id) + return ok +end + +function timers.Timer:isRunning() + return leap.request('Timers', {op='isRunning', id=self.id}).running +end + +-- returns (true, seconds left) for a live timer, else (false, 0) +function timers.Timer:timeUntilCall() + local result = leap.request('Timers', {op='timeUntilCall', id=self.id}) + return result.ok, result.remaining +end + +return timers -- cgit v1.2.3 From 47821cf53f89acec4ed6d465e14d7793d2420b41 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 3 Jun 2024 11:48:11 -0400 Subject: Leverage new leap.eventstream() function in Floater.lua. --- indra/newview/scripts/lua/Floater.lua | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/Floater.lua b/indra/newview/scripts/lua/Floater.lua index 76efd47c43..75696533e4 100644 --- a/indra/newview/scripts/lua/Floater.lua +++ b/indra/newview/scripts/lua/Floater.lua @@ -46,10 +46,18 @@ function Floater:new(path, extra) end function Floater:show() - local event = leap.request('LLFloaterReg', self._command) + -- leap.eventstream() returns the first response, and launches a + -- background fiber to call the passed callback with all subsequent + -- responses. + local event = leap.eventstream( + 'LLFloaterReg', + self._command, + -- handleEvents() returns false when done. + -- eventstream() expects a true return when done. + function(event) return not self:handleEvents(event) end) self._pump = event.command_name - -- we use the returned reqid to claim subsequent unsolicited events - local reqid = event.reqid + -- we might need the returned reqid to cancel the eventstream() fiber + self.reqid = event.reqid -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if -- subclass has a post_build() method. Honor the convention that if @@ -57,22 +65,6 @@ function Floater:show() if not self:handleEvents(event) then return end - - local waitfor = leap.WaitFor:new(-1, self.name) - function waitfor:filter(pump, data) - if data.reqid == reqid then - return data - end - end - - fiber.launch( - self.name, - function () - event = waitfor:wait() - while event and self:handleEvents(event) do - event = waitfor:wait() - end - end) end function Floater:post(action) @@ -125,7 +117,7 @@ function Floater:handleEvents(event_data) -- We check for event() method before recognizing floater_close in case -- the consumer needs to react specially to closing the floater. Now that -- we've checked, recognize it ourselves. Returning false terminates the - -- anonymous fiber function launched by show(). + -- anonymous fiber function launched by leap.eventstream(). if event == _event('floater_close') then LL.print_warning(self.name .. ' closed') return false -- cgit v1.2.3 From 9e6cf32add0a857b4e28c638bd378a8d3f70fcdb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 4 Jun 2024 09:52:55 -0400 Subject: Comment the intent of test_timers.lua so the user need not reverse-engineer the code to figure out the output. --- indra/newview/scripts/lua/test_timers.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_timers.lua b/indra/newview/scripts/lua/test_timers.lua index 53a2dc83f2..ed0de070f7 100644 --- a/indra/newview/scripts/lua/test_timers.lua +++ b/indra/newview/scripts/lua/test_timers.lua @@ -1,5 +1,11 @@ local timers = require 'timers' +-- This t0 is constructed for 10 seconds, but its purpose is to exercise the +-- query and cancel methods. It would print "t0 fired at..." if it fired, but +-- it doesn't, so you don't see that message. Instead you see that isRunning() +-- is true, that timeUntilCall() is (true, close to 10), that cancel() returns +-- true. After that, isRunning() is false, timeUntilCall() returns (false, 0), +-- and a second cancel() returns false. print('t0:new(10)') start = os.clock() t0 = timers.Timer:new(10, function() print('t0 fired at', os.clock() - start) end) @@ -10,10 +16,15 @@ print('t0:isRunning(): ', t0:isRunning()) print('t0:timeUntilCall(): ', t0:timeUntilCall()) print('t0:cancel(): ', t0:cancel()) +-- t1 is supposed to fire after 5 seconds, but it doesn't wait, so you see the +-- t2 messages immediately after. print('t1:new(5)') start = os.clock() t1 = timers.Timer:new(5, function() print('t1 fired at', os.clock() - start) end) +-- t2 illustrates that instead of passing a callback to new(), you can +-- override the timer instance's tick() method. But t2 doesn't wait either, so +-- you see the Timer(5) message immediately. print('t2:new(2)') start = os.clock() t2 = timers.Timer:new(2) @@ -21,10 +32,23 @@ function t2:tick() print('t2 fired at', os.clock() - start) end +-- This anonymous timer blocks the calling fiber for 5 seconds. Other fibers +-- are free to run during that time, so you see the t2 callback message and +-- then the t1 callback message before the Timer(5) completion message. +print('Timer(5) waiting') start = os.clock() timers.Timer:new(5, 'wait') print(string.format('Timer(5) waited %f seconds', os.clock() - start)) +-- This test demonstrates a repeating timer. It also shows that you can (but +-- need not) use a coroutine as the timer's callback function: unlike Python, +-- Lua doesn't disinguish between yield() and return. A coroutine wrapped with +-- coroutine.wrap() looks to Lua just like any other function that you can +-- call repeatedly and get a result each time. We use that to count the +-- callback calls and stop after a certain number. Of course that could also +-- be arranged in a plain function by incrementing a script-scope counter, but +-- it's worth knowing that a coroutine timer callback can be used to manage +-- more complex control flows. start = os.clock() timers.Timer:new( 2, -- cgit v1.2.3 From 486a6b189a3ea3fb2700718a64f574c3240fae7d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 7 Jun 2024 21:43:41 -0400 Subject: Introduce mapargs.lua, which defines the mapargs() function. There are two conventions for Lua function calls. You can call a function with positional arguments as usual: f(1, 2, 3) Lua makes it easy to handle omitted positional arguments: their values are nil. But as in C++, positional arguments get harder to read when there are many, or when you want to omit arguments other than the last ones. Alternatively, using Lua syntactic sugar, you can pass a single argument which is a table containing the desired function arguments. For this you can use table constructor syntax to effect keyword arguments: f{a=1, b=2, c=3} A call passing keyword arguments is more readable because you explicitly associate the parameter name with each argument value. Moreover, it gracefully handles the case of multiple optional arguments. The reader need not be concerned about parameters *not* being passed. Now you're coding a Lua module with a number of functions. Some have numerous or complicated arguments; some do not. For simplicity, you code the simple functions to accept positional arguments, the more complicated functions to accept the single-table argument style. But how the bleep is a consumer of your module supposed to remember which calling style to use for a given function? mapargs() blurs the distinction, accepting either style. Coding a function like this (where '...' is literal code, not documentation ellipsis): function f(...) local args = mapargs({'a', 'b', 'c'}, ...) -- now use args.a, args.b, args.c end supports calls like: f(1, 2, 3) f{1, 2, 3} f{c=3, a=1, b=2} f{1, 2, c=3} f{c=3, 1, 2} -- unlike Python! In every call above, args.a == 1, args.b == 2, args.c == 3. Moreover, omitting arguments (or explicitly passing nil, positionally or by keyword) works correctly. test_mapargs.lua exercises these cases. --- indra/newview/scripts/lua/mapargs.lua | 67 +++++++++++++++++++++++++++++ indra/newview/scripts/lua/test_mapargs.lua | 68 ++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 indra/newview/scripts/lua/mapargs.lua create mode 100644 indra/newview/scripts/lua/test_mapargs.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/mapargs.lua b/indra/newview/scripts/lua/mapargs.lua new file mode 100644 index 0000000000..78e691d8bc --- /dev/null +++ b/indra/newview/scripts/lua/mapargs.lua @@ -0,0 +1,67 @@ +-- Allow a calling function to be passed a mix of positional arguments with +-- keyword arguments. Reference them as fields of a table. +-- Don't use this for a function that can accept a single table argument. +-- mapargs() assumes that a single table argument means its caller was called +-- with f{table constructor} syntax, and maps that table to the specified names. +-- Usage: +-- function f(...) +-- local a = mapargs({'a1', 'a2', 'a3'}, ...) +-- ... a.a1 ... etc. +-- end +-- f(10, 20, 30) -- a.a1 == 10, a.a2 == 20, a.a3 == 30 +-- f{10, 20, 30} -- a.a1 == 10, a.a2 == 20, a.a3 == 30 +-- f{a3=300, a1=100} -- a.a1 == 100, a.a2 == nil, a.a3 == 300 +-- f{1, a3=3} -- a.a1 == 1, a.a2 == nil, a.a3 == 3 +-- f{a3=3, 1} -- a.a1 == 1, a.a2 == nil, a.a3 == 3 +local function mapargs(names, ...) + local args = table.pack(...) + local posargs = {} + local keyargs = {} + -- For a mixed table, no Lua operation will reliably tell you how many + -- array items it contains, if there are any holes. Track that by hand. + -- We must be able to handle f(1, nil, 3) calls. + local maxpos = 0 + if not (args.n == 1 and type(args[1]) == 'table') then + -- If caller passes more than one argument, or if the first argument + -- is not a table, then it's classic positional function-call syntax: + -- f(first, second, etc.). In that case we need not bother teasing + -- apart positional from keyword arguments. + posargs = args + maxpos = args.n + else + -- Single table argument implies f{mixed} syntax. + -- Tease apart positional arguments from keyword arguments. + for k, v in pairs(args[1]) do + if type(k) == 'number' then + posargs[k] = v + maxpos = math.max(maxpos, k) + else + if table.find(names, k) == nil then + error('unknown keyword argument ' .. tostring(k)) + end + keyargs[k] = v + end + end + end + + -- keyargs already has keyword arguments in place, just fill in positionals + args = keyargs + -- Don't exceed the number of parameter names. Loop explicitly over every + -- index value instead of using ipairs() so we can support holes (nils) in + -- posargs. + for i = 1, math.min(#names, maxpos) do + if posargs[i] ~= nil then + -- As in Python, make it illegal to pass an argument both positionally + -- and by keyword. This implementation permits func(17, first=nil), a + -- corner case about which I don't particularly care. + if args[names[i]] ~= nil then + error(string.format('parameter %s passed both positionally and by keyword', + tostring(names[i]))) + end + args[names[i]] = posargs[i] + end + end + return args +end + +return mapargs diff --git a/indra/newview/scripts/lua/test_mapargs.lua b/indra/newview/scripts/lua/test_mapargs.lua new file mode 100644 index 0000000000..999a57acb4 --- /dev/null +++ b/indra/newview/scripts/lua/test_mapargs.lua @@ -0,0 +1,68 @@ +local mapargs = require 'mapargs' +local inspect = require 'inspect' + +function tabfunc(...) + local a = mapargs({'a1', 'a2', 'a3'}, ...) + print(inspect(a)) +end + +print('----------') +print('f(10, 20, 30)') +tabfunc(10, 20, 30) +print('f(10, nil, 30)') +tabfunc(10, nil, 30) +print('f{10, 20, 30}') +tabfunc{10, 20, 30} +print('f{10, nil, 30}') +tabfunc{10, nil, 30} +print('f{a3=300, a1=100}') +tabfunc{a3=300, a1=100} +print('f{1, a3=3}') +tabfunc{1, a3=3} +print('f{a3=3, 1}') +tabfunc{a3=3, 1} +print('----------') + +if false then + -- the code below was used to explore ideas that became mapargs() + mixed = { '[1]', nil, '[3]', abc='[abc]', '[3]', def='[def]' } + local function showtable(desc, t) + print(string.format('%s (len %s)\n%s', desc, #t, inspect(t))) + end + showtable('mixed', mixed) + + print('ipairs(mixed)') + for k, v in ipairs(mixed) do + print(string.format('[%s] = %s', k, tostring(v))) + end + + print('table.pack(mixed)') + print(inspect(table.pack(mixed))) + + local function nilarg(desc, a, b, c) + print(desc) + print('a = ' .. tostring(a)) + print('b = ' .. tostring(b)) + print('c = ' .. tostring(c)) + end + + nilarg('nilarg(1)', 1) + nilarg('nilarg(1, nil, 3)', 1, nil, 3) + + local function nilargs(desc, ...) + args = table.pack(...) + showtable(desc, args) + end + + nilargs('nilargs{a=1, b=2, c=3}', {a=1, b=2, c=3}) + nilargs('nilargs(1, 2, 3)', 1, 2, 3) + nilargs('nilargs(1, nil, 3)', 1, nil, 3) + nilargs('nilargs{1, 2, 3}', {1, 2, 3}) + nilargs('nilargs{1, nil, 3}', {1, nil, 3}) + + print('table.unpack({1, nil, 3})') + a, b, c = table.unpack({1, nil, 3}) + print('a = ' .. tostring(a)) + print('b = ' .. tostring(b)) + print('c = ' .. tostring(c)) +end -- cgit v1.2.3 From ad608dbc5f0d57ad29ec3a15e4d0a434dfaa38d2 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 10 Jun 2024 14:29:22 +0300 Subject: Remove SharedCommitCallbackRegistry; add helpers CommitRegistrarHelper and ScopedRegistrarHelper --- indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llfloaterauction.cpp | 8 +- indra/newview/llfloateravatarpicker.cpp | 2 +- indra/newview/llfloateravatarrendersettings.cpp | 4 +- indra/newview/llfloaterbeacons.cpp | 2 +- indra/newview/llfloaterbulkpermission.cpp | 12 +- indra/newview/llfloaterbump.cpp | 18 +-- indra/newview/llfloatercamera.cpp | 16 +-- indra/newview/llfloatercamerapresets.cpp | 4 +- indra/newview/llfloaterconversationlog.cpp | 2 +- indra/newview/llfloatereditextdaycycle.cpp | 4 +- indra/newview/llfloatergesture.cpp | 10 +- indra/newview/llfloatergodtools.cpp | 41 +++---- indra/newview/llfloaterimcontainer.cpp | 6 +- indra/newview/llfloaterimnearbychat.cpp | 2 +- indra/newview/llfloaterimsession.cpp | 2 +- indra/newview/llfloaterimsessiontab.cpp | 6 +- indra/newview/llfloaterinspect.cpp | 6 +- indra/newview/llfloaterlagmeter.cpp | 2 +- indra/newview/llfloaterluascripts.cpp | 8 +- indra/newview/llfloatermarketplacelistings.cpp | 2 +- indra/newview/llfloatermemleak.cpp | 12 +- indra/newview/llfloateropenobject.cpp | 4 +- indra/newview/llfloaterperformance.cpp | 2 +- indra/newview/llfloaterperms.cpp | 6 +- indra/newview/llfloaterpreference.cpp | 90 +++++++-------- .../llfloaterpreferencesgraphicsadvanced.cpp | 10 +- indra/newview/llfloaterpreferenceviewadvanced.cpp | 2 +- indra/newview/llfloaterscriptedprefs.cpp | 4 +- indra/newview/llfloatersettingsdebug.cpp | 4 +- indra/newview/llfloatertestinspectors.cpp | 4 +- indra/newview/llfloatertools.cpp | 30 ++--- indra/newview/llfloatertopobjects.cpp | 20 ++-- indra/newview/llfloatertoybox.cpp | 4 +- indra/newview/llfloatervoiceeffect.cpp | 6 +- indra/newview/llfloaterwebcontent.cpp | 14 +-- indra/newview/llfloaterworldmap.cpp | 22 ++-- indra/newview/llflyoutcombobtn.cpp | 2 +- indra/newview/llgrouplist.cpp | 2 +- indra/newview/llinspectgroup.cpp | 6 +- indra/newview/llinspectobject.cpp | 16 +-- indra/newview/llinventorygallerymenu.cpp | 14 ++- indra/newview/llinventorypanel.cpp | 24 ++-- indra/newview/lllocationinputctrl.cpp | 2 +- indra/newview/llmediactrl.cpp | 4 +- indra/newview/llnetmap.cpp | 2 +- indra/newview/lloutfitgallery.cpp | 6 +- indra/newview/lloutfitslist.cpp | 8 +- indra/newview/llpanelblockedlist.cpp | 2 +- indra/newview/llpanelface.cpp | 2 +- indra/newview/llpanelmaininventory.cpp | 20 ++-- indra/newview/llpanelmediasettingssecurity.cpp | 4 +- indra/newview/llpanelnearbymedia.cpp | 22 ++-- indra/newview/llpanelobject.cpp | 2 +- indra/newview/llpanelobjectinventory.cpp | 18 +-- indra/newview/llpaneloutfitedit.cpp | 4 +- indra/newview/llpanelpeople.cpp | 24 ++-- indra/newview/llpanelpeoplemenus.cpp | 22 ++-- indra/newview/llpanelpresetscamerapulldown.cpp | 4 +- indra/newview/llpanelpresetspulldown.cpp | 6 +- indra/newview/llpanelprimmediacontrols.cpp | 44 ++++---- indra/newview/llpanelprofile.cpp | 2 +- indra/newview/llpanelsnapshotinventory.cpp | 8 +- indra/newview/llpanelsnapshotlocal.cpp | 2 +- indra/newview/llpanelsnapshotoptions.cpp | 8 +- indra/newview/llpanelsnapshotpostcard.cpp | 4 +- indra/newview/llpanelsnapshotprofile.cpp | 4 +- indra/newview/llpanelteleporthistory.cpp | 9 +- indra/newview/llpaneltopinfobar.cpp | 2 +- indra/newview/llpanelvoiceeffect.cpp | 2 +- indra/newview/llpanelvolume.cpp | 2 +- indra/newview/llpanelvolumepulldown.cpp | 8 +- indra/newview/llpanelwearing.cpp | 6 +- indra/newview/llpreviewanim.cpp | 2 +- indra/newview/llpreviewscript.cpp | 2 +- indra/newview/llsaveoutfitcombobtn.cpp | 2 +- indra/newview/lltoolmgr.cpp | 4 +- indra/newview/llviewermenu.cpp | 121 ++++++++++----------- indra/newview/llwearableitemslist.cpp | 4 +- 79 files changed, 425 insertions(+), 420 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index d3c9cd26d7..6edaf0e1c0 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -395,7 +395,7 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) { // Register callback for menus with current registrar (will be parent panel's registrar) LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", - boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2)); + { boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK }); // Add this if we need to selectively enable items LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected", diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index f4a9400120..06d2e31814 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -76,10 +76,10 @@ LLFloaterAuction::LLFloaterAuction(const LLSD& key) : LLFloater(key), mParcelID(-1) { - mCommitCallbackRegistrar.add("ClickSnapshot", boost::bind(&LLFloaterAuction::onClickSnapshot, this)); - mCommitCallbackRegistrar.add("ClickSellToAnyone", boost::bind(&LLFloaterAuction::onClickSellToAnyone, this)); - mCommitCallbackRegistrar.add("ClickStartAuction", boost::bind(&LLFloaterAuction::onClickStartAuction, this)); - mCommitCallbackRegistrar.add("ClickResetParcel", boost::bind(&LLFloaterAuction::onClickResetParcel, this)); + mCommitCallbackRegistrar.add("ClickSnapshot", { boost::bind(&LLFloaterAuction::onClickSnapshot, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ClickSellToAnyone", { boost::bind(&LLFloaterAuction::onClickSellToAnyone, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ClickStartAuction", { boost::bind(&LLFloaterAuction::onClickStartAuction, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ClickResetParcel", { boost::bind(&LLFloaterAuction::onClickResetParcel, this), cb_info::UNTRUSTED_BLOCK }); } // Destroys the object diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index f903b1bd8d..681105236c 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -111,7 +111,7 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key) mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA), mContextConeFadeTime(CONTEXT_CONE_FADE_TIME) { - mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this)); + mCommitCallbackRegistrar.add("Refresh.FriendList", { boost::bind(&LLFloaterAvatarPicker::populateFriend, this), cb_info::UNTRUSTED_THROTTLE }); } BOOL LLFloaterAvatarPicker::postBuild() diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp index bc860308b3..d22537d371 100644 --- a/indra/newview/llfloateravatarrendersettings.cpp +++ b/indra/newview/llfloateravatarrendersettings.cpp @@ -51,7 +51,7 @@ protected: { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - registrar.add("Settings.SetRendering", boost::bind(&LLFloaterAvatarRenderSettings::onCustomAction, mFloaterSettings, _2, mUUIDs.front())); + registrar.add("Settings.SetRendering", { boost::bind(&LLFloaterAvatarRenderSettings::onCustomAction, mFloaterSettings, _2, mUUIDs.front()) }); enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterAvatarRenderSettings::isActionChecked, mFloaterSettings, _2, mUUIDs.front())); LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml"); @@ -75,7 +75,7 @@ LLFloaterAvatarRenderSettings::LLFloaterAvatarRenderSettings(const LLSD& key) { mContextMenu = new LLSettingsContextMenu(this); LLRenderMuteList::getInstance()->addObserver(&sAvatarRenderMuteListObserver); - mCommitCallbackRegistrar.add("Settings.AddNewEntry", boost::bind(&LLFloaterAvatarRenderSettings::onClickAdd, this, _2)); + mCommitCallbackRegistrar.add("Settings.AddNewEntry", {boost::bind(&LLFloaterAvatarRenderSettings::onClickAdd, this, _2)}); } LLFloaterAvatarRenderSettings::~LLFloaterAvatarRenderSettings() diff --git a/indra/newview/llfloaterbeacons.cpp b/indra/newview/llfloaterbeacons.cpp index fb1da84e79..f363705e5f 100644 --- a/indra/newview/llfloaterbeacons.cpp +++ b/indra/newview/llfloaterbeacons.cpp @@ -49,7 +49,7 @@ LLFloaterBeacons::LLFloaterBeacons(const LLSD& seed) LLPipeline::setRenderHighlights( gSavedSettings.getBOOL("renderhighlights")); LLPipeline::setRenderBeacons( gSavedSettings.getBOOL("renderbeacons")); LLPipeline::setRenderMOAPBeacons( gSavedSettings.getBOOL("moapbeacon")); - mCommitCallbackRegistrar.add("Beacons.UICheck", boost::bind(&LLFloaterBeacons::onClickUICheck, this,_1)); + mCommitCallbackRegistrar.add("Beacons.UICheck", { boost::bind(&LLFloaterBeacons::onClickUICheck, this,_1) }); } BOOL LLFloaterBeacons::postBuild() diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp index 243c546169..bc6586320d 100644 --- a/indra/newview/llfloaterbulkpermission.cpp +++ b/indra/newview/llfloaterbulkpermission.cpp @@ -56,12 +56,12 @@ LLFloaterBulkPermission::LLFloaterBulkPermission(const LLSD& seed) mDone(FALSE) { mID.generate(); - mCommitCallbackRegistrar.add("BulkPermission.Ok", boost::bind(&LLFloaterBulkPermission::onOkBtn, this)); - mCommitCallbackRegistrar.add("BulkPermission.Apply", boost::bind(&LLFloaterBulkPermission::onApplyBtn, this)); - mCommitCallbackRegistrar.add("BulkPermission.Close", boost::bind(&LLFloaterBulkPermission::onCloseBtn, this)); - mCommitCallbackRegistrar.add("BulkPermission.CheckAll", boost::bind(&LLFloaterBulkPermission::onCheckAll, this)); - mCommitCallbackRegistrar.add("BulkPermission.UncheckAll", boost::bind(&LLFloaterBulkPermission::onUncheckAll, this)); - mCommitCallbackRegistrar.add("BulkPermission.CommitCopy", boost::bind(&LLFloaterBulkPermission::onCommitCopy, this)); + mCommitCallbackRegistrar.add("BulkPermission.Ok", { boost::bind(&LLFloaterBulkPermission::onOkBtn, this) }); + mCommitCallbackRegistrar.add("BulkPermission.Apply", { boost::bind(&LLFloaterBulkPermission::onApplyBtn, this) }); + mCommitCallbackRegistrar.add("BulkPermission.Close", { boost::bind(&LLFloaterBulkPermission::onCloseBtn, this) }); + mCommitCallbackRegistrar.add("BulkPermission.CheckAll", { boost::bind(&LLFloaterBulkPermission::onCheckAll, this) }); + mCommitCallbackRegistrar.add("BulkPermission.UncheckAll", { boost::bind(&LLFloaterBulkPermission::onUncheckAll, this) }); + mCommitCallbackRegistrar.add("BulkPermission.CommitCopy", { boost::bind(&LLFloaterBulkPermission::onCommitCopy, this) }); } BOOL LLFloaterBulkPermission::postBuild() diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 8138a3c976..46a9ba0a12 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -51,18 +51,18 @@ LLFloaterBump::LLFloaterBump(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("Avatar.SendIM", boost::bind(&LLFloaterBump::startIM, this)); - mCommitCallbackRegistrar.add("Avatar.ReportAbuse", boost::bind(&LLFloaterBump::reportAbuse, this)); - mCommitCallbackRegistrar.add("ShowAgentProfile", boost::bind(&LLFloaterBump::showProfile, this)); - mCommitCallbackRegistrar.add("Avatar.InviteToGroup", boost::bind(&LLFloaterBump::inviteToGroup, this)); - mCommitCallbackRegistrar.add("Avatar.Call", boost::bind(&LLFloaterBump::startCall, this)); + mCommitCallbackRegistrar.add("Avatar.SendIM", { boost::bind(&LLFloaterBump::startIM, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("Avatar.ReportAbuse", { boost::bind(&LLFloaterBump::reportAbuse, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("ShowAgentProfile", { boost::bind(&LLFloaterBump::showProfile, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("Avatar.InviteToGroup", { boost::bind(&LLFloaterBump::inviteToGroup, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("Avatar.Call", { boost::bind(&LLFloaterBump::startCall, this), cb_info::UNTRUSTED_BLOCK }); mEnableCallbackRegistrar.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); - mCommitCallbackRegistrar.add("Avatar.AddFriend", boost::bind(&LLFloaterBump::addFriend, this)); + mCommitCallbackRegistrar.add("Avatar.AddFriend", { boost::bind(&LLFloaterBump::addFriend, this), cb_info::UNTRUSTED_THROTTLE }); mEnableCallbackRegistrar.add("Avatar.EnableAddFriend", boost::bind(&LLFloaterBump::enableAddFriend, this)); - mCommitCallbackRegistrar.add("Avatar.Mute", boost::bind(&LLFloaterBump::muteAvatar, this)); + mCommitCallbackRegistrar.add("Avatar.Mute", { boost::bind(&LLFloaterBump::muteAvatar, this), cb_info::UNTRUSTED_BLOCK }); mEnableCallbackRegistrar.add("Avatar.EnableMute", boost::bind(&LLFloaterBump::enableMute, this)); - mCommitCallbackRegistrar.add("PayObject", boost::bind(&LLFloaterBump::payAvatar, this)); - mCommitCallbackRegistrar.add("Tools.LookAtSelection", boost::bind(&LLFloaterBump::zoomInAvatar, this)); + mCommitCallbackRegistrar.add("PayObject", { boost::bind(&LLFloaterBump::payAvatar, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Tools.LookAtSelection", { boost::bind(&LLFloaterBump::zoomInAvatar, this) }); } diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp index 4b91ff6881..143def4594 100644 --- a/indra/newview/llfloatercamera.cpp +++ b/indra/newview/llfloatercamera.cpp @@ -169,11 +169,11 @@ static LLPanelInjector<LLPanelCameraZoom> t_camera_zoom_panel("camera_zoom_panel void LLPanelCameraZoom::onCreate() { - mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this)); - mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this)); - mCommitCallbackRegistrar.add("Slider.value_changed", boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this)); - mCommitCallbackRegistrar.add("Camera.track", boost::bind(&LLPanelCameraZoom::onCameraTrack, this)); - mCommitCallbackRegistrar.add("Camera.rotate", boost::bind(&LLPanelCameraZoom::onCameraRotate, this)); + mCommitCallbackRegistrar.add("Zoom.minus", { boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this) }); + mCommitCallbackRegistrar.add("Zoom.plus", { boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this) }); + mCommitCallbackRegistrar.add("Slider.value_changed", { boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this) }); + mCommitCallbackRegistrar.add("Camera.track", { boost::bind(&LLPanelCameraZoom::onCameraTrack, this) }); + mCommitCallbackRegistrar.add("Camera.rotate", { boost::bind(&LLPanelCameraZoom::onCameraRotate, this) }); } BOOL LLPanelCameraZoom::postBuild() @@ -461,9 +461,9 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val) mPrevMode(CAMERA_CTRL_MODE_PAN) { LLHints::getInstance()->registerHintTarget("view_popup", getHandle()); - mCommitCallbackRegistrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2)); - mCommitCallbackRegistrar.add("CameraPresets.Save", boost::bind(&LLFloaterCamera::onSavePreset, this)); - mCommitCallbackRegistrar.add("CameraPresets.ShowPresetsList", boost::bind(&LLFloaterReg::showInstance, "camera_presets", LLSD(), FALSE)); + mCommitCallbackRegistrar.add("CameraPresets.ChangeView", {boost::bind(&LLFloaterCamera::onClickCameraItem, _2)}); + mCommitCallbackRegistrar.add("CameraPresets.Save", {boost::bind(&LLFloaterCamera::onSavePreset, this)}); + mCommitCallbackRegistrar.add("CameraPresets.ShowPresetsList", {boost::bind(&LLFloaterReg::showInstance, "camera_presets", LLSD(), FALSE)}); } // virtual diff --git a/indra/newview/llfloatercamerapresets.cpp b/indra/newview/llfloatercamerapresets.cpp index eaf03dea81..68897804f3 100644 --- a/indra/newview/llfloatercamerapresets.cpp +++ b/indra/newview/llfloatercamerapresets.cpp @@ -90,8 +90,8 @@ LLCameraPresetFlatItem::LLCameraPresetFlatItem(const std::string &preset_name, b mPresetName(preset_name), mIsDefaultPrest(is_default) { - mCommitCallbackRegistrar.add("CameraPresets.Delete", boost::bind(&LLCameraPresetFlatItem::onDeleteBtnClick, this)); - mCommitCallbackRegistrar.add("CameraPresets.Reset", boost::bind(&LLCameraPresetFlatItem::onResetBtnClick, this)); + mCommitCallbackRegistrar.add("CameraPresets.Delete", { boost::bind(&LLCameraPresetFlatItem::onDeleteBtnClick, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("CameraPresets.Reset", { boost::bind(&LLCameraPresetFlatItem::onResetBtnClick, this), cb_info::UNTRUSTED_BLOCK }); buildFromFile("panel_camera_preset_item.xml"); } diff --git a/indra/newview/llfloaterconversationlog.cpp b/indra/newview/llfloaterconversationlog.cpp index 23f5c1e96d..b1e884d2ad 100644 --- a/indra/newview/llfloaterconversationlog.cpp +++ b/indra/newview/llfloaterconversationlog.cpp @@ -35,7 +35,7 @@ LLFloaterConversationLog::LLFloaterConversationLog(const LLSD& key) : LLFloater(key), mConversationLogList(NULL) { - mCommitCallbackRegistrar.add("CallLog.Action", boost::bind(&LLFloaterConversationLog::onCustomAction, this, _2)); + mCommitCallbackRegistrar.add("CallLog.Action", { boost::bind(&LLFloaterConversationLog::onCustomAction, this, _2) }); mEnableCallbackRegistrar.add("CallLog.Check", boost::bind(&LLFloaterConversationLog::isActionChecked, this, _2)); } diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index 2db1ef381d..a81375b595 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -185,8 +185,8 @@ LLFloaterEditExtDayCycle::LLFloaterEditExtDayCycle(const LLSD &key) : mClearTrack(nullptr) { - mCommitCallbackRegistrar.add(EVNT_DAYTRACK, [this](LLUICtrl *ctrl, const LLSD &data) { onTrackSelectionCallback(data); }); - mCommitCallbackRegistrar.add(EVNT_PLAY, [this](LLUICtrl *ctrl, const LLSD &data) { onPlayActionCallback(data); }); + mCommitCallbackRegistrar.add(EVNT_DAYTRACK, { [this](LLUICtrl *ctrl, const LLSD &data) { onTrackSelectionCallback(data); }}); + mCommitCallbackRegistrar.add(EVNT_PLAY, { [this](LLUICtrl *ctrl, const LLSD &data) { onPlayActionCallback(data); }}); mScratchSky = LLSettingsVOSky::buildDefaultSky(); mScratchWater = LLSettingsVOWater::buildDefaultWater(); diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 3b2132d4b1..c2c1fb89e7 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -122,11 +122,11 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key) mObserver = new LLFloaterGestureObserver(this); LLGestureMgr::instance().addObserver(mObserver); - mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this)); - mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this)); - mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2)); - mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this)); - mCommitCallbackRegistrar.add("Gesture.Action.Rename", boost::bind(&LLFloaterGesture::onRenameSelected, this)); + mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", { boost::bind(&LLFloaterGesture::onActivateBtnClick, this) }); + mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", { boost::bind(&LLFloaterGesture::onClickEdit, this) }); + mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", { boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2) }); + mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", { boost::bind(&LLFloaterGesture::addToCurrentOutFit, this) }); + mCommitCallbackRegistrar.add("Gesture.Action.Rename", { boost::bind(&LLFloaterGesture::onRenameSelected, this) }); mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2)); } diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index 3b99139aba..2c3038631e 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -431,15 +431,15 @@ const F32 PRICE_PER_METER_DEFAULT = 1.f; LLPanelRegionTools::LLPanelRegionTools() : LLPanel() { - mCommitCallbackRegistrar.add("RegionTools.ChangeAnything", boost::bind(&LLPanelRegionTools::onChangeAnything, this)); - mCommitCallbackRegistrar.add("RegionTools.ChangePrelude", boost::bind(&LLPanelRegionTools::onChangePrelude, this)); - mCommitCallbackRegistrar.add("RegionTools.BakeTerrain", boost::bind(&LLPanelRegionTools::onBakeTerrain, this)); - mCommitCallbackRegistrar.add("RegionTools.RevertTerrain", boost::bind(&LLPanelRegionTools::onRevertTerrain, this)); - mCommitCallbackRegistrar.add("RegionTools.SwapTerrain", boost::bind(&LLPanelRegionTools::onSwapTerrain, this)); - mCommitCallbackRegistrar.add("RegionTools.Refresh", boost::bind(&LLPanelRegionTools::onRefresh, this)); - mCommitCallbackRegistrar.add("RegionTools.ApplyChanges", boost::bind(&LLPanelRegionTools::onApplyChanges, this)); - mCommitCallbackRegistrar.add("RegionTools.SelectRegion", boost::bind(&LLPanelRegionTools::onSelectRegion, this)); - mCommitCallbackRegistrar.add("RegionTools.SaveState", boost::bind(&LLPanelRegionTools::onSaveState, this)); + mCommitCallbackRegistrar.add("RegionTools.ChangeAnything", { boost::bind(&LLPanelRegionTools::onChangeAnything, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.ChangePrelude", { boost::bind(&LLPanelRegionTools::onChangePrelude, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.BakeTerrain", { boost::bind(&LLPanelRegionTools::onBakeTerrain, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.RevertTerrain", { boost::bind(&LLPanelRegionTools::onRevertTerrain, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.SwapTerrain", { boost::bind(&LLPanelRegionTools::onSwapTerrain, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.Refresh", { boost::bind(&LLPanelRegionTools::onRefresh, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.ApplyChanges", { boost::bind(&LLPanelRegionTools::onApplyChanges, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.SelectRegion", { boost::bind(&LLPanelRegionTools::onSelectRegion, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("RegionTools.SaveState", { boost::bind(&LLPanelRegionTools::onSaveState, this), cb_info::UNTRUSTED_BLOCK }); } BOOL LLPanelRegionTools::postBuild() @@ -854,7 +854,8 @@ void LLPanelRegionTools::onSelectRegion() LLPanelGridTools::LLPanelGridTools() : LLPanel() { - mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches", boost::bind(&LLPanelGridTools::onClickFlushMapVisibilityCaches, this)); + mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches", + { boost::bind(&LLPanelGridTools::onClickFlushMapVisibilityCaches, this), cb_info::UNTRUSTED_BLOCK }); } // Destroys the object @@ -929,15 +930,15 @@ LLPanelObjectTools::LLPanelObjectTools() : LLPanel(), mTargetAvatar() { - mCommitCallbackRegistrar.add("ObjectTools.ChangeAnything", boost::bind(&LLPanelObjectTools::onChangeAnything, this)); - mCommitCallbackRegistrar.add("ObjectTools.DeletePublicOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeletePublicOwnedBy, this)); - mCommitCallbackRegistrar.add("ObjectTools.DeleteAllScriptedOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy, this)); - mCommitCallbackRegistrar.add("ObjectTools.DeleteAllOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeleteAllOwnedBy, this)); - mCommitCallbackRegistrar.add("ObjectTools.ApplyChanges", boost::bind(&LLPanelObjectTools::onApplyChanges, this)); - mCommitCallbackRegistrar.add("ObjectTools.Set", boost::bind(&LLPanelObjectTools::onClickSet, this)); - mCommitCallbackRegistrar.add("ObjectTools.GetTopColliders", boost::bind(&LLPanelObjectTools::onGetTopColliders, this)); - mCommitCallbackRegistrar.add("ObjectTools.GetTopScripts", boost::bind(&LLPanelObjectTools::onGetTopScripts, this)); - mCommitCallbackRegistrar.add("ObjectTools.GetScriptDigest", boost::bind(&LLPanelObjectTools::onGetScriptDigest, this)); + mCommitCallbackRegistrar.add("ObjectTools.ChangeAnything", { boost::bind(&LLPanelObjectTools::onChangeAnything, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.DeletePublicOwnedBy", { boost::bind(&LLPanelObjectTools::onClickDeletePublicOwnedBy, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.DeleteAllScriptedOwnedBy", { boost::bind(&LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.DeleteAllOwnedBy", { boost::bind(&LLPanelObjectTools::onClickDeleteAllOwnedBy, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.ApplyChanges", { boost::bind(&LLPanelObjectTools::onApplyChanges, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.Set", { boost::bind(&LLPanelObjectTools::onClickSet, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.GetTopColliders", { boost::bind(&LLPanelObjectTools::onGetTopColliders, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.GetTopScripts", { boost::bind(&LLPanelObjectTools::onGetTopScripts, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ObjectTools.GetScriptDigest", { boost::bind(&LLPanelObjectTools::onGetScriptDigest, this), cb_info::UNTRUSTED_BLOCK }); } // Destroys the object @@ -1224,7 +1225,7 @@ const std::string AGENT_REGION = "Agent Region"; LLPanelRequestTools::LLPanelRequestTools(): LLPanel() { - mCommitCallbackRegistrar.add("GodTools.Request", boost::bind(&LLPanelRequestTools::onClickRequest, this)); + mCommitCallbackRegistrar.add("GodTools.Request", {boost::bind(&LLPanelRequestTools::onClickRequest, this), cb_info::UNTRUSTED_BLOCK }); } LLPanelRequestTools::~LLPanelRequestTools() diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 8d0f0a0e57..9521b716ef 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -76,14 +76,14 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param mConversationEventQueue() { mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2)); - mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2)); + mCommitCallbackRegistrar.add("IMFloaterContainer.Action", { boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2) }); mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMContainer::checkContextMenuItem, this, _2)); mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMContainer::enableContextMenuItem, this, _2)); mEnableCallbackRegistrar.add("Avatar.VisibleItem", boost::bind(&LLFloaterIMContainer::visibleContextMenuItem, this, _2)); - mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMContainer::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Avatar.DoToSelected", { boost::bind(&LLFloaterIMContainer::doToSelected, this, _2) }); - mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&LLFloaterIMContainer::doToSelectedGroup, this, _2)); + mCommitCallbackRegistrar.add("Group.DoToSelected", { boost::bind(&LLFloaterIMContainer::doToSelectedGroup, this, _2) }); // Firstly add our self to IMSession observers, so we catch session events LLIMMgr::getInstance()->addSessionObserver(this); diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 6b817c7cf1..6c2cdc0897 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -109,7 +109,7 @@ LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd) // Required by LLFloaterIMSessionTab::mGearBtn // But nearby floater has no 'per agent' menu items, mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&cb_do_nothing)); - mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&cb_do_nothing)); + mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", { boost::bind(&cb_do_nothing) }); mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&cb_do_nothing)); mMinFloaterHeight = EXPANDED_MIN_HEIGHT; diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index a2d1cb7036..85d55575be 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -92,7 +92,7 @@ LLFloaterIMSession::LLFloaterIMSession(const LLUUID& session_id) LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this); mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&LLFloaterIMSession::enableGearMenuItem, this, _2)); - mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&LLFloaterIMSession::GearDoToSelected, this, _2)); + mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", { boost::bind(&LLFloaterIMSession::GearDoToSelected, this, _2), cb_info::UNTRUSTED_BLOCK }); mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&LLFloaterIMSession::checkGearMenuItem, this, _2)); setDocked(true); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index dc64d09f9f..b7f6fe76fb 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -82,7 +82,7 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) mSession = LLIMModel::getInstance()->findIMSession(mSessionID); mCommitCallbackRegistrar.add("IMSession.Menu.Action", - boost::bind(&LLFloaterIMSessionTab::onIMSessionMenuItemClicked, this, _2)); + { boost::bind(&LLFloaterIMSessionTab::onIMSessionMenuItemClicked, this, _2) }); mEnableCallbackRegistrar.add("IMSession.Menu.CompactExpandedModes.CheckItem", boost::bind(&LLFloaterIMSessionTab::onIMCompactExpandedMenuItemCheck, this, _2)); mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.CheckItem", @@ -93,8 +93,8 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) // Right click menu handling mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMSessionTab::checkContextMenuItem, this, _2)); mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2)); - mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing)); + mCommitCallbackRegistrar.add("Avatar.DoToSelected", { boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2) }); + mCommitCallbackRegistrar.add("Group.DoToSelected", { boost::bind(&cb_group_do_nothing) }); mMinFloaterHeight = getMinHeight(); } diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 7190bccb81..79f62aae80 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -51,9 +51,9 @@ LLFloaterInspect::LLFloaterInspect(const LLSD& key) mOwnerNameCacheConnection(), mCreatorNameCacheConnection() { - mCommitCallbackRegistrar.add("Inspect.OwnerProfile", boost::bind(&LLFloaterInspect::onClickOwnerProfile, this)); - mCommitCallbackRegistrar.add("Inspect.CreatorProfile", boost::bind(&LLFloaterInspect::onClickCreatorProfile, this)); - mCommitCallbackRegistrar.add("Inspect.SelectObject", boost::bind(&LLFloaterInspect::onSelectObject, this)); + mCommitCallbackRegistrar.add("Inspect.OwnerProfile", { boost::bind(&LLFloaterInspect::onClickOwnerProfile, this) }); + mCommitCallbackRegistrar.add("Inspect.CreatorProfile", { boost::bind(&LLFloaterInspect::onClickCreatorProfile, this) }); + mCommitCallbackRegistrar.add("Inspect.SelectObject", { boost::bind(&LLFloaterInspect::onSelectObject, this) }); } BOOL LLFloaterInspect::postBuild() diff --git a/indra/newview/llfloaterlagmeter.cpp b/indra/newview/llfloaterlagmeter.cpp index 3d4d0e55d4..67c5733fb5 100644 --- a/indra/newview/llfloaterlagmeter.cpp +++ b/indra/newview/llfloaterlagmeter.cpp @@ -47,7 +47,7 @@ const std::string LAG_GOOD_IMAGE_NAME = "lag_status_good.tga"; LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("LagMeter.ClickShrink", boost::bind(&LLFloaterLagMeter::onClickShrink, this)); + mCommitCallbackRegistrar.add("LagMeter.ClickShrink", { boost::bind(&LLFloaterLagMeter::onClickShrink, this) }); } BOOL LLFloaterLagMeter::postBuild() diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 39d5816b0d..189ee0c9d1 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -41,22 +41,22 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) mUpdateTimer(new LLTimer()), mContextMenuHandle() { - mCommitCallbackRegistrar.add("Script.OpenFolder", [this](LLUICtrl*, const LLSD &userdata) + mCommitCallbackRegistrar.add("Script.OpenFolder", {[this](LLUICtrl*, const LLSD &userdata) { if (mScriptList->hasSelectedItem()) { std::string target_folder_path = std::filesystem::path((mScriptList->getFirstSelected()->getColumn(1)->getValue().asString())).parent_path().string(); gViewerWindow->getWindow()->openFolder(target_folder_path); } - }); - mCommitCallbackRegistrar.add("Script.Terminate", [this](LLUICtrl*, const LLSD &userdata) + }, cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Script.Terminate", {[this](LLUICtrl*, const LLSD &userdata) { if (mScriptList->hasSelectedItem()) { std::string coro_name = mScriptList->getSelectedValue(); LLCoros::instance().killreq(coro_name); } - }); + }, cb_info::UNTRUSTED_BLOCK }); } diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 266648bc54..f8cb96ecc2 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -58,7 +58,7 @@ LLPanelMarketplaceListings::LLPanelMarketplaceListings() , mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME) , mFilterListingFoldersOnly(false) { - mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", { boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2) }); mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemCheck, this, _2)); } diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp index fda9eeca51..6c72064e15 100644 --- a/indra/newview/llfloatermemleak.cpp +++ b/indra/newview/llfloatermemleak.cpp @@ -48,12 +48,12 @@ LLFloaterMemLeak::LLFloaterMemLeak(const LLSD& key) : LLFloater(key) { setTitle("Memory Leaking Simulation Floater"); - mCommitCallbackRegistrar.add("MemLeak.ChangeLeakingSpeed", boost::bind(&LLFloaterMemLeak::onChangeLeakingSpeed, this)); - mCommitCallbackRegistrar.add("MemLeak.ChangeMaxMemLeaking", boost::bind(&LLFloaterMemLeak::onChangeMaxMemLeaking, this)); - mCommitCallbackRegistrar.add("MemLeak.Start", boost::bind(&LLFloaterMemLeak::onClickStart, this)); - mCommitCallbackRegistrar.add("MemLeak.Stop", boost::bind(&LLFloaterMemLeak::onClickStop, this)); - mCommitCallbackRegistrar.add("MemLeak.Release", boost::bind(&LLFloaterMemLeak::onClickRelease, this)); - mCommitCallbackRegistrar.add("MemLeak.Close", boost::bind(&LLFloaterMemLeak::onClickClose, this)); + mCommitCallbackRegistrar.add("MemLeak.ChangeLeakingSpeed", { boost::bind(&LLFloaterMemLeak::onChangeLeakingSpeed, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("MemLeak.ChangeMaxMemLeaking", { boost::bind(&LLFloaterMemLeak::onChangeMaxMemLeaking, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("MemLeak.Start", { boost::bind(&LLFloaterMemLeak::onClickStart, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("MemLeak.Stop", { boost::bind(&LLFloaterMemLeak::onClickStop, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("MemLeak.Release", { boost::bind(&LLFloaterMemLeak::onClickRelease, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("MemLeak.Close", { boost::bind(&LLFloaterMemLeak::onClickClose, this), cb_info::UNTRUSTED_BLOCK }); } //---------------------------------------------- diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 408eac6289..a4bf65d578 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -55,8 +55,8 @@ LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key) mPanelInventoryObject(NULL), mDirty(TRUE) { - mCommitCallbackRegistrar.add("OpenObject.MoveToInventory", boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this)); - mCommitCallbackRegistrar.add("OpenObject.Cancel", boost::bind(&LLFloaterOpenObject::onClickCancel, this)); + mCommitCallbackRegistrar.add("OpenObject.MoveToInventory", { boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("OpenObject.Cancel", { boost::bind(&LLFloaterOpenObject::onClickCancel, this) }); } LLFloaterOpenObject::~LLFloaterOpenObject() diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 97ae97dafc..34be99dcf7 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -67,7 +67,7 @@ protected: { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - registrar.add("Settings.SetRendering", boost::bind(&LLFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front())); + registrar.add("Settings.SetRendering", { boost::bind(&LLFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front()), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterPerformance::isActionChecked, mFloaterPerformance, _2, mUUIDs.front())); LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml"); diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 15ca87c326..265fd31da3 100644 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -107,9 +107,9 @@ static bool mCapSent = false; LLFloaterPermsDefault::LLFloaterPermsDefault(const LLSD& seed) : LLFloater(seed) { - mCommitCallbackRegistrar.add("PermsDefault.Copy", boost::bind(&LLFloaterPermsDefault::onCommitCopy, this, _2)); - mCommitCallbackRegistrar.add("PermsDefault.OK", boost::bind(&LLFloaterPermsDefault::onClickOK, this)); - mCommitCallbackRegistrar.add("PermsDefault.Cancel", boost::bind(&LLFloaterPermsDefault::onClickCancel, this)); + mCommitCallbackRegistrar.add("PermsDefault.Copy", { boost::bind(&LLFloaterPermsDefault::onCommitCopy, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("PermsDefault.OK", { boost::bind(&LLFloaterPermsDefault::onClickOK, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("PermsDefault.Cancel", { boost::bind(&LLFloaterPermsDefault::onClickCancel, this), cb_info::UNTRUSTED_BLOCK }); } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index d731f1c592..5ea455cff1 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -312,43 +312,43 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) registered_dialog = true; } - mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this, _2)); - mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this, _2)); - - mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); - mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); - mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); - mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); - mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); - mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); - mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); - mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); - mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); - mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); - mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); - mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); - mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); - mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); - mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreference::onRenderOptionEnable, this)); - mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); - mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this)); - mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); - mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); - mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); - mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); - mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); - mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); - mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); - mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); - mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); - mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); + mCommitCallbackRegistrar.add("Pref.Cancel", { boost::bind(&LLFloaterPreference::onBtnCancel, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.OK", { boost::bind(&LLFloaterPreference::onBtnOK, this, _2), cb_info::UNTRUSTED_BLOCK }); + + mCommitCallbackRegistrar.add("Pref.ClearCache", { boost::bind(&LLFloaterPreference::onClickClearCache, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.WebClearCache", { boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.SetCache", { boost::bind(&LLFloaterPreference::onClickSetCache, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.ResetCache", { boost::bind(&LLFloaterPreference::onClickResetCache, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.ClickSkin", { boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.SelectSkin", { boost::bind(&LLFloaterPreference::onSelectSkin, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.SetSounds", { boost::bind(&LLFloaterPreference::onClickSetSounds, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", { boost::bind(&LLFloaterPreference::onClickEnablePopup, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", { boost::bind(&LLFloaterPreference::onClickDisablePopup, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.LogPath", { boost::bind(&LLFloaterPreference::onClickLogPath, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.RenderExceptions", { boost::bind(&LLFloaterPreference::onClickRenderExceptions, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.AutoAdjustments", { boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.HardwareDefaults", { boost::bind(&LLFloaterPreference::setHardwareDefaults, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", { boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", { boost::bind(&LLFloaterPreference::updateMaxComplexity, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", { boost::bind(&LLFloaterPreference::onRenderOptionEnable, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.WindowedMod", { boost::bind(&LLFloaterPreference::onCommitWindowedMode, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.UpdateSliderText", { boost::bind(&LLFloaterPreference::refreshUI,this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.QualityPerformance", { boost::bind(&LLFloaterPreference::onChangeQuality, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.applyUIColor", { boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.getUIColor", { boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.MaturitySettings", { boost::bind(&LLFloaterPreference::onChangeMaturity, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.BlockList", { boost::bind(&LLFloaterPreference::onClickBlockList, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.Proxy", { boost::bind(&LLFloaterPreference::onClickProxySettings, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.TranslationSettings", { boost::bind(&LLFloaterPreference::onClickTranslationSettings, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.AutoReplace", { boost::bind(&LLFloaterPreference::onClickAutoReplace, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.PermsDefault", { boost::bind(&LLFloaterPreference::onClickPermsDefault, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", { boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.SpellChecker", { boost::bind(&LLFloaterPreference::onClickSpellChecker, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.Advanced", { boost::bind(&LLFloaterPreference::onClickAdvanced, this), cb_info::UNTRUSTED_BLOCK }); sSkin = gSavedSettings.getString("SkinCurrent"); - mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); + mCommitCallbackRegistrar.add("Pref.ClickActionChange", { boost::bind(&LLFloaterPreference::onClickActionChange, this), cb_info::UNTRUSTED_BLOCK }); gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); @@ -361,9 +361,9 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); - mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); - mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); - mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering + mCommitCallbackRegistrar.add("Pref.ClearLog", { boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance()), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", { boost::bind(&LLFloaterPreference::onDeleteTranscripts, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("UpdateFilter", { boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false), cb_info::UNTRUSTED_BLOCK }); // <FS:ND/> Hook up for filtering } void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type ) @@ -1976,11 +1976,11 @@ LLPanelPreference::LLPanelPreference() : LLPanel(), mBandWidthUpdater(NULL) { - mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2)); - mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1)); - mCommitCallbackRegistrar.add("Pref.PrefDelete", boost::bind(&LLPanelPreference::deletePreset, this, _2)); - mCommitCallbackRegistrar.add("Pref.PrefSave", boost::bind(&LLPanelPreference::savePreset, this, _2)); - mCommitCallbackRegistrar.add("Pref.PrefLoad", boost::bind(&LLPanelPreference::loadPreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.setControlFalse", { boost::bind(&LLPanelPreference::setControlFalse,this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", { boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.PrefDelete", { boost::bind(&LLPanelPreference::deletePreset, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.PrefSave", { boost::bind(&LLPanelPreference::savePreset, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.PrefLoad", { boost::bind(&LLPanelPreference::loadPreset, this, _2), cb_info::UNTRUSTED_BLOCK }); } //virtual @@ -3075,9 +3075,9 @@ LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) : LLFloater(key), mSocksSettingsDirty(false) { - mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); - mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); - mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); + mCommitCallbackRegistrar.add("Proxy.OK", { boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Proxy.Cancel", { boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Proxy.Change", { boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this), cb_info::UNTRUSTED_BLOCK }); } LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp index 709963b924..e95cff9d42 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -45,12 +45,12 @@ LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); + mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this) }); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this) }); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this) }); - mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2)); - mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2)); + mCommitCallbackRegistrar.add("Pref.Cancel", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Pref.OK", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2), cb_info::UNTRUSTED_BLOCK }); gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors, this, _2)); } diff --git a/indra/newview/llfloaterpreferenceviewadvanced.cpp b/indra/newview/llfloaterpreferenceviewadvanced.cpp index 3481397daa..290742a4cd 100644 --- a/indra/newview/llfloaterpreferenceviewadvanced.cpp +++ b/indra/newview/llfloaterpreferenceviewadvanced.cpp @@ -37,7 +37,7 @@ LLFloaterPreferenceViewAdvanced::LLFloaterPreferenceViewAdvanced(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this)); + mCommitCallbackRegistrar.add("CommitSettings", { boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this), cb_info::UNTRUSTED_BLOCK }); } LLFloaterPreferenceViewAdvanced::~LLFloaterPreferenceViewAdvanced() diff --git a/indra/newview/llfloaterscriptedprefs.cpp b/indra/newview/llfloaterscriptedprefs.cpp index 89c5d3617c..0f19f88d8e 100644 --- a/indra/newview/llfloaterscriptedprefs.cpp +++ b/indra/newview/llfloaterscriptedprefs.cpp @@ -36,8 +36,8 @@ LLFloaterScriptEdPrefs::LLFloaterScriptEdPrefs(const LLSD& key) : LLFloater(key) , mEditor(NULL) { - mCommitCallbackRegistrar.add("ScriptPref.applyUIColor", boost::bind(&LLFloaterScriptEdPrefs::applyUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("ScriptPref.getUIColor", boost::bind(&LLFloaterScriptEdPrefs::getUIColor, this ,_1, _2)); + mCommitCallbackRegistrar.add("ScriptPref.applyUIColor", { boost::bind(&LLFloaterScriptEdPrefs::applyUIColor, this ,_1, _2) }); + mCommitCallbackRegistrar.add("ScriptPref.getUIColor", { boost::bind(&LLFloaterScriptEdPrefs::getUIColor, this ,_1, _2) }); } BOOL LLFloaterScriptEdPrefs::postBuild() diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 751990b3b6..1c10db4e0d 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -41,8 +41,8 @@ LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) : LLFloater(key), mSettingList(NULL) { - mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); - mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); + mCommitCallbackRegistrar.add("CommitSettings", { boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("ClickDefault", { boost::bind(&LLFloaterSettingsDebug::onClickDefault, this), cb_info::UNTRUSTED_BLOCK }); } LLFloaterSettingsDebug::~LLFloaterSettingsDebug() diff --git a/indra/newview/llfloatertestinspectors.cpp b/indra/newview/llfloatertestinspectors.cpp index f6f4324e71..90a825ed5c 100644 --- a/indra/newview/llfloatertestinspectors.cpp +++ b/indra/newview/llfloatertestinspectors.cpp @@ -37,9 +37,9 @@ LLFloaterTestInspectors::LLFloaterTestInspectors(const LLSD& seed) : LLFloater(seed) { mCommitCallbackRegistrar.add("ShowAvatarInspector", - boost::bind(&LLFloaterTestInspectors::showAvatarInspector, this, _1, _2)); + { boost::bind(&LLFloaterTestInspectors::showAvatarInspector, this, _1, _2) }); mCommitCallbackRegistrar.add("ShowObjectInspector", - boost::bind(&LLFloaterTestInspectors::showObjectInspector, this, _1, _2)); + { boost::bind(&LLFloaterTestInspectors::showObjectInspector, this, _1, _2) }); } LLFloaterTestInspectors::~LLFloaterTestInspectors() diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index ccecdd89f0..f42cc2e3d8 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -378,21 +378,21 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) mFactoryMap["Contents"] = LLCallbackMap(createPanelContents, this);//LLPanelContents mFactoryMap["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo - mCommitCallbackRegistrar.add("BuildTool.setTool", boost::bind(&LLFloaterTools::setTool,this, _2)); - mCommitCallbackRegistrar.add("BuildTool.commitZoom", boost::bind(&commit_slider_zoom, _1)); - mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", boost::bind(&commit_radio_group_focus, _1)); - mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", boost::bind(&commit_radio_group_move,_1)); - mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", boost::bind(&commit_radio_group_edit,_1)); - - mCommitCallbackRegistrar.add("BuildTool.gridMode", boost::bind(&commit_grid_mode,_1)); - mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&commit_select_component, this)); - mCommitCallbackRegistrar.add("BuildTool.gridOptions", boost::bind(&LLFloaterTools::onClickGridOptions,this)); - mCommitCallbackRegistrar.add("BuildTool.applyToSelection", boost::bind(&click_apply_to_selection, this)); - mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", boost::bind(&commit_radio_group_land,_1)); - mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", boost::bind(&commit_slider_dozer_force,_1)); - - mCommitCallbackRegistrar.add("BuildTool.LinkObjects", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance())); - mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); + mCommitCallbackRegistrar.add("BuildTool.setTool", { boost::bind(&LLFloaterTools::setTool,this, _2) }); + mCommitCallbackRegistrar.add("BuildTool.commitZoom", { boost::bind(&commit_slider_zoom, _1), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", { boost::bind(&commit_radio_group_focus, _1), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", { boost::bind(&commit_radio_group_move,_1), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", { boost::bind(&commit_radio_group_edit,_1), cb_info::UNTRUSTED_BLOCK }); + + mCommitCallbackRegistrar.add("BuildTool.gridMode", { boost::bind(&commit_grid_mode,_1), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.selectComponent", { boost::bind(&commit_select_component, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.gridOptions", { boost::bind(&LLFloaterTools::onClickGridOptions,this) }); + mCommitCallbackRegistrar.add("BuildTool.applyToSelection", { boost::bind(&click_apply_to_selection, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", { boost::bind(&commit_radio_group_land,_1), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", { boost::bind(&commit_slider_dozer_force,_1), cb_info::UNTRUSTED_BLOCK }); + + mCommitCallbackRegistrar.add("BuildTool.LinkObjects", { boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()) }); + mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects", { boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()) }); mLandImpactsObserver = new LLLandImpactsObserver(); LLViewerParcelMgr::getInstance()->addObserver(mLandImpactsObserver); diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index c630daa836..c31bab241d 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -76,16 +76,16 @@ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key) mInitialized(FALSE), mtotalScore(0.f) { - mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this)); - mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", boost::bind(&LLFloaterTopObjects::onReturnSelected, this)); - mCommitCallbackRegistrar.add("TopObjects.ReturnAll", boost::bind(&LLFloaterTopObjects::onReturnAll, this)); - mCommitCallbackRegistrar.add("TopObjects.Refresh", boost::bind(&LLFloaterTopObjects::onRefresh, this)); - mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", boost::bind(&LLFloaterTopObjects::onGetByObjectName, this)); - mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this)); - mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", boost::bind(&LLFloaterTopObjects::onGetByParcelName, this)); - mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this)); - - mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this)); + mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", { boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this) }); + mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", { boost::bind(&LLFloaterTopObjects::onReturnSelected, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("TopObjects.ReturnAll", { boost::bind(&LLFloaterTopObjects::onReturnAll, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("TopObjects.Refresh", { boost::bind(&LLFloaterTopObjects::onRefresh, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", { boost::bind(&LLFloaterTopObjects::onGetByObjectName, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", { boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", { boost::bind(&LLFloaterTopObjects::onGetByParcelName, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",{ boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this), cb_info::UNTRUSTED_THROTTLE }); + + mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", { boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this), cb_info::UNTRUSTED_THROTTLE }); } LLFloaterTopObjects::~LLFloaterTopObjects() diff --git a/indra/newview/llfloatertoybox.cpp b/indra/newview/llfloatertoybox.cpp index 635d1e2bc4..260badaf63 100644 --- a/indra/newview/llfloatertoybox.cpp +++ b/indra/newview/llfloatertoybox.cpp @@ -41,8 +41,8 @@ LLFloaterToybox::LLFloaterToybox(const LLSD& key) : LLFloater(key) , mToolBar(NULL) { - mCommitCallbackRegistrar.add("Toybox.RestoreDefaults", boost::bind(&LLFloaterToybox::onBtnRestoreDefaults, this)); - mCommitCallbackRegistrar.add("Toybox.ClearAll", boost::bind(&LLFloaterToybox::onBtnClearAll, this)); + mCommitCallbackRegistrar.add("Toybox.RestoreDefaults", { boost::bind(&LLFloaterToybox::onBtnRestoreDefaults, this) }); + mCommitCallbackRegistrar.add("Toybox.ClearAll", { boost::bind(&LLFloaterToybox::onBtnClearAll, this) }); } LLFloaterToybox::~LLFloaterToybox() diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp index 4bde73c7ec..f58eb46ffe 100644 --- a/indra/newview/llfloatervoiceeffect.cpp +++ b/indra/newview/llfloatervoiceeffect.cpp @@ -36,9 +36,9 @@ LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this)); - mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this)); - mCommitCallbackRegistrar.add("VoiceEffect.Stop", boost::bind(&LLFloaterVoiceEffect::onClickStop, this)); + mCommitCallbackRegistrar.add("VoiceEffect.Record", { boost::bind(&LLFloaterVoiceEffect::onClickRecord, this) }); + mCommitCallbackRegistrar.add("VoiceEffect.Play", { boost::bind(&LLFloaterVoiceEffect::onClickPlay, this) }); + mCommitCallbackRegistrar.add("VoiceEffect.Stop", { boost::bind(&LLFloaterVoiceEffect::onClickStop, this) }); // mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this)); } diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 71f1181566..6319ddccdf 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -75,13 +75,13 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params ) mDisplayURL(""), mDevelopMode(params.dev_mode) // if called from "Develop" Menu, set a flag and change things to be more useful for devs { - mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this )); - mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this )); - mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this )); - mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this )); - mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this )); - mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind(&LLFloaterWebContent::onPopExternal, this)); - mCommitCallbackRegistrar.add( "WebContent.TestURL", boost::bind(&LLFloaterWebContent::onTestURL, this, _2)); + mCommitCallbackRegistrar.add( "WebContent.Back", { boost::bind( &LLFloaterWebContent::onClickBack, this ), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add( "WebContent.Forward", { boost::bind( &LLFloaterWebContent::onClickForward, this ), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add( "WebContent.Reload", { boost::bind( &LLFloaterWebContent::onClickReload, this ), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add( "WebContent.Stop", { boost::bind( &LLFloaterWebContent::onClickStop, this ), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add( "WebContent.EnterAddress", { boost::bind( &LLFloaterWebContent::onEnterAddress, this ), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add( "WebContent.PopExternal", { boost::bind(&LLFloaterWebContent::onPopExternal, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add( "WebContent.TestURL", { boost::bind(&LLFloaterWebContent::onTestURL, this, _2), cb_info::UNTRUSTED_BLOCK }); } BOOL LLFloaterWebContent::postBuild() diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index bb4ae7e8ab..b8900bef8b 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -291,17 +291,17 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key) mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL); - mCommitCallbackRegistrar.add("WMap.Coordinates", boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this)); - mCommitCallbackRegistrar.add("WMap.Location", boost::bind(&LLFloaterWorldMap::onLocationCommit, this)); - mCommitCallbackRegistrar.add("WMap.AvatarCombo", boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this)); - mCommitCallbackRegistrar.add("WMap.Landmark", boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this)); - mCommitCallbackRegistrar.add("WMap.SearchResult", boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this)); - mCommitCallbackRegistrar.add("WMap.GoHome", boost::bind(&LLFloaterWorldMap::onGoHome, this)); - mCommitCallbackRegistrar.add("WMap.Teleport", boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); - mCommitCallbackRegistrar.add("WMap.ShowTarget", boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this)); - mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this)); - mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this)); - mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this)); + mCommitCallbackRegistrar.add("WMap.Coordinates", { boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this) }); + mCommitCallbackRegistrar.add("WMap.Location", { boost::bind(&LLFloaterWorldMap::onLocationCommit, this) }); + mCommitCallbackRegistrar.add("WMap.AvatarCombo", { boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this) }); + mCommitCallbackRegistrar.add("WMap.Landmark", { boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this) }); + mCommitCallbackRegistrar.add("WMap.SearchResult", { boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this) }); + mCommitCallbackRegistrar.add("WMap.GoHome", { boost::bind(&LLFloaterWorldMap::onGoHome, this) }); + mCommitCallbackRegistrar.add("WMap.Teleport", { boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this) }); + mCommitCallbackRegistrar.add("WMap.ShowTarget", { boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this) }); + mCommitCallbackRegistrar.add("WMap.ShowAgent", { boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this) }); + mCommitCallbackRegistrar.add("WMap.Clear", { boost::bind(&LLFloaterWorldMap::onClearBtn, this) }); + mCommitCallbackRegistrar.add("WMap.CopySLURL", { boost::bind(&LLFloaterWorldMap::onCopySLURL, this) }); gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this)); } diff --git a/indra/newview/llflyoutcombobtn.cpp b/indra/newview/llflyoutcombobtn.cpp index 728f60e1c0..97cd637da1 100644 --- a/indra/newview/llflyoutcombobtn.cpp +++ b/indra/newview/llflyoutcombobtn.cpp @@ -41,7 +41,7 @@ LLFlyoutComboBtnCtrl::LLFlyoutComboBtnCtrl(LLPanel* parent, { // register action mapping before creating menu LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar; - save_registar.add("FlyoutCombo.Button.Action", [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutItemSelected(ctrl, data); }); + save_registar.add("FlyoutCombo.Button.Action", { [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutItemSelected(ctrl, data); } }); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enabled_rgistar; enabled_rgistar.add("FlyoutCombo.Button.Check", [this](LLUICtrl *ctrl, const LLSD &data) { return onFlyoutItemCheck(ctrl, data); }); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 38b2f4adc8..0f4ff2aac8 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -141,7 +141,7 @@ void LLGroupList::enableForAgent(bool show_icons) gAgent.addListener(this, "new group"); // Set up context menu. - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; registrar.add("People.Groups.Action", boost::bind(&LLGroupList::onContextMenuItemClick, this, _2)); diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index db48061c56..c39380105b 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -97,11 +97,11 @@ LLInspectGroup::LLInspectGroup(const LLSD& sd) mGroupID() // set in onOpen() { mCommitCallbackRegistrar.add("InspectGroup.ViewProfile", - boost::bind(&LLInspectGroup::onClickViewProfile, this)); + { boost::bind(&LLInspectGroup::onClickViewProfile, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("InspectGroup.Join", - boost::bind(&LLInspectGroup::onClickJoin, this)); + { boost::bind(&LLInspectGroup::onClickJoin, this), cb_info::UNTRUSTED_THROTTLE }); mCommitCallbackRegistrar.add("InspectGroup.Leave", - boost::bind(&LLInspectGroup::onClickLeave, this)); + { boost::bind(&LLInspectGroup::onClickLeave, this), cb_info::UNTRUSTED_BLOCK }); // can't make the properties request until the widgets are constructed // as it might return immediately, so do it in postBuild. diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index eccc359a3a..94261615de 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -129,14 +129,14 @@ LLInspectObject::LLInspectObject(const LLSD& sd) { // can't make the properties request until the widgets are constructed // as it might return immediately, so do it in postBuild. - mCommitCallbackRegistrar.add("InspectObject.Buy", boost::bind(&LLInspectObject::onClickBuy, this)); - mCommitCallbackRegistrar.add("InspectObject.Pay", boost::bind(&LLInspectObject::onClickPay, this)); - mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", boost::bind(&LLInspectObject::onClickTakeFreeCopy, this)); - mCommitCallbackRegistrar.add("InspectObject.Touch", boost::bind(&LLInspectObject::onClickTouch, this)); - mCommitCallbackRegistrar.add("InspectObject.Sit", boost::bind(&LLInspectObject::onClickSit, this)); - mCommitCallbackRegistrar.add("InspectObject.Open", boost::bind(&LLInspectObject::onClickOpen, this)); - mCommitCallbackRegistrar.add("InspectObject.MoreInfo", boost::bind(&LLInspectObject::onClickMoreInfo, this)); - mCommitCallbackRegistrar.add("InspectObject.ZoomIn", boost::bind(&LLInspectObject::onClickZoomIn, this)); + mCommitCallbackRegistrar.add("InspectObject.Buy", {boost::bind(&LLInspectObject::onClickBuy, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("InspectObject.Pay", {boost::bind(&LLInspectObject::onClickPay, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", {boost::bind(&LLInspectObject::onClickTakeFreeCopy, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("InspectObject.Touch", {boost::bind(&LLInspectObject::onClickTouch, this), cb_info::UNTRUSTED_BLOCK}); + mCommitCallbackRegistrar.add("InspectObject.Sit", {boost::bind(&LLInspectObject::onClickSit, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("InspectObject.Open", {boost::bind(&LLInspectObject::onClickOpen, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("InspectObject.MoreInfo", {boost::bind(&LLInspectObject::onClickMoreInfo, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("InspectObject.ZoomIn", {boost::bind(&LLInspectObject::onClickZoomIn, this), cb_info::UNTRUSTED_BLOCK}); } diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 4b47346473..fb7baefe5b 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -50,16 +50,18 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2)); - registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2)); - registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); - registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); + registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Inventory.EmptyTrash", + boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Inventory.EmptyLostAndFound", + boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK); std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end()); - registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery))); + registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)), LLUICtrl::cb_info::UNTRUSTED_BLOCK); enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2)); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 4ac43ea6b2..67efe01720 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -177,15 +177,15 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : } // context menu callbacks - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); - mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); - mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); - mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this)); - mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2)); - mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID())); + mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLInventoryPanel::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&LLInventoryPanel::doCreate, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.AttachObject", { boost::bind(&LLInventoryPanel::attachObject, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", { boost::bind(&LLInventoryPanel::beginIMSession, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.Share", { boost::bind(&LLAvatarActions::shareWithAvatars, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", { boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", { boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()), LLUICtrl::cb_info::UNTRUSTED_THROTTLE }); } LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id ) @@ -2204,9 +2204,9 @@ LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params) getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches"); getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty"); - mCommitCallbackRegistrar.replace("Inventory.DoToSelected", boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2)); - mCommitCallbackRegistrar.replace("Inventory.DoCreate", boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2)); - mCommitCallbackRegistrar.replace("Inventory.Share", boost::bind(&LLInventorySingleFolderPanel::doShare, this)); + mCommitCallbackRegistrar.replace("Inventory.DoToSelected", { boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.replace("Inventory.DoCreate", { boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.replace("Inventory.Share", { boost::bind(&LLInventorySingleFolderPanel::doShare, this), cb_info::UNTRUSTED_BLOCK }); } LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel() diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 67ad63b7fb..c75bbec1d7 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -377,7 +377,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) addChild(mParcelIcon[SEE_AVATARS_ICON]); // Register callbacks and load the location field context menu (NB: the order matters). - LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add("Navbar.Action", LLUICtrl::CommitCallbackInfo(boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2))); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", LLUICtrl::CommitCallbackInfo(boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2))); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2)); setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 72783408b8..3c09ad162a 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -345,8 +345,8 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask ) auto menu = mContextMenuHandle.get(); if (!menu) { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; - registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + LLUICtrl::ScopedRegistrarHelper registrar; + registrar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); // stinson 05/05/2014 : use this as the parent of the context menu if the static menu // container has yet to be created diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index d8ac641e56..d85426b41a 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -128,7 +128,7 @@ LLNetMap::~LLNetMap() BOOL LLNetMap::postBuild() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commitRegistrar; + LLUICtrl::ScopedRegistrarHelper commitRegistrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enableRegistrar; enableRegistrar.add("Minimap.Zoom.Check", boost::bind(&LLNetMap::isZoomChecked, this, _2)); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 0b127b1b93..b5e99c39c4 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1134,7 +1134,7 @@ void LLOutfitGalleryItem::setDefaultImage() LLContextMenu* LLOutfitGalleryContextMenu::createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; LLUUID selected_id = mUUIDs.front(); @@ -1146,8 +1146,8 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu() boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id)); registrar.add("Outfit.Edit", boost::bind(editOutfit)); registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); - registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id)); - registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2)); + registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id)); registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id)); enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2)); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 0870211a8e..becaa9953d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1053,7 +1053,7 @@ void LLOutfitListBase::deselectOutfit(const LLUUID& category_id) LLContextMenu* LLOutfitContextMenu::createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; LLUUID selected_id = mUUIDs.front(); @@ -1064,8 +1064,8 @@ LLContextMenu* LLOutfitContextMenu::createMenu() registrar.add("Outfit.TakeOff", boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id)); registrar.add("Outfit.Edit", boost::bind(editOutfit)); - registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); - registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); + registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id)); registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id)); @@ -1163,7 +1163,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist) { llassert_always(mOutfitList); - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenuBase::onWear, this)); diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp index 5cc567395c..527094b4b2 100644 --- a/indra/newview/llpanelblockedlist.cpp +++ b/indra/newview/llpanelblockedlist.cpp @@ -62,7 +62,7 @@ const std::string BLOCKED_PARAM_NAME = "blocked_to_select"; LLPanelBlockedList::LLPanelBlockedList() : LLPanel() { - mCommitCallbackRegistrar.add("Block.Action", boost::bind(&LLPanelBlockedList::onCustomAction, this, _2)); + mCommitCallbackRegistrar.add("Block.Action", { boost::bind(&LLPanelBlockedList::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK }); mEnableCallbackRegistrar.add("Block.Check", boost::bind(&LLPanelBlockedList::isActionChecked, this, _2)); } diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 9761c6ae10..261ab6f9cd 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -494,7 +494,7 @@ LLPanelFace::LLPanelFace() mNeedMediaTitle(true) { USE_TEXTURE = LLTrans::getString("use_texture"); - mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2)); + mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", { boost::bind(&LLPanelFace::menuDoToSelected, this, _2) }); mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2)); } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 5887e793e1..415f579ab4 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -124,14 +124,16 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p) mGalleryRootUpdatedConnection() { // Menu Callbacks (non contex menus) - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLPanelMainInventory::closeAllFolders, this)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2)); - mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this)); - mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this)); - mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2)); + mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLPanelMainInventory::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", { boost::bind(&LLPanelMainInventory::closeAllFolders, this) }); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, + "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, + "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&LLPanelMainInventory::doCreate, this, _2) }); + mCommitCallbackRegistrar.add("Inventory.ShowFilters", { boost::bind(&LLPanelMainInventory::toggleFindOptions, this) }); + mCommitCallbackRegistrar.add("Inventory.ResetFilters", { boost::bind(&LLPanelMainInventory::resetFilters, this) }); + mCommitCallbackRegistrar.add("Inventory.SetSortBy", { boost::bind(&LLPanelMainInventory::setSortBy, this, _2) }); mEnableCallbackRegistrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasSettingsInventory(); }); mEnableCallbackRegistrar.add("Inventory.MaterialsEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasMaterialsInventory(); }); @@ -1488,7 +1490,7 @@ void LLPanelMainInventory::initListCommandsHandlers() childSetAction("back_btn", boost::bind(&LLPanelMainInventory::onBackFolderClicked, this)); childSetAction("forward_btn", boost::bind(&LLPanelMainInventory::onForwardFolderClicked, this)); - mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2)); + mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", { boost::bind(&LLPanelMainInventory::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK }); mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2)); mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2)); mEnableCallbackRegistrar.add("Inventory.GearDefault.Visible", boost::bind(&LLPanelMainInventory::isActionVisible, this, _2)); diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp index 96ec1b17eb..c16be54f47 100644 --- a/indra/newview/llpanelmediasettingssecurity.cpp +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -49,8 +49,8 @@ LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() : mParent( NULL ) { - mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); - mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); + mCommitCallbackRegistrar.add("Media.whitelistAdd", { boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Media.whitelistDelete", { boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this), cb_info::UNTRUSTED_BLOCK }); // build dialog from XML buildFromFile( "panel_media_settings_security.xml"); diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index a46894988c..068a2333c4 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -85,17 +85,17 @@ LLPanelNearByMedia::LLPanelNearByMedia() gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); - mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", boost::bind(&LLPanelNearByMedia::onClickEnableAll, this)); - mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", boost::bind(&LLPanelNearByMedia::onClickDisableAll, this)); - mCommitCallbackRegistrar.add("MediaListCtrl.GoMediaPrefs", boost::bind(&LLPanelNearByMedia::onAdvancedButtonClick, this)); - mCommitCallbackRegistrar.add("MediaListCtrl.MoreLess", boost::bind(&LLPanelNearByMedia::onMoreLess, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Stop", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaStop, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Play", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPlay, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Pause", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPause, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Mute", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaMute, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Volume", boost::bind(&LLPanelNearByMedia::onCommitSelectedMediaVolume, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Zoom", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaZoom, this)); - mCommitCallbackRegistrar.add("SelectedMediaCtrl.Unzoom", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaUnzoom, this)); + mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", { boost::bind(&LLPanelNearByMedia::onClickEnableAll, this) }); + mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", { boost::bind(&LLPanelNearByMedia::onClickDisableAll, this) }); + mCommitCallbackRegistrar.add("MediaListCtrl.GoMediaPrefs", { boost::bind(&LLPanelNearByMedia::onAdvancedButtonClick, this) }); + mCommitCallbackRegistrar.add("MediaListCtrl.MoreLess", { boost::bind(&LLPanelNearByMedia::onMoreLess, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Stop", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaStop, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Play", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPlay, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Pause", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPause, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Mute", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaMute, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Volume", { boost::bind(&LLPanelNearByMedia::onCommitSelectedMediaVolume, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Zoom", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaZoom, this) }); + mCommitCallbackRegistrar.add("SelectedMediaCtrl.Unzoom", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaUnzoom, this) }); buildFromFile( "panel_nearby_media.xml"); } diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 9267604098..f20a05decd 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -296,7 +296,7 @@ LLPanelObject::LLPanelObject() mHasClipboardRot(false), mSizeChanged(FALSE) { - mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2)); + mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", { boost::bind(&LLPanelObject::menuDoToSelected, this, _2) }); mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2)); } diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 141a1515d5..97d876f778 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1346,14 +1346,16 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par mShowRootFolder(p.show_root_folder) { // Setup context menu callbacks - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&do_nothing)); - mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&do_nothing)); - mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&do_nothing)); - mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this)); - mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&do_nothing)); + mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLPanelObjectInventory::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", + { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", + { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&do_nothing) }); + mCommitCallbackRegistrar.add("Inventory.AttachObject", { boost::bind(&do_nothing) }); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", { boost::bind(&do_nothing) }); + mCommitCallbackRegistrar.add("Inventory.Share", { boost::bind(&LLAvatarActions::shareWithAvatars, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", { boost::bind(&do_nothing) }); } // Destroys the object diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 1bfae630a0..b1a70ecdba 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -157,7 +157,7 @@ public: { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("Wearable.Create", boost::bind(onCreate, _2)); + registrar.add("Wearable.Create", { boost::bind(onCreate, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); llassert(LLMenuGL::sMenuContainer != NULL); LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( @@ -226,7 +226,7 @@ public: LLHandle<LLView> flat_list_handle = flat_list->getHandle(); LLHandle<LLPanel> inventory_panel_handle = inventory_panel->getHandle(); - registrar.add("AddWearable.Gear.Sort", boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2)); + registrar.add("AddWearable.Gear.Sort", { boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2) }); enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2)); enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2)); diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 44e860837e..a8538709c6 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -548,18 +548,18 @@ LLPanelPeople::LLPanelPeople() mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this)); - mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); - mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); - mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Group.Minus", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Chat", boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Gear", boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1)); - - mCommitCallbackRegistrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.AddFriend", { boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this) }); + mCommitCallbackRegistrar.add("People.AddFriendWizard", { boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this) }); + mCommitCallbackRegistrar.add("People.DelFriend", { boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("People.Group.Minus", { boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("People.Chat", { boost::bind(&LLPanelPeople::onChatButtonClicked, this) }); + mCommitCallbackRegistrar.add("People.Gear", { boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1) }); + + mCommitCallbackRegistrar.add("People.Group.Plus.Action", { boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", { boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2) }); + mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", { boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2) }); + mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", { boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2) }); + mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", { boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2) }); mEnableCallbackRegistrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2)); mEnableCallbackRegistrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2)); diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 172c7d0828..7c469401c4 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -58,7 +58,7 @@ NearbyPeopleContextMenu gNearbyPeopleContextMenu; LLContextMenu* PeopleContextMenu::createMenu() { // set up the callbacks for all of the avatar menu items - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; LLContextMenu* menu; @@ -68,21 +68,21 @@ LLContextMenu* PeopleContextMenu::createMenu() const LLUUID& id = mUUIDs.front(); registrar.add("Avatar.Profile", boost::bind(&LLAvatarActions::showProfile, id)); - registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, id)); - registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id)); + registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, id), LLUICtrl::cb_info::UNTRUSTED_THROTTLE); + registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startIM, id)); - registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id)); - registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this)); + registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Avatar.ZoomIn", boost::bind(&handle_zoom_to_object, id)); registrar.add("Avatar.ShowOnMap", boost::bind(&LLAvatarActions::showOnMap, id)); - registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id)); - registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id)); + registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); + registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id)); - registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id)); + registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Avatar.TeleportRequest", boost::bind(&PeopleContextMenu::requestTeleport, this)); - registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id)); - registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::freezeAvatar, id)); - registrar.add("Avatar.Eject", boost::bind(&PeopleContextMenu::eject, this)); + registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id), LLUICtrl::cb_info::UNTRUSTED_THROTTLE); + registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::freezeAvatar, id), LLUICtrl::cb_info::UNTRUSTED_THROTTLE); + registrar.add("Avatar.Eject", boost::bind(&PeopleContextMenu::eject, this), LLUICtrl::cb_info::UNTRUSTED_THROTTLE); enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2)); diff --git a/indra/newview/llpanelpresetscamerapulldown.cpp b/indra/newview/llpanelpresetscamerapulldown.cpp index 124a38bebb..fe54c3b8c1 100644 --- a/indra/newview/llpanelpresetscamerapulldown.cpp +++ b/indra/newview/llpanelpresetscamerapulldown.cpp @@ -48,8 +48,8 @@ // Default constructor LLPanelPresetsCameraPulldown::LLPanelPresetsCameraPulldown() { - mCommitCallbackRegistrar.add("Presets.toggleCameraFloater", boost::bind(&LLPanelPresetsCameraPulldown::onViewButtonClick, this, _2)); - mCommitCallbackRegistrar.add("PresetsCamera.RowClick", boost::bind(&LLPanelPresetsCameraPulldown::onRowClick, this, _2)); + mCommitCallbackRegistrar.add("Presets.toggleCameraFloater", { boost::bind(&LLPanelPresetsCameraPulldown::onViewButtonClick, this, _2) }); + mCommitCallbackRegistrar.add("PresetsCamera.RowClick", { boost::bind(&LLPanelPresetsCameraPulldown::onRowClick, this, _2) }); buildFromFile( "panel_presets_camera_pulldown.xml"); } diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp index 61331aad95..433b6c033b 100644 --- a/indra/newview/llpanelpresetspulldown.cpp +++ b/indra/newview/llpanelpresetspulldown.cpp @@ -50,9 +50,9 @@ LLPanelPresetsPulldown::LLPanelPresetsPulldown() { mHoverTimer.stop(); - mCommitCallbackRegistrar.add("Presets.GoGraphicsPrefs", boost::bind(&LLPanelPresetsPulldown::onGraphicsButtonClick, this, _2)); - mCommitCallbackRegistrar.add("Presets.GoAutofpsPrefs", boost::bind(&LLPanelPresetsPulldown::onAutofpsButtonClick, this, _2)); - mCommitCallbackRegistrar.add("Presets.RowClick", boost::bind(&LLPanelPresetsPulldown::onRowClick, this, _2)); + mCommitCallbackRegistrar.add("Presets.GoGraphicsPrefs", { boost::bind(&LLPanelPresetsPulldown::onGraphicsButtonClick, this, _2) }); + mCommitCallbackRegistrar.add("Presets.GoAutofpsPrefs", { boost::bind(&LLPanelPresetsPulldown::onAutofpsButtonClick, this, _2) }); + mCommitCallbackRegistrar.add("Presets.RowClick", { boost::bind(&LLPanelPresetsPulldown::onRowClick, this, _2) }); buildFromFile( "panel_presets_pulldown.xml"); } diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 16cf46529d..788b506ac9 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -102,28 +102,28 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() : mSecureURL(false), mMediaPlaySliderCtrlMouseDownValue(0.0) { - mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Forward", boost::bind(&LLPanelPrimMediaControls::onClickForward, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Home", boost::bind(&LLPanelPrimMediaControls::onClickHome, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Stop", boost::bind(&LLPanelPrimMediaControls::onClickStop, this)); - mCommitCallbackRegistrar.add("MediaCtrl.MediaStop", boost::bind(&LLPanelPrimMediaControls::onClickMediaStop, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Reload", boost::bind(&LLPanelPrimMediaControls::onClickReload, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Play", boost::bind(&LLPanelPrimMediaControls::onClickPlay, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Pause", boost::bind(&LLPanelPrimMediaControls::onClickPause, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Open", boost::bind(&LLPanelPrimMediaControls::onClickOpen, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Zoom", boost::bind(&LLPanelPrimMediaControls::onClickZoom, this)); - mCommitCallbackRegistrar.add("MediaCtrl.CommitURL", boost::bind(&LLPanelPrimMediaControls::onCommitURL, this)); - mCommitCallbackRegistrar.add("MediaCtrl.MouseDown", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown, this)); - mCommitCallbackRegistrar.add("MediaCtrl.MouseUp", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp, this)); - mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this)); - mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this)); - mCommitCallbackRegistrar.add("MediaCtrl.Volume", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this)); - mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute", boost::bind(&LLPanelPrimMediaControls::onToggleMute, this)); - mCommitCallbackRegistrar.add("MediaCtrl.ShowVolumeSlider", boost::bind(&LLPanelPrimMediaControls::showVolumeSlider, this)); - mCommitCallbackRegistrar.add("MediaCtrl.HideVolumeSlider", boost::bind(&LLPanelPrimMediaControls::hideVolumeSlider, this)); - mCommitCallbackRegistrar.add("MediaCtrl.SkipBack", boost::bind(&LLPanelPrimMediaControls::onClickSkipBack, this)); - mCommitCallbackRegistrar.add("MediaCtrl.SkipForward", boost::bind(&LLPanelPrimMediaControls::onClickSkipForward, this)); + mCommitCallbackRegistrar.add("MediaCtrl.Close", { boost::bind(&LLPanelPrimMediaControls::onClickClose, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Back", { boost::bind(&LLPanelPrimMediaControls::onClickBack, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Forward", { boost::bind(&LLPanelPrimMediaControls::onClickForward, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Home", { boost::bind(&LLPanelPrimMediaControls::onClickHome, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Stop", { boost::bind(&LLPanelPrimMediaControls::onClickStop, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.MediaStop", { boost::bind(&LLPanelPrimMediaControls::onClickMediaStop, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Reload", { boost::bind(&LLPanelPrimMediaControls::onClickReload, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Play", { boost::bind(&LLPanelPrimMediaControls::onClickPlay, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Pause", { boost::bind(&LLPanelPrimMediaControls::onClickPause, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Open", { boost::bind(&LLPanelPrimMediaControls::onClickOpen, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Zoom", { boost::bind(&LLPanelPrimMediaControls::onClickZoom, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.CommitURL", { boost::bind(&LLPanelPrimMediaControls::onCommitURL, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("MediaCtrl.MouseDown", { boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.MouseUp", { boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp", { boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", { boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.Volume", { boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute", { boost::bind(&LLPanelPrimMediaControls::onToggleMute, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.ShowVolumeSlider", { boost::bind(&LLPanelPrimMediaControls::showVolumeSlider, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.HideVolumeSlider", { boost::bind(&LLPanelPrimMediaControls::hideVolumeSlider, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.SkipBack", { boost::bind(&LLPanelPrimMediaControls::onClickSkipBack, this) }); + mCommitCallbackRegistrar.add("MediaCtrl.SkipForward", { boost::bind(&LLPanelPrimMediaControls::onClickSkipForward, this) }); buildFromFile( "panel_prim_media_controls.xml"); mInactivityTimer.reset(); diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 0f0af37485..4973932bc1 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -774,7 +774,7 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key) } // Init menu, menu needs to be created in scope of a registar to work correctly. - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit; + ScopedRegistrarHelper commit; commit.add("Profile.Commit", [this](LLUICtrl*, const LLSD& userdata) { onCommitMenu(userdata); }); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable; diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp index 3092ea3b18..4b21d5e977 100644 --- a/indra/newview/llpanelsnapshotinventory.cpp +++ b/indra/newview/llpanelsnapshotinventory.cpp @@ -119,8 +119,8 @@ LLSnapshotModel::ESnapshotType LLPanelSnapshotInventoryBase::getSnapshotType() LLPanelSnapshotInventory::LLPanelSnapshotInventory() { - mCommitCallbackRegistrar.add("Inventory.Save", boost::bind(&LLPanelSnapshotInventory::onSend, this)); - mCommitCallbackRegistrar.add("Inventory.Cancel", boost::bind(&LLPanelSnapshotInventory::cancel, this)); + mCommitCallbackRegistrar.add("Inventory.Save", { boost::bind(&LLPanelSnapshotInventory::onSend, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.Cancel", { boost::bind(&LLPanelSnapshotInventory::cancel, this), cb_info::UNTRUSTED_BLOCK }); } // virtual @@ -178,8 +178,8 @@ void LLPanelSnapshotInventoryBase::onSend() LLPanelOutfitSnapshotInventory::LLPanelOutfitSnapshotInventory() { - mCommitCallbackRegistrar.add("Inventory.SaveOutfitPhoto", boost::bind(&LLPanelOutfitSnapshotInventory::onSend, this)); - mCommitCallbackRegistrar.add("Inventory.SaveOutfitCancel", boost::bind(&LLPanelOutfitSnapshotInventory::cancel, this)); + mCommitCallbackRegistrar.add("Inventory.SaveOutfitPhoto", { boost::bind(&LLPanelOutfitSnapshotInventory::onSend, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("Inventory.SaveOutfitCancel", { boost::bind(&LLPanelOutfitSnapshotInventory::cancel, this), cb_info::UNTRUSTED_BLOCK }); } // virtual diff --git a/indra/newview/llpanelsnapshotlocal.cpp b/indra/newview/llpanelsnapshotlocal.cpp index bcb1022c81..41b4a59e35 100644 --- a/indra/newview/llpanelsnapshotlocal.cpp +++ b/indra/newview/llpanelsnapshotlocal.cpp @@ -75,7 +75,7 @@ static LLPanelInjector<LLPanelSnapshotLocal> panel_class("llpanelsnapshotlocal") LLPanelSnapshotLocal::LLPanelSnapshotLocal() { mLocalFormat = gSavedSettings.getS32("SnapshotFormat"); - mCommitCallbackRegistrar.add("Local.Cancel", boost::bind(&LLPanelSnapshotLocal::cancel, this)); + mCommitCallbackRegistrar.add("Local.Cancel", { boost::bind(&LLPanelSnapshotLocal::cancel, this) }); } // virtual diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp index 28e1f33b16..560391d7e9 100644 --- a/indra/newview/llpanelsnapshotoptions.cpp +++ b/indra/newview/llpanelsnapshotoptions.cpp @@ -64,10 +64,10 @@ static LLPanelInjector<LLPanelSnapshotOptions> panel_class("llpanelsnapshotoptio LLPanelSnapshotOptions::LLPanelSnapshotOptions() { - mCommitCallbackRegistrar.add("Snapshot.SaveToProfile", boost::bind(&LLPanelSnapshotOptions::onSaveToProfile, this)); - mCommitCallbackRegistrar.add("Snapshot.SaveToEmail", boost::bind(&LLPanelSnapshotOptions::onSaveToEmail, this)); - mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this)); - mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this)); + mCommitCallbackRegistrar.add("Snapshot.SaveToProfile", { boost::bind(&LLPanelSnapshotOptions::onSaveToProfile, this) }); + mCommitCallbackRegistrar.add("Snapshot.SaveToEmail", { boost::bind(&LLPanelSnapshotOptions::onSaveToEmail, this) }); + mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", { boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this) }); + mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", { boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this) }); } LLPanelSnapshotOptions::~LLPanelSnapshotOptions() diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index 3a25e471bb..eb4814bd93 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -86,8 +86,8 @@ static LLPanelInjector<LLPanelSnapshotPostcard> panel_class("llpanelsnapshotpost LLPanelSnapshotPostcard::LLPanelSnapshotPostcard() : mHasFirstMsgFocus(false) { - mCommitCallbackRegistrar.add("Postcard.Send", boost::bind(&LLPanelSnapshotPostcard::onSend, this)); - mCommitCallbackRegistrar.add("Postcard.Cancel", boost::bind(&LLPanelSnapshotPostcard::cancel, this)); + mCommitCallbackRegistrar.add("Postcard.Send", { boost::bind(&LLPanelSnapshotPostcard::onSend, this), cb_info::UNTRUSTED_THROTTLE }); + mCommitCallbackRegistrar.add("Postcard.Cancel", { boost::bind(&LLPanelSnapshotPostcard::cancel, this), cb_info::UNTRUSTED_THROTTLE }); } diff --git a/indra/newview/llpanelsnapshotprofile.cpp b/indra/newview/llpanelsnapshotprofile.cpp index 7204235407..25afd0dd39 100644 --- a/indra/newview/llpanelsnapshotprofile.cpp +++ b/indra/newview/llpanelsnapshotprofile.cpp @@ -68,8 +68,8 @@ static LLPanelInjector<LLPanelSnapshotProfile> panel_class("llpanelsnapshotprofi LLPanelSnapshotProfile::LLPanelSnapshotProfile() { - mCommitCallbackRegistrar.add("PostToProfile.Send", boost::bind(&LLPanelSnapshotProfile::onSend, this)); - mCommitCallbackRegistrar.add("PostToProfile.Cancel", boost::bind(&LLPanelSnapshotProfile::cancel, this)); + mCommitCallbackRegistrar.add("PostToProfile.Send", { boost::bind(&LLPanelSnapshotProfile::onSend, this), cb_info::UNTRUSTED_BLOCK }); + mCommitCallbackRegistrar.add("PostToProfile.Cancel", { boost::bind(&LLPanelSnapshotProfile::cancel, this), cb_info::UNTRUSTED_BLOCK }); } // virtual diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 627074efa9..403920a8f5 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -402,7 +402,7 @@ LLTeleportHistoryPanel::~LLTeleportHistoryPanel() BOOL LLTeleportHistoryPanel::postBuild() { - mCommitCallbackRegistrar.add("TeleportHistory.GearMenu.Action", boost::bind(&LLTeleportHistoryPanel::onGearMenuAction, this, _2)); + mCommitCallbackRegistrar.add("TeleportHistory.GearMenu.Action", { boost::bind(&LLTeleportHistoryPanel::onGearMenuAction, this, _2), cb_info::UNTRUSTED_THROTTLE }); mEnableCallbackRegistrar.add("TeleportHistory.GearMenu.Enable", boost::bind(&LLTeleportHistoryPanel::isActionEnabled, this, _2)); // init menus before list, since menus are passed to list @@ -939,10 +939,9 @@ void LLTeleportHistoryPanel::onAccordionTabRightClick(LLView *view, S32 x, S32 y // set up the callbacks for all of the avatar menu items // (N.B. callbacks don't take const refs as mID is local scope) - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - - registrar.add("TeleportHistory.TabOpen", boost::bind(&LLTeleportHistoryPanel::onAccordionTabOpen, this, tab)); - registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab)); + ScopedRegistrarHelper registrar; + registrar.add("TeleportHistory.TabOpen", boost::bind(&LLTeleportHistoryPanel::onAccordionTabOpen, this, tab)); + registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab)); // create the context menu from the XUI llassert(LLMenuGL::sMenuContainer != NULL); diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index 499c290c66..773200058b 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -133,7 +133,7 @@ BOOL LLPanelTopInfoBar::handleRightMouseDown(S32 x, S32 y, MASK mask) if(!LLUICtrl::CommitCallbackRegistry::getValue("TopInfoBar.Action")) { LLUICtrl::CommitCallbackRegistry::currentRegistrar() - .add("TopInfoBar.Action", boost::bind(&LLPanelTopInfoBar::onContextMenuItemClicked, this, _2)); + .add("TopInfoBar.Action", { boost::bind(&LLPanelTopInfoBar::onContextMenuItemClicked, this, _2) }); } show_topinfobar_context_menu(this, x, y); return TRUE; diff --git a/indra/newview/llpanelvoiceeffect.cpp b/indra/newview/llpanelvoiceeffect.cpp index 681d35dafc..dd8dadadc0 100644 --- a/indra/newview/llpanelvoiceeffect.cpp +++ b/indra/newview/llpanelvoiceeffect.cpp @@ -42,7 +42,7 @@ static LLPanelInjector<LLPanelVoiceEffect> t_panel_voice_effect("panel_voice_eff LLPanelVoiceEffect::LLPanelVoiceEffect() : mVoiceEffectCombo(NULL) { - mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this)); + mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", { boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this), cb_info::UNTRUSTED_BLOCK }); } LLPanelVoiceEffect::~LLPanelVoiceEffect() diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 7a483a44ea..d64e31b7fb 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -222,7 +222,7 @@ LLPanelVolume::LLPanelVolume() { setMouseOpaque(FALSE); - mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2)); + mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", { boost::bind(&LLPanelVolume::menuDoToSelected, this, _2) }); mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2)); } diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp index 553decca2c..d7eb1e28a3 100644 --- a/indra/newview/llpanelvolumepulldown.cpp +++ b/indra/newview/llpanelvolumepulldown.cpp @@ -48,10 +48,10 @@ // Default constructor LLPanelVolumePulldown::LLPanelVolumePulldown() { - mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2)); - mCommitCallbackRegistrar.add("Vol.SetSounds", boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this)); - mCommitCallbackRegistrar.add("Vol.updateCheckbox", boost::bind(&LLPanelVolumePulldown::updateCheckbox, this, _1, _2)); - mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2)); + mCommitCallbackRegistrar.add("Vol.setControlFalse", { boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2) }); + mCommitCallbackRegistrar.add("Vol.SetSounds", { boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this) }); + mCommitCallbackRegistrar.add("Vol.updateCheckbox", { boost::bind(&LLPanelVolumePulldown::updateCheckbox, this, _1, _2) }); + mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", { boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2) }); buildFromFile( "panel_volume_pulldown.xml"); } diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 9a7281cda4..1715a8bbfc 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -62,7 +62,7 @@ public: LLWearingGearMenu(LLPanelWearing* panel_wearing) : mMenu(NULL), mPanelWearing(panel_wearing) { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; registrar.add("Gear.TouchAttach", boost::bind(&LLWearingGearMenu::handleMultiple, this, handle_attachment_touch)); @@ -103,7 +103,7 @@ class LLWearingContextMenu : public LLListContextMenu protected: /* virtual */ LLContextMenu* createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; registrar.add("Wearing.TouchAttach", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs)); registrar.add("Wearing.EditItem", boost::bind(handleMultiple, handle_item_edit, mUUIDs)); @@ -180,7 +180,7 @@ public: protected: /* virtual */ LLContextMenu* createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; registrar.add("Wearing.EditItem", boost::bind(&LLPanelWearing::onEditAttachment, mPanelWearing)); registrar.add("Wearing.Detach", boost::bind(&LLPanelWearing::onRemoveAttachment, mPanelWearing)); diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index dfc41b6700..040a477756 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -46,7 +46,7 @@ const S32 ADVANCED_VPAD = 3; LLPreviewAnim::LLPreviewAnim(const LLSD& key) : LLPreview( key ) { - mCommitCallbackRegistrar.add("PreviewAnim.Play", boost::bind(&LLPreviewAnim::play, this, _2)); + mCommitCallbackRegistrar.add("PreviewAnim.Play", { boost::bind(&LLPreviewAnim::play, this, _2) }); } // virtual diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 70458af0e8..07a4000cf2 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -495,7 +495,7 @@ BOOL LLScriptEdCore::postBuild() LLSyntaxIdLSL::getInstance()->initialize(); processKeywords(); - mCommitCallbackRegistrar.add("FontSize.Set", boost::bind(&LLScriptEdCore::onChangeFontSize, this, _2)); + mCommitCallbackRegistrar.add("FontSize.Set", { boost::bind(&LLScriptEdCore::onChangeFontSize, this, _2) }); mEnableCallbackRegistrar.add("FontSize.Check", boost::bind(&LLScriptEdCore::isFontSizeChecked, this, _2)); LLToggleableMenu *context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( diff --git a/indra/newview/llsaveoutfitcombobtn.cpp b/indra/newview/llsaveoutfitcombobtn.cpp index 6418c310c1..bc1bdfdcda 100644 --- a/indra/newview/llsaveoutfitcombobtn.cpp +++ b/indra/newview/llsaveoutfitcombobtn.cpp @@ -39,7 +39,7 @@ LLSaveOutfitComboBtn::LLSaveOutfitComboBtn(LLPanel* parent, bool saveAsDefaultAc mParent(parent), mSaveAsDefaultAction(saveAsDefaultAction) { // register action mapping before creating menu - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar; + LLUICtrl::ScopedRegistrarHelper save_registar; save_registar.add("Outfit.Save.Action", boost::bind( &LLSaveOutfitComboBtn::saveOutfit, this, false)); save_registar.add("Outfit.SaveAs.Action", boost::bind( diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index b1f895317a..e01f04f210 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -84,9 +84,9 @@ LLToolMgr::LLToolMgr() LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Active", boost::bind(&LLToolMgr::inEdit, this)); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this)); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&LLToolMgr::buildEnabledOrActive, this)); - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this, _2)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", { boost::bind(&LLToolMgr::toggleBuildMode, this, _2) }); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Marketplace.Enabled", boost::bind(&LLToolMgr::canAccessMarketplace, this)); - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Marketplace.Toggle", boost::bind(&LLToolMgr::toggleMarketplace, this, _2)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Marketplace.Toggle", { boost::bind(&LLToolMgr::toggleMarketplace, this, _2) }); gToolNull = new LLTool(LLStringUtil::null); // Does nothing setCurrentTool(gToolNull); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 557197ccf0..a9d400881c 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9396,19 +9396,17 @@ void initialize_edit_menu() } typedef LLUICtrl::CommitCallbackInfo cb_info; -#define COMMIT_ADD(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func)) -#define COMMIT_ADD_TRUSTED(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_BLOCK)) -#define COMMIT_ADD_THROTTLE(func_name, func) LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(func_name, cb_info(func, cb_info::UNTRUSTED_THROTTLE)) void initialize_spellcheck_menu() { + LLUICtrl::CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::defaultRegistrar()); LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - COMMIT_ADD_TRUSTED("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + registrar.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2), cb_info::UNTRUSTED_BLOCK); enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); - COMMIT_ADD_TRUSTED("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + registrar.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1), cb_info::UNTRUSTED_BLOCK); enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); - COMMIT_ADD_TRUSTED("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + registrar.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1), cb_info::UNTRUSTED_BLOCK); enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); } @@ -9432,6 +9430,7 @@ void initialize_menus() bool mMult; }; + LLUICtrl::CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::defaultRegistrar()); LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); // Generic enable and visible @@ -9447,11 +9446,11 @@ void initialize_menus() enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); // Agent - COMMIT_ADD("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); + registrar.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); - COMMIT_ADD_TRUSTED("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); - COMMIT_ADD_TRUSTED("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); - COMMIT_ADD_TRUSTED("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); + registrar.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2), cb_info::UNTRUSTED_BLOCK); + registrar.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2), cb_info::UNTRUSTED_BLOCK); + registrar.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2), cb_info::UNTRUSTED_BLOCK); enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); @@ -9463,12 +9462,12 @@ void initialize_menus() view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); - COMMIT_ADD("CustomizeAvatar", boost::bind(&handle_customize_avatar)); - COMMIT_ADD("NowWearing", boost::bind(&handle_now_wearing)); - COMMIT_ADD("EditOutfit", boost::bind(&handle_edit_outfit)); - COMMIT_ADD("EditShape", boost::bind(&handle_edit_shape)); - COMMIT_ADD("HoverHeight", boost::bind(&handle_hover_height)); - COMMIT_ADD("EditPhysics", boost::bind(&handle_edit_physics)); + registrar.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); + registrar.add("NowWearing", boost::bind(&handle_now_wearing)); + registrar.add("EditOutfit", boost::bind(&handle_edit_outfit)); + registrar.add("EditShape", boost::bind(&handle_edit_shape)); + registrar.add("HoverHeight", boost::bind(&handle_hover_height)); + registrar.add("EditPhysics", boost::bind(&handle_edit_physics)); // View menu view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); @@ -9501,14 +9500,14 @@ void initialize_menus() view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); // Communicate > Voice morphing > Subscribe... - COMMIT_ADD("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); + registrar.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); // Communicate > Voice morphing > Premium perk... - COMMIT_ADD("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); + registrar.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); - COMMIT_ADD_TRUSTED("Communicate.VoiceMorphing.NoVoiceMorphing.Click" - , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); + registrar.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" + , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing"), cb_info::UNTRUSTED_BLOCK); // World menu view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); @@ -9548,14 +9547,14 @@ void initialize_menus() view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); - COMMIT_ADD("Tools.Link", boost::bind(&handle_link_objects)); - COMMIT_ADD("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); + registrar.add("Tools.Link", boost::bind(&handle_link_objects)); + registrar.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - COMMIT_ADD("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - COMMIT_ADD_THROTTLE("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - COMMIT_ADD_THROTTLE("Tools.TakeCopy", boost::bind(&handle_take_copy)); + registrar.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); + registrar.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take), cb_info::UNTRUSTED_THROTTLE); + registrar.add("Tools.TakeCopy", boost::bind(&handle_take_copy), cb_info::UNTRUSTED_THROTTLE); view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); @@ -9605,7 +9604,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); - COMMIT_ADD("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); + registrar.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); // Develop > Render @@ -9636,15 +9635,15 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); // Advanced > UI - COMMIT_ADD("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser - COMMIT_ADD("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater - COMMIT_ADD("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); - COMMIT_ADD("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); + registrar.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser + registrar.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater + registrar.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); + registrar.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - COMMIT_ADD_THROTTLE("Advanced.DumpTimers", boost::bind(&handle_dump_timers)); - COMMIT_ADD("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); + registrar.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers), cb_info::UNTRUSTED_THROTTLE); + registrar.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus)); view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); @@ -9665,11 +9664,11 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); // Advanced > XUI - COMMIT_ADD("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); + registrar.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - COMMIT_ADD_TRUSTED("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); + registrar.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches), cb_info::UNTRUSTED_BLOCK); // Advanced > Character > Grab Baked Texture view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); @@ -9755,11 +9754,11 @@ void initialize_menus() view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); //Develop (clear cache immediately) - COMMIT_ADD_TRUSTED("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + registrar.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately), cb_info::UNTRUSTED_BLOCK); // Develop (Fonts debugging) - COMMIT_ADD_THROTTLE("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); - COMMIT_ADD_THROTTLE("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); + registrar.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts), cb_info::UNTRUSTED_THROTTLE); + registrar.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures), cb_info::UNTRUSTED_THROTTLE); // Admin >Object view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); @@ -9796,12 +9795,12 @@ void initialize_menus() view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); - COMMIT_ADD("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); + registrar.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - COMMIT_ADD("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); - COMMIT_ADD("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); + registrar.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); + registrar.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call", cb_info::UNTRUSTED_BLOCK); enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); @@ -9816,34 +9815,34 @@ void initialize_menus() enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible)); - COMMIT_ADD("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); + registrar.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); // Object pie menu view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); - COMMIT_ADD("Object.Touch", boost::bind(&handle_object_touch)); - COMMIT_ADD("Object.ShowOriginal", boost::bind(&handle_object_show_original)); - COMMIT_ADD("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - COMMIT_ADD("Object.Delete", boost::bind(&handle_object_delete)); + registrar.add("Object.Touch", boost::bind(&handle_object_touch)); + registrar.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); + registrar.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); + registrar.add("Object.Delete", boost::bind(&handle_object_delete)); view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); - COMMIT_ADD("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); + registrar.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse", cb_info::UNTRUSTED_THROTTLE); view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - COMMIT_ADD_THROTTLE("Object.Buy", boost::bind(&handle_buy)); - COMMIT_ADD("Object.Edit", boost::bind(&handle_object_edit)); - COMMIT_ADD("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); - COMMIT_ADD("Object.Inspect", boost::bind(&handle_object_inspect)); - COMMIT_ADD("Object.Open", boost::bind(&handle_object_open)); - COMMIT_ADD("Object.Take", boost::bind(&handle_take)); - COMMIT_ADD("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); + registrar.add("Object.Buy", boost::bind(&handle_buy), cb_info::UNTRUSTED_THROTTLE); + registrar.add("Object.Edit", boost::bind(&handle_object_edit)); + registrar.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); + registrar.add("Object.Inspect", boost::bind(&handle_object_inspect)); + registrar.add("Object.Open", boost::bind(&handle_object_open)); + registrar.add("Object.Take", boost::bind(&handle_take)); + registrar.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect)); enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); @@ -9862,7 +9861,7 @@ void initialize_menus() enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); - COMMIT_ADD("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); + registrar.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); // Attachment pie menu enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); @@ -9884,11 +9883,11 @@ void initialize_menus() view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - COMMIT_ADD_THROTTLE("Land.Buy", boost::bind(&handle_buy_land)); + registrar.add("Land.Buy", boost::bind(&handle_buy_land), cb_info::UNTRUSTED_THROTTLE); // Generic actions - COMMIT_ADD_THROTTLE("ReportAbuse", boost::bind(&handle_report_abuse)); - COMMIT_ADD_THROTTLE("BuyCurrency", boost::bind(&handle_buy_currency)); + registrar.add("ReportAbuse", boost::bind(&handle_report_abuse), cb_info::UNTRUSTED_THROTTLE); + registrar.add("BuyCurrency", boost::bind(&handle_buy_currency), cb_info::UNTRUSTED_THROTTLE); view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak", cb_info::UNTRUSTED_BLOCK); @@ -9900,19 +9899,19 @@ void initialize_menus() view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); - COMMIT_ADD("PayObject", boost::bind(&handle_give_money_dialog)); + registrar.add("PayObject", boost::bind(&handle_give_money_dialog)); - COMMIT_ADD_THROTTLE("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); + registrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow), cb_info::UNTRUSTED_THROTTLE); enable.add("EnablePayObject", boost::bind(&enable_pay_object)); enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); enable.add("EnableEdit", boost::bind(&enable_object_edit)); enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); enable.add("VisibleBuild", boost::bind(&enable_object_build)); - COMMIT_ADD("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); + registrar.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); - COMMIT_ADD("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); + registrar.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 187c4ed638..676164fcc6 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -888,7 +888,7 @@ void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, LLWearableTyp } LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("Wearable.CreateNew", boost::bind(createNewWearableByType, w_type)); + registrar.add("Wearable.CreateNew", { boost::bind(createNewWearableByType, w_type), cb_info::UNTRUSTED_THROTTLE }); menup = createFromFile("menu_wearable_list_item.xml"); if (!menup) { @@ -914,7 +914,7 @@ void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, LLWearableTyp // virtual LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; const uuid_vec_t& ids = mUUIDs; // selected items IDs LLUUID selected_id = ids.front(); // ID of the first selected item -- cgit v1.2.3 From e99c494418b4eec21ce3c17c5e642c253fae8084 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 10 Jun 2024 15:41:55 +0300 Subject: another batch of changes to use ScopedRegistrarHelper --- indra/newview/llblocklist.cpp | 2 +- indra/newview/llchathistory.cpp | 6 +++--- indra/newview/llchiclet.cpp | 12 ++++++------ indra/newview/llcofwearables.cpp | 10 +++++----- indra/newview/llconversationloglist.cpp | 4 ++-- indra/newview/llfloatermyenvironment.cpp | 8 ++++---- indra/newview/llfloaternotificationsconsole.cpp | 2 +- indra/newview/llfloaterregioninfo.cpp | 2 +- indra/newview/llpaneleditwearable.cpp | 4 ++-- indra/newview/llpanellandmarks.cpp | 8 ++++---- indra/newview/llpanelplaces.cpp | 2 +- indra/newview/lluilistener.cpp | 2 +- 12 files changed, 31 insertions(+), 31 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llblocklist.cpp b/indra/newview/llblocklist.cpp index 31b83cfb57..e065e9c23e 100644 --- a/indra/newview/llblocklist.cpp +++ b/indra/newview/llblocklist.cpp @@ -50,7 +50,7 @@ LLBlockList::LLBlockList(const Params& p) mMuteListSize = LLMuteList::getInstance()->getMutes().size(); // Set up context menu. - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; registrar.add ("Block.Action", boost::bind(&LLBlockList::onCustomAction, this, _2)); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index d549f372e3..603b7618ef 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -871,7 +871,7 @@ protected: LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleObject.get(); if (!menu) { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); @@ -899,9 +899,9 @@ protected: LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get(); if (!menu) { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; - registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); + registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK); registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 3d328e66c8..70aed212bd 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -210,9 +210,9 @@ void LLNotificationChiclet::createMenu() return; } - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; registrar.add("NotificationWellChicletMenu.Action", - boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2)); + boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; enable_registrar.add("NotificationWellChicletMenu.EnableItem", @@ -1132,8 +1132,8 @@ void LLScriptChiclet::createPopupMenu() if(!canCreateMenu()) return; - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2)); + ScopedRegistrarHelper registrar; + registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK); LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> ("menu_script_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); @@ -1215,8 +1215,8 @@ void LLInvOfferChiclet::createPopupMenu() if(!canCreateMenu()) return; - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2)); + ScopedRegistrarHelper registrar; + registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK); LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> ("menu_inv_offer_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index c43864d85f..3e6c966616 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -138,7 +138,7 @@ protected: /*virtual*/ LLContextMenu* createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; registrar.add("Attachment.Touch", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs)); registrar.add("Attachment.Edit", boost::bind(handleMultiple, handle_item_edit, mUUIDs)); @@ -191,7 +191,7 @@ protected: /*virtual*/ LLContextMenu* createMenu() { - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; LLUUID selected_id = mUUIDs.back(); @@ -251,9 +251,9 @@ protected: LLUUID selected_id = mUUIDs.back(); LLPanelOutfitEdit* panel_oe = dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit")); - registrar.add("BodyPart.Replace", boost::bind(&LLPanelOutfitEdit::onReplaceMenuItemClicked, panel_oe, selected_id)); - registrar.add("BodyPart.Edit", boost::bind(LLAgentWearables::editWearable, selected_id)); - registrar.add("BodyPart.Create", boost::bind(&CofBodyPartContextMenu::createNew, this, selected_id)); + registrar.add("BodyPart.Replace", { boost::bind(&LLPanelOutfitEdit::onReplaceMenuItemClicked, panel_oe, selected_id) }); + registrar.add("BodyPart.Edit", { boost::bind(LLAgentWearables::editWearable, selected_id) }); + registrar.add("BodyPart.Create", { boost::bind(&CofBodyPartContextMenu::createNew, this, selected_id) }); enable_registrar.add("BodyPart.OnEnable", boost::bind(&CofBodyPartContextMenu::onEnable, this, _2)); diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 832d4c269b..f6fce7146d 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -47,11 +47,11 @@ LLConversationLogList::LLConversationLogList(const Params& p) LLConversationLog::instance().addObserver(this); // Set up context menu. - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar check_registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - registrar.add ("Calllog.Action", boost::bind(&LLConversationLogList::onCustomAction, this, _2)); + registrar.add ("Calllog.Action", boost::bind(&LLConversationLogList::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK); check_registrar.add ("Calllog.Check", boost::bind(&LLConversationLogList::isActionChecked,this, _2)); enable_registrar.add("Calllog.Enable", boost::bind(&LLConversationLogList::isActionEnabled,this, _2)); diff --git a/indra/newview/llfloatermyenvironment.cpp b/indra/newview/llfloatermyenvironment.cpp index f93af9c312..53ee7ae540 100644 --- a/indra/newview/llfloatermyenvironment.cpp +++ b/indra/newview/llfloatermyenvironment.cpp @@ -81,10 +81,10 @@ LLFloaterMyEnvironment::LLFloaterMyEnvironment(const LLSD& key) : mTypeFilter((0x01 << static_cast<U64>(LLSettingsType::ST_DAYCYCLE)) | (0x01 << static_cast<U64>(LLSettingsType::ST_SKY)) | (0x01 << static_cast<U64>(LLSettingsType::ST_WATER))), mSelectedAsset() { - mCommitCallbackRegistrar.add(ACTION_DOCREATE, [this](LLUICtrl *, const LLSD &userdata) { onDoCreate(userdata); }); - mCommitCallbackRegistrar.add(ACTION_DOEDIT, [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->openSelected(); }); - mCommitCallbackRegistrar.add(ACTION_DOAPPLY, [this](LLUICtrl *, const LLSD &userdata) { onDoApply(userdata.asString()); }); - mCommitCallbackRegistrar.add(ACTION_COPYPASTE, [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->doToSelected(userdata.asString()); }); + mCommitCallbackRegistrar.add(ACTION_DOCREATE, { [this](LLUICtrl *, const LLSD &userdata) { onDoCreate(userdata); } }); + mCommitCallbackRegistrar.add(ACTION_DOEDIT, { [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->openSelected(); } }); + mCommitCallbackRegistrar.add(ACTION_DOAPPLY, { [this](LLUICtrl *, const LLSD &userdata) { onDoApply(userdata.asString()); } }); + mCommitCallbackRegistrar.add(ACTION_COPYPASTE, { [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->doToSelected(userdata.asString()); } }); mEnableCallbackRegistrar.add(ENABLE_ACTION, [this](LLUICtrl *, const LLSD &userdata) { return canAction(userdata.asString()); }); mEnableCallbackRegistrar.add(ENABLE_CANAPPLY, [this](LLUICtrl *, const LLSD &userdata) { return canApply(userdata.asString()); }); diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp index dbeb5ca573..56546912c8 100644 --- a/indra/newview/llfloaternotificationsconsole.cpp +++ b/indra/newview/llfloaternotificationsconsole.cpp @@ -151,7 +151,7 @@ bool LLNotificationChannelPanel::update(const LLSD& payload) LLFloaterNotificationConsole::LLFloaterNotificationConsole(const LLSD& key) : LLFloater(key) { - mCommitCallbackRegistrar.add("ClickAdd", boost::bind(&LLFloaterNotificationConsole::onClickAdd, this)); + mCommitCallbackRegistrar.add("ClickAdd", { boost::bind(&LLFloaterNotificationConsole::onClickAdd, this) }); } BOOL LLFloaterNotificationConsole::postBuild() diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index ef81cb549f..82bcb94669 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -258,7 +258,7 @@ BOOL LLFloaterRegionInfo::postBuild() panel = new LLPanelRegionGeneralInfo; mInfoPanels.push_back(panel); - panel->getCommitCallbackRegistrar().add("RegionInfo.ManageTelehub", boost::bind(&LLPanelRegionInfo::onClickManageTelehub, panel)); + panel->getCommitCallbackRegistrar().add("RegionInfo.ManageTelehub", { boost::bind(&LLPanelRegionInfo::onClickManageTelehub, panel) }); panel->buildFromFile("panel_region_general.xml"); mTab->addTabPanel(panel); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 0c69e68639..85671e2cc2 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -641,8 +641,8 @@ LLPanelEditWearable::LLPanelEditWearable() , mWearablePtr(NULL) , mWearableItem(NULL) { - mCommitCallbackRegistrar.add("ColorSwatch.Commit", boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1)); - mCommitCallbackRegistrar.add("TexturePicker.Commit", boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1)); + mCommitCallbackRegistrar.add("ColorSwatch.Commit", { boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1) }); + mCommitCallbackRegistrar.add("TexturePicker.Commit", { boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1) }); } //virtual diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 2a726e3092..f8bb0f71a7 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -458,10 +458,10 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list // List Commands Handlers void LLLandmarksPanel::initListCommandsHandlers() { - mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2)); - mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2)); - mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2)); - mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2)); + mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", { boost::bind(&LLLandmarksPanel::onAddAction, this, _2) }); + mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", { boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2) }); + mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", { boost::bind(&LLLandmarksPanel::onCustomAction, this, _2) }); + mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", { boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2)} ); mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2)); mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2)); mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 67aa51e38a..0895d3dc0b 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -315,7 +315,7 @@ BOOL LLPanelPlaces::postBuild() , _7 // EAcceptance* accept )); - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; registrar.add("Places.OverflowMenu.Action", boost::bind(&LLPanelPlaces::onOverflowMenuItemClicked, this, _2)); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; enable_registrar.add("Places.OverflowMenu.Enable", boost::bind(&LLPanelPlaces::onOverflowMenuItemEnable, this, _2)); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 604f766ab2..3ec300ffba 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -63,7 +63,7 @@ typedef LLUICtrl::CommitCallbackInfo cb_info; void LLUIListener::call(const LLSD& event) { Response response(LLSD(), event); - LLUICtrl::CommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(event["function"]); + LLUICtrl::CommitCallbackInfo *info = LLUICtrl::CommitCallbackRegistry::getValue(event["function"]); if (!info ) { return response.error(stringize("Function ", std::quoted(event["function"].asString()), " was not found")); -- cgit v1.2.3 From f3bfc13f7957a5f142871bddc57d63cd08595ad9 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Tue, 11 Jun 2024 17:37:33 +0300 Subject: clean up LLUIListener::call --- indra/newview/lllocationinputctrl.cpp | 2 +- indra/newview/lluilistener.cpp | 46 +++++++++++++++++------------------ indra/newview/lluilistener.h | 4 +-- indra/newview/llviewermenu.cpp | 2 +- 4 files changed, 26 insertions(+), 28 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index c75bbec1d7..21f13108e0 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -377,7 +377,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) addChild(mParcelIcon[SEE_AVATARS_ICON]); // Register callbacks and load the location field context menu (NB: the order matters). - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", LLUICtrl::CommitCallbackInfo(boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2))); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", { boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2) }); LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2)); setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 3ec300ffba..4afd7f1766 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -64,45 +64,43 @@ void LLUIListener::call(const LLSD& event) { Response response(LLSD(), event); LLUICtrl::CommitCallbackInfo *info = LLUICtrl::CommitCallbackRegistry::getValue(event["function"]); - if (!info ) + if (!info || !info->callback_func) { return response.error(stringize("Function ", std::quoted(event["function"].asString()), " was not found")); } if (info->handle_untrusted == cb_info::UNTRUSTED_BLOCK) { - return response.error(stringize("Function ", std::quoted(event["function"].asString()), " is not allowed to be called from the script")); + return response.error(stringize("Function ", std::quoted(event["function"].asString()), " may not be called from the script")); } - F64 cur_time = LLTimer::getElapsedSeconds(); - bool is_untrusted_throttle = info->handle_untrusted == cb_info::UNTRUSTED_THROTTLE; //Separate UNTRUSTED_THROTTLE and UNTRUSTED_ALLOW functions to have different timeout - F64 time_delta = is_untrusted_throttle ? mLastUntrustedThrottle + THROTTLE_PERIOD : mLastMinThrottle + MIN_THROTTLE; - if (cur_time < time_delta) + F64 *throttlep, period; + if (info->handle_untrusted == cb_info::UNTRUSTED_THROTTLE) { - LL_WARNS("LLUIListener") << "Throttled function " << std::quoted(event["function"].asString()) << LL_ENDL; - return; - } - if (is_untrusted_throttle) - { - mLastUntrustedThrottle = cur_time; + throttlep = &mLastUntrustedThrottle; + period = THROTTLE_PERIOD; } else { - mLastMinThrottle = cur_time; + throttlep = &mLastMinThrottle; + period = MIN_THROTTLE; } - - LLUICtrl::commit_callback_t func = info->callback_func; - - if (info->callback_func) + F64 cur_time = LLTimer::getElapsedSeconds(); + F64 time_delta = *throttlep + period; + if (cur_time < time_delta) { - // Interestingly, view_listener_t::addMenu() (addCommit(), - // addEnable()) constructs a commit_callback_t callable that accepts - // two parameters but discards the first. Only the second is passed to - // handleEvent(). Therefore we feel completely safe passing NULL for - // the first parameter. - (func)(NULL, event["parameter"]); + LL_WARNS("LLUIListener") << "Throttled function " << std::quoted(event["function"].asString()) << LL_ENDL; + return; } + *throttlep = cur_time; + + // Interestingly, view_listener_t::addMenu() (addCommit(), + // addEnable()) constructs a commit_callback_t callable that accepts + // two parameters but discards the first. Only the second is passed to + // handleEvent(). Therefore we feel completely safe passing NULL for + // the first parameter. + (info->callback_func)(NULL, event["parameter"]); } void LLUIListener::getValue(const LLSD&event) const @@ -119,6 +117,6 @@ void LLUIListener::getValue(const LLSD&event) const } else { - response.error(STRINGIZE("UI control " << std::quoted(event["path"].asString()) << " was not found")); + response.error(stringize("UI control ", std::quoted(event["path"].asString()), " was not found")); } } diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index 790284a27a..0df2afb3fe 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -45,8 +45,8 @@ public: void getValue(const LLSD&event) const; private: - F64 mLastUntrustedThrottle {0.f}; - F64 mLastMinThrottle {0.f}; + F64 mLastUntrustedThrottle {0}; + F64 mLastMinThrottle {0}; }; #endif /* ! defined(LL_LLUILISTENER_H) */ diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a9d400881c..e7ac8d9be2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9430,7 +9430,7 @@ void initialize_menus() bool mMult; }; - LLUICtrl::CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::defaultRegistrar()); + LLUICtrl::CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::currentRegistrar()); LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); // Generic enable and visible -- cgit v1.2.3 From 9b7d71cdfc09e9d49a2bbd44a010086b37ab78b4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 13:37:59 -0400 Subject: Update "LLWindow" listener doc to cite github URL, not bitbucket. --- indra/newview/llwindowlistener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp index 87d18cfc00..efe395d9ca 100644 --- a/indra/newview/llwindowlistener.cpp +++ b/indra/newview/llwindowlistener.cpp @@ -55,7 +55,7 @@ LLWindowListener::LLWindowListener(LLViewerWindow *window, const KeyboardGetter& "Given [\"keysym\"], [\"keycode\"] or [\"char\"], inject the specified "; std::string keyExplain = "(integer keycode values, or keysym string from any addKeyName() call in\n" - "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llwindow/llkeyboard.cpp )\n"; + "https://github.com/secondlife/viewer/blob/main/indra/llwindow/llkeyboard.cpp#L68-L124)\n"; std::string mask = "Specify optional [\"mask\"] as an array containing any of \"CTL\", \"ALT\",\n" "\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n" -- cgit v1.2.3 From eae45eefb55410782559b4ace5350b2a99f63234 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 13:39:13 -0400 Subject: mapargs() now accepts 'name1,name2,...' as argument names in addition to a list {'name1', 'name2', ...}. --- indra/newview/scripts/lua/mapargs.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/mapargs.lua b/indra/newview/scripts/lua/mapargs.lua index 78e691d8bc..45f5a9c556 100644 --- a/indra/newview/scripts/lua/mapargs.lua +++ b/indra/newview/scripts/lua/mapargs.lua @@ -21,6 +21,12 @@ local function mapargs(names, ...) -- array items it contains, if there are any holes. Track that by hand. -- We must be able to handle f(1, nil, 3) calls. local maxpos = 0 + + -- For convenience, allow passing 'names' as a string 'n0,n1,...' + if type(names) == 'string' then + names = string.split(names, ',') + end + if not (args.n == 1 and type(args[1]) == 'table') then -- If caller passes more than one argument, or if the first argument -- is not a table, then it's classic positional function-call syntax: -- cgit v1.2.3 From 18c4dcc5998e061fe3ab54607665c775dd18c826 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 21:42:10 -0400 Subject: Allow Python-like 'object = ClassName(ctor args)' constructor calls. The discussions we've read about Lua classes conventionally use ClassName:new() as the constructor, and so far we've followed that convention. But setting metaclass(ClassName).__call = ClassName.new permits Lua to respond to calls of the form ClassName(ctor args) by implicitly calling ClassName:new(ctor args). Introduce util.classctor(). Calling util.classctor(ClassName) sets ClassName's metaclass's __call to ClassName's constructor method. If the constructor method is named something other than new(), pass ClassName.method as the second arg. Use util.classctor() on each of our classes that defines a new() method. Replace ClassName:new(args) calls with ClassName(args) calls throughout. --- indra/newview/scripts/lua/ErrorQueue.lua | 5 ++++- indra/newview/scripts/lua/Floater.lua | 3 +++ indra/newview/scripts/lua/Queue.lua | 4 ++++ indra/newview/scripts/lua/WaitQueue.lua | 7 ++++-- indra/newview/scripts/lua/leap.lua | 13 +++++++---- indra/newview/scripts/lua/qtest.lua | 12 +++++------ indra/newview/scripts/lua/test_luafloater_demo.lua | 2 +- .../newview/scripts/lua/test_luafloater_demo2.lua | 2 +- .../scripts/lua/test_luafloater_gesture_list.lua | 2 +- .../scripts/lua/test_luafloater_gesture_list2.lua | 2 +- indra/newview/scripts/lua/test_timers.lua | 16 +++++++------- indra/newview/scripts/lua/timers.lua | 3 +++ indra/newview/scripts/lua/util.lua | 25 ++++++++++++++++++++++ 13 files changed, 71 insertions(+), 25 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index 13e4e92941..e6e9a5ef48 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -5,8 +5,11 @@ local WaitQueue = require('WaitQueue') local function dbg(...) end -- local dbg = require('printf') +local util = require('util') -local ErrorQueue = WaitQueue:new() +local ErrorQueue = WaitQueue() + +util.classctor(ErrorQueue) function ErrorQueue:Error(message) -- Setting Error() is a marker, like closing the queue. Once we reach the diff --git a/indra/newview/scripts/lua/Floater.lua b/indra/newview/scripts/lua/Floater.lua index 75696533e4..d057a74386 100644 --- a/indra/newview/scripts/lua/Floater.lua +++ b/indra/newview/scripts/lua/Floater.lua @@ -2,6 +2,7 @@ local leap = require 'leap' local fiber = require 'fiber' +local util = require 'util' -- list of all the events that a LLLuaFloater might send local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events @@ -45,6 +46,8 @@ function Floater:new(path, extra) return obj end +util.classctor(Floater) + function Floater:show() -- leap.eventstream() returns the first response, and launches a -- background fiber to call the passed callback with all subsequent diff --git a/indra/newview/scripts/lua/Queue.lua b/indra/newview/scripts/lua/Queue.lua index 5ab2a8a72c..5bc72e4057 100644 --- a/indra/newview/scripts/lua/Queue.lua +++ b/indra/newview/scripts/lua/Queue.lua @@ -7,6 +7,8 @@ -- But had to resist -- For fear it might be too obscua. +local util = require 'util' + local Queue = {} function Queue:new() @@ -20,6 +22,8 @@ function Queue:new() return obj end +util.classctor(Queue) + -- Check if the queue is empty function Queue:IsEmpty() return self._first > self._last diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index 6bcb9d62c2..7e10d03295 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -4,14 +4,15 @@ local fiber = require('fiber') local Queue = require('Queue') +local util = require('util') local function dbg(...) end -- local dbg = require('printf') -local WaitQueue = Queue:new() +local WaitQueue = Queue() function WaitQueue:new() - local obj = Queue:new() + local obj = Queue() setmetatable(obj, self) self.__index = self @@ -20,6 +21,8 @@ function WaitQueue:new() return obj end +util.classctor(WaitQueue) + function WaitQueue:Enqueue(value) if self._closed then error("can't Enqueue() on closed Queue") diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 8caae24e94..82f91ce9e9 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -43,6 +43,7 @@ local ErrorQueue = require('ErrorQueue') local inspect = require('inspect') local function dbg(...) end -- local dbg = require('printf') +local util = require('util') local leap = {} @@ -129,7 +130,7 @@ local function requestSetup(pump, data) -- because, unlike the WaitFor base class, WaitForReqid does not -- self-register on our waitfors list. Instead, capture the new -- WaitForReqid object in pending so dispatch() can find it. - local waitfor = leap.WaitForReqid:new(reqid) + local waitfor = leap.WaitForReqid(reqid) pending[reqid] = waitfor -- Pass reqid to send() to stamp it into (a copy of) the request data. dbg('requestSetup(%s, %s) storing %s', pump, data, waitfor.name) @@ -432,7 +433,7 @@ function leap.WaitFor:new(priority, name) self._id += 1 obj.name = 'WaitFor' .. self._id end - obj._queue = ErrorQueue:new() + obj._queue = ErrorQueue() obj._registered = false -- if no priority, then don't enable() - remember 0 is truthy if priority then @@ -442,6 +443,8 @@ function leap.WaitFor:new(priority, name) return obj end +util.classctor(leap.WaitFor) + -- Re-enable a disable()d WaitFor object. New WaitFor objects are -- enable()d by default. function leap.WaitFor:enable() @@ -514,13 +517,13 @@ function leap.WaitFor:exception(message) end -- ------------------------------ WaitForReqid ------------------------------- -leap.WaitForReqid = leap.WaitFor:new() +leap.WaitForReqid = leap.WaitFor() function leap.WaitForReqid:new(reqid) -- priority is meaningless, since this object won't be added to the -- priority-sorted waitfors list. Use the reqid as the debugging name -- string. - local obj = leap.WaitFor:new(nil, 'WaitForReqid(' .. reqid .. ')') + local obj = leap.WaitFor(nil, 'WaitForReqid(' .. reqid .. ')') setmetatable(obj, self) self.__index = self @@ -529,6 +532,8 @@ function leap.WaitForReqid:new(reqid) return obj end +util.classctor(leap.WaitForReqid) + function leap.WaitForReqid:filter(pump, data) -- Because we expect to directly look up the WaitForReqid object of -- interest based on the incoming ["reqid"] value, it's not necessary diff --git a/indra/newview/scripts/lua/qtest.lua b/indra/newview/scripts/lua/qtest.lua index 009446d0c3..9526f58b04 100644 --- a/indra/newview/scripts/lua/qtest.lua +++ b/indra/newview/scripts/lua/qtest.lua @@ -21,8 +21,8 @@ function resume(co, ...) end -- ------------------ Queue variables are instance-specific ------------------ -q1 = Queue:new() -q2 = Queue:new() +q1 = Queue() +q2 = Queue() q1:Enqueue(17) @@ -33,8 +33,8 @@ assert(q1:Dequeue() == nil) assert(q2:Dequeue() == nil) -- ----------------------------- test WaitQueue ------------------------------ -q1 = WaitQueue:new() -q2 = WaitQueue:new() +q1 = WaitQueue() +q2 = WaitQueue() result = {} values = { 1, 1, 2, 3, 5, 8, 13, 21 } @@ -76,7 +76,7 @@ print('result:', inspect(result)) assert(util.equal(values, result)) -- try incrementally enqueueing values -q3 = WaitQueue:new() +q3 = WaitQueue() result = {} values = { 'This', 'is', 'a', 'test', 'script' } @@ -124,7 +124,7 @@ print(string.format('%q', table.concat(result, ' '))) assert(util.equal(values, result)) -- ----------------------------- test ErrorQueue ----------------------------- -q4 = ErrorQueue:new() +q4 = ErrorQueue() result = {} values = { 'This', 'is', 'a', 'test', 'script' } diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index ab638dcdd1..65a31670c8 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -60,7 +60,7 @@ local resp = leap.request("LLFloaterReg", key) COMMAND_PUMP_NAME = resp.command_name reqid = resp.reqid -catch_events = leap.WaitFor:new(-1, "all_events") +catch_events = leap.WaitFor(-1, "all_events") function catch_events:filter(pump, data) if data.reqid == reqid then return data diff --git a/indra/newview/scripts/lua/test_luafloater_demo2.lua b/indra/newview/scripts/lua/test_luafloater_demo2.lua index 9e24237d28..3903d01e65 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo2.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo2.lua @@ -2,7 +2,7 @@ local Floater = require 'Floater' local leap = require 'leap' local startup = require 'startup' -local flt = Floater:new( +local flt = Floater( 'luafloater_demo.xml', {show_time_lbl = {"right_mouse_down", "double_click"}}) diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index 3d9a9b0ad4..a5fd325430 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -58,7 +58,7 @@ local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} key.extra_events={gesture_list = {_event("double_click")}} handleEvents(leap.request("LLFloaterReg", key)) -catch_events = leap.WaitFor:new(-1, "all_events") +catch_events = leap.WaitFor(-1, "all_events") function catch_events:filter(pump, data) if data.reqid == reqid then return data diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua index d702d09c51..bd397ef2a6 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua @@ -2,7 +2,7 @@ local Floater = require 'Floater' local LLGesture = require 'LLGesture' local startup = require 'startup' -local flt = Floater:new( +local flt = Floater( "luafloater_gesture_list.xml", {gesture_list = {"double_click"}}) diff --git a/indra/newview/scripts/lua/test_timers.lua b/indra/newview/scripts/lua/test_timers.lua index ed0de070f7..be5001aa16 100644 --- a/indra/newview/scripts/lua/test_timers.lua +++ b/indra/newview/scripts/lua/test_timers.lua @@ -6,9 +6,9 @@ local timers = require 'timers' -- is true, that timeUntilCall() is (true, close to 10), that cancel() returns -- true. After that, isRunning() is false, timeUntilCall() returns (false, 0), -- and a second cancel() returns false. -print('t0:new(10)') +print('t0(10)') start = os.clock() -t0 = timers.Timer:new(10, function() print('t0 fired at', os.clock() - start) end) +t0 = timers.Timer(10, function() print('t0 fired at', os.clock() - start) end) print('t0:isRunning(): ', t0:isRunning()) print('t0:timeUntilCall(): ', t0:timeUntilCall()) print('t0:cancel(): ', t0:cancel()) @@ -18,16 +18,16 @@ print('t0:cancel(): ', t0:cancel()) -- t1 is supposed to fire after 5 seconds, but it doesn't wait, so you see the -- t2 messages immediately after. -print('t1:new(5)') +print('t1(5)') start = os.clock() -t1 = timers.Timer:new(5, function() print('t1 fired at', os.clock() - start) end) +t1 = timers.Timer(5, function() print('t1 fired at', os.clock() - start) end) -- t2 illustrates that instead of passing a callback to new(), you can -- override the timer instance's tick() method. But t2 doesn't wait either, so -- you see the Timer(5) message immediately. -print('t2:new(2)') +print('t2(2)') start = os.clock() -t2 = timers.Timer:new(2) +t2 = timers.Timer(2) function t2:tick() print('t2 fired at', os.clock() - start) end @@ -37,7 +37,7 @@ end -- then the t1 callback message before the Timer(5) completion message. print('Timer(5) waiting') start = os.clock() -timers.Timer:new(5, 'wait') +timers.Timer(5, 'wait') print(string.format('Timer(5) waited %f seconds', os.clock() - start)) -- This test demonstrates a repeating timer. It also shows that you can (but @@ -50,7 +50,7 @@ print(string.format('Timer(5) waited %f seconds', os.clock() - start)) -- it's worth knowing that a coroutine timer callback can be used to manage -- more complex control flows. start = os.clock() -timers.Timer:new( +timers.Timer( 2, coroutine.wrap(function() for i = 1,5 do diff --git a/indra/newview/scripts/lua/timers.lua b/indra/newview/scripts/lua/timers.lua index e0d27a680d..e4938078dc 100644 --- a/indra/newview/scripts/lua/timers.lua +++ b/indra/newview/scripts/lua/timers.lua @@ -1,6 +1,7 @@ -- Access to the viewer's time-delay facilities local leap = require 'leap' +local util = require 'util' local timers = {} @@ -78,6 +79,8 @@ function timers.Timer:new(delay, callback, iterate) return obj end +util.classctor(timers.Timer) + function timers.Timer:tick() error('Pass a callback to Timer:new(), or override Timer:tick()') end diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua index a2191288f6..bfbfc8637c 100644 --- a/indra/newview/scripts/lua/util.lua +++ b/indra/newview/scripts/lua/util.lua @@ -2,6 +2,31 @@ local util = {} +-- Allow MyClass(ctor args...) equivalent to MyClass:new(ctor args...) +-- Usage: +-- local MyClass = {} +-- function MyClass:new(...) +-- ... +-- end +-- ... +-- util.classctor(MyClass) +-- or if your constructor is named something other than MyClass:new(), e.g. +-- MyClass:construct(): +-- util.classctor(MyClass, MyClass.construct) +-- return MyClass +function util.classctor(class, ctor) + -- get the metatable for the passed class + local mt = getmetatable(class) + if mt == nil then + -- if it doesn't already have a metatable, then create one + mt = {} + setmetatable(class, mt) + end + -- now that class has a metatable, set its __call method to the specified + -- constructor method (class.new if not specified) + mt.__call = ctor or class.new +end + -- check if array-like table contains certain value function util.contains(t, v) return table.find(t, v) ~= nil -- cgit v1.2.3 From f2020bff30808d28aec06cce5fed61717fcde7fc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 21:50:35 -0400 Subject: Fix a couple bugs in startup.lua. The 'startup' table, the module's namespace, must be defined near the top because its local waitfor:process() override references startup. The byname table's metatable's __index() function wants to raise an error if you try to access an undefined entry, but it referenced t[k] to check that, producing infinite recursion. Use rawget(t, k) instead. Also use new leap.WaitFor(args) syntax instead of leap.WaitFor:new(args). --- indra/newview/scripts/lua/startup.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/startup.lua b/indra/newview/scripts/lua/startup.lua index 4311bb9a60..c3040f94b8 100644 --- a/indra/newview/scripts/lua/startup.lua +++ b/indra/newview/scripts/lua/startup.lua @@ -12,6 +12,8 @@ local function dbg(...) end -- local dbg = require 'printf' -- --------------------------------------------------------------------------- +local startup = {} + -- Get the list of startup states from the viewer. local bynum = leap.request('LLStartUp', {op='getStateTable'})['table'] @@ -19,7 +21,7 @@ local byname = setmetatable( {}, -- set metatable to throw an error if you look up invalid state name {__index=function(t, k) - local v = t[k] + local v = rawget(t, k) if v then return v end @@ -35,7 +37,7 @@ end -- specialize a WaitFor to track the viewer's startup state local startup_pump = 'StartupState' -local waitfor = leap.WaitFor:new(0, startup_pump) +local waitfor = leap.WaitFor(0, startup_pump) function waitfor:filter(pump, data) if pump == self.name then return data @@ -57,8 +59,6 @@ leap.request(leap.cmdpump(), leap.send('LLStartUp', {op='postStartupState'}) -- --------------------------------------------------------------------------- -startup = {} - -- wait for response from postStartupState while not startup._state do dbg('startup.state() waiting for first StartupState event') @@ -98,4 +98,3 @@ function startup.wait(state) end return startup - -- cgit v1.2.3 From 44182d0719c209aabe0d80aea291a9e3e45b1e59 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 21:59:31 -0400 Subject: Add to UI.lua a set of 'LLWindow' listener operations. Add listviews(), viewinfo(), click(), doubleclick(), drag(), keypress() and type(). WIP: These are ported from Python LEAP equivalents, but the Lua implementation has only been partially tested. --- indra/newview/scripts/lua/UI.lua | 113 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/UI.lua b/indra/newview/scripts/lua/UI.lua index 24f822bbd9..eb1a4017c7 100644 --- a/indra/newview/scripts/lua/UI.lua +++ b/indra/newview/scripts/lua/UI.lua @@ -1,9 +1,14 @@ --- Engage the UI LLEventAPI +-- Engage the viewer's UI -leap = require 'leap' +local leap = require 'leap' +local Timer = (require 'timers').Timer +local mapargs = require 'mapargs' local UI = {} +-- *************************************************************************** +-- registered menu actions +-- *************************************************************************** function UI.call(func, parameter) -- 'call' is fire-and-forget leap.request('UI', {op='call', ['function']=func, parameter=parameter}) @@ -13,4 +18,108 @@ function UI.getValue(path) return leap.request('UI', {op='getValue', path=path})['value'] end +-- *************************************************************************** +-- UI views +-- *************************************************************************** +-- Either: +-- wreq{op='Something', a=1, b=2, ...} +-- or: +-- (args should be local, as this wreq() call modifies it) +-- local args = {a=1, b=2, ...} +-- wreq('Something', args) +local function wreq(op_or_data, data_if_op) + if data_if_op ~= nil then + -- this is the wreq(op, data) form + data_if_op.op = op_or_data + op_or_data = data_if_op + end + return leap.request('LLWindow', op_or_data) +end + +-- omit 'parent' to list all view paths +function UI.listviews(parent) + return wreq{op='getPaths', under=parent} +end + +function UI.viewinfo(path) + return wreq{op='getInfo', path=path} +end + +-- *************************************************************************** +-- mouse actions +-- *************************************************************************** +-- pass a table: +-- UI.click{path=path +-- [, button='LEFT' | 'CENTER' | 'RIGHT'] +-- [, x=x, y=y] +-- [, hold=duration]} +function UI.click(...) + local args = mapargs('path,button,x,y,hold', ...) + args.button = args.button or 'LEFT' + local hold = args.hold or 1.0 + wreq('mouseMove', args) + wreq('mouseDown', args) + Timer(hold, 'wait') + wreq('mouseUp', args) +end + +-- pass a table as for UI.click() +function UI.doubleclick(...) + local args = mapargs('path,button,x,y', ...) + args.button = args.button or 'LEFT' + wreq('mouseDown', args) + wreq('mouseUp', args) + wreq('mouseDown', args) + wreq('mouseUp', args) +end + +-- UI.drag{path=, xoff=, yoff=} +function UI.drag(...) + local args = mapargs('path,xoff,yoff', ...) + -- query the specified path + local rect = UI.viewinfo(args.path).rect + local centerx = math.floor(rect.left + (rect.right - rect.left)/2) + local centery = math.floor(rect.bottom + (rect.top - rect.bottom)/2) + wreq{op='mouseMove', path=args.path, x=centerx, y=centery} + wreq{op='mouseDown', path=args.path, button='LEFT'} + wreq{op='mouseMove', path=args.path, x=centerx + args.xoff, y=centery + args.yoff} + wreq{op='mouseUp', path=args.path, button='LEFT'} +end + +-- *************************************************************************** +-- keyboard actions +-- *************************************************************************** +-- pass a table: +-- UI.keypress{ +-- [path=path] -- if omitted, default input field +-- [, char='x'] -- requires one of char, keycode, keysym +-- [, keycode=120] +-- keysym per https://github.com/secondlife/viewer/blob/main/indra/llwindow/llkeyboard.cpp#L68-L124 +-- [, keysym='Enter'] +-- [, mask={'SHIFT', 'CTL', 'ALT', 'MAC_CONTROL'}] -- some subset of these +-- } +function UI.keypress(...) + local args = mapargs('path,char,keycode,keysym,mask', ...) + if args.char == '\n' then + args.char = nil + args.keysym = 'Enter' + end + return wreq('keyDown', args) +end + +-- UI.type{text=, path=} +function UI.type(...) + local args = mapargs('text,path', ...) + if #args.text > 0 then + -- The caller's path may be specified in a way that requires recursively + -- searching parts of the LLView tree. No point in doing that more than + -- once. Capture the actual path found by that first call and use that for + -- subsequent calls. + local path = UI.keypress{path=args.path, char=string.sub(args.text, 1, 1)}.path + for i = 2, #args.text do + UI.keypress{path=path, char=string.sub(args.text, i, i)} + end + end +end + return UI -- cgit v1.2.3 From beb28c4351f3ef622c45f3603df0ba9c5e162793 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 22:01:40 -0400 Subject: Add login.lua module with login() function. The nullary login() call (login with saved credentials) has been tested, but the binary login(username, password) call is known not to work yet. --- indra/newview/scripts/lua/login.lua | 19 +++++++++++++++++++ indra/newview/scripts/lua/test_login.lua | 7 +++++++ 2 files changed, 26 insertions(+) create mode 100644 indra/newview/scripts/lua/login.lua create mode 100644 indra/newview/scripts/lua/test_login.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/login.lua b/indra/newview/scripts/lua/login.lua new file mode 100644 index 0000000000..0d8591cace --- /dev/null +++ b/indra/newview/scripts/lua/login.lua @@ -0,0 +1,19 @@ +local UI = require 'UI' +local leap = require 'leap' + +local function login(username, password) + if username and password then + local userpath = '//username_combo/Combo Text Entry' + local passpath = '//password_edit' + -- first clear anything presently in those text fields + for _, path in pairs({userpath, passpath}) do + UI.click(path) + UI.keypress{keysym='Backsp', path=path} + end + UI.type{path=userpath, text=username} + UI.type{path=passpath, text=password} + end + leap.send('LLPanelLogin', {op='onClickConnect'}) +end + +return login diff --git a/indra/newview/scripts/lua/test_login.lua b/indra/newview/scripts/lua/test_login.lua new file mode 100644 index 0000000000..6df52b08c2 --- /dev/null +++ b/indra/newview/scripts/lua/test_login.lua @@ -0,0 +1,7 @@ +startup = require 'startup' +login = require 'login' + +startup.wait('STATE_LOGIN_WAIT') +login() +-- WIP: not working as of 2024-06-11 +-- login('My Username', 'password') -- cgit v1.2.3 From f95dc89d5e7481f4e02953617ce7a13feb87d27a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 11 Jun 2024 22:05:00 -0400 Subject: Add popup.lua, a preliminary API for viewer notifications. WIP: This is known not to work yet. --- indra/newview/scripts/lua/popup.lua | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 indra/newview/scripts/lua/popup.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/popup.lua b/indra/newview/scripts/lua/popup.lua new file mode 100644 index 0000000000..65b04b513e --- /dev/null +++ b/indra/newview/scripts/lua/popup.lua @@ -0,0 +1,32 @@ +leap = require 'leap' + +-- notification is any name defined in notifications.xml as +-- <notification name=> +-- vars is a table providing values for [VAR] substitution keys in the +-- notification body. +local popup_meta = { + -- setting this function as getmetatable(popup).__call() means this gets + -- called when a consumer calls popup(notification, vars, payload) + __call = function(self, notification, vars, payload) + return leap.request('LLNotifications', + {op='requestAdd', name=notification, + substitutions=vars, + payload=payload or {}}) + end +} + +local popup = setmetatable({}, popup_meta) + +function popup:alert(message) + return self('GenericAlert', {MESSAGE=message}) +end + +function popup:alertOK(message) + return self('GenericAlertOK', {MESSAGE=message}) +end + +function popup:alertYesCancel(message) + return self('GenericAlertYesCancel', {MESSAGE=message}) +end + +return popup -- cgit v1.2.3 From c10e785e338aa63165c614d926ce882f4f116716 Mon Sep 17 00:00:00 2001 From: AiraYumi <aira.youme@airanyumi.net> Date: Tue, 11 Jun 2024 14:06:54 +0900 Subject: Replace LL_X11 and LL_FLTK to LL_LINUX --- indra/newview/lldirpicker.cpp | 12 ++++++------ indra/newview/lldirpicker.h | 2 +- indra/newview/llfilepicker.cpp | 6 +++--- indra/newview/llfilepicker.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 75875551f4..957bd6a4d3 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -41,7 +41,7 @@ # include "llfilepicker.h" #endif -#ifdef LL_FLTK +#ifdef LL_LINUX #include "FL/Fl.H" #include "FL/Fl_Native_File_Chooser.H" #endif @@ -197,7 +197,7 @@ LLDirPicker::LLDirPicker() : mFileName(NULL), mLocked(false) { -#ifndef LL_FLTK +#ifndef LL_LINUX mFilePicker = new LLFilePicker(); #endif reset(); @@ -205,7 +205,7 @@ LLDirPicker::LLDirPicker() : LLDirPicker::~LLDirPicker() { -#ifndef LL_FLTK +#ifndef LL_LINUX delete mFilePicker; #endif } @@ -213,7 +213,7 @@ LLDirPicker::~LLDirPicker() void LLDirPicker::reset() { -#ifndef LL_FLTK +#ifndef LL_LINUX if (mFilePicker) mFilePicker->reset(); #else @@ -231,7 +231,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) return FALSE; } -#ifdef LL_FLTK +#ifdef LL_LINUX gViewerWindow->getWindow()->beforeDialog(); Fl_Native_File_Chooser flDlg; flDlg.title(LLTrans::getString("choose_the_directory").c_str()); @@ -254,7 +254,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) std::string LLDirPicker::getDirName() { -#ifndef LL_FLTK +#ifndef LL_LINUX if (mFilePicker) { return mFilePicker->getFirstFile(); diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index bcc7792c1a..5a3316d500 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -80,7 +80,7 @@ private: #if LL_LINUX || LL_DARWIN // On Linux we just implement LLDirPicker on top of LLFilePicker -#ifndef LL_FLTK +#ifndef LL_LINUX LLFilePicker *mFilePicker; #endif #endif diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index d6f3727643..5be987f92a 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -40,7 +40,7 @@ #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers #endif // LL_SDL -#ifdef LL_FLTK +#ifdef LL_LINUX #include "FL/Fl.H" #include "FL/Fl_Native_File_Chooser.H" #endif @@ -1101,7 +1101,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, #elif LL_LINUX -#if LL_FLTK +#if LL_LINUX BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, const std::string& filename, @@ -1410,7 +1410,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, return FALSE; } -#endif // LL_FLTK +#endif // LL_LINUX #else // not implemented diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 1ca4137ac6..ddf3d7ca16 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -172,7 +172,7 @@ private: void *userdata); #endif -#if LL_FLTK +#if LL_LINUX enum EType { eSaveFile, eOpenFile, eOpenMultiple -- cgit v1.2.3 From 241156cf9831e30a3bbb529478e73aaf233a759b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 12 Jun 2024 16:45:35 -0400 Subject: Make popup() directly pass payload. The expression (payload or {}) is unnecessary, since that value will be converted to LLSD -- and both Lua nil and empty table convert to LLSD::isUndefined(). --- indra/newview/scripts/lua/popup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/popup.lua b/indra/newview/scripts/lua/popup.lua index 65b04b513e..9eecc46753 100644 --- a/indra/newview/scripts/lua/popup.lua +++ b/indra/newview/scripts/lua/popup.lua @@ -11,7 +11,7 @@ local popup_meta = { return leap.request('LLNotifications', {op='requestAdd', name=notification, substitutions=vars, - payload=payload or {}}) + payload=payload}) end } -- cgit v1.2.3 From 52ff9dfe404e4a49ac43185004218ce4e50e2971 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 12 Jun 2024 16:49:19 -0400 Subject: For a single string concatenation, use operator+(). stringize() constructs, populates and destroys a std::ostringstream, which is actually less efficient than directly allocating a std::string big enough for the result of operator+(). Maybe someday we'll specialize stringize(p0, p1) for the case in which they're both string-like, and invoke operator+() for that situation... --- indra/newview/llluamanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 97779a12ad..6f72eb4142 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -254,7 +254,7 @@ void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_r if (shortchunk.length() > shortlen) shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); - std::string desc{ stringize("lua: ", shortchunk) }; + std::string desc{ "lua: " + shortchunk }; LLCoros::instance().launch(desc, [&L, desc, chunk, cb]() { auto [count, result] = L.expr(desc, chunk); -- cgit v1.2.3 From 2ad31a8316c56edfcd78ce494edfcd98209a2cfa Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 12 Jun 2024 16:59:05 -0400 Subject: Defend LLFloaterLUADebug against recursive calls to handlers. The special case of a Lua snippet that indirectly invokes the "LLNotifications" listener can result in a recursive call to LLFloaterLUADebug's handler methods. Defend against that case. --- indra/newview/llfloaterluadebug.cpp | 24 ++++++++++++++++++++++++ indra/newview/llfloaterluadebug.h | 1 + 2 files changed, 25 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 60571d6247..6da28aef5e 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -41,6 +41,7 @@ #include "llsdutil.h" #include "lua_function.h" #include "stringize.h" +#include "tempset.h" LLFloaterLUADebug::LLFloaterLUADebug(const LLSD &key) @@ -77,6 +78,17 @@ LLFloaterLUADebug::~LLFloaterLUADebug() void LLFloaterLUADebug::onExecuteClicked() { + // Empirically, running Lua code that indirectly invokes the + // "LLNotifications" listener can result (via mysterious labyrinthine + // viewer UI byways) in a recursive call to this handler. We've seen Bad + // Things happen to the viewer with a second call to runScriptLine() with + // the same cmd on the same LuaState. + if (mExecuting) + { + LL_DEBUGS("Lua") << "recursive call to onExecuteClicked()" << LL_ENDL; + return; + } + TempSet executing(mExecuting, true); mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); @@ -94,6 +106,12 @@ void LLFloaterLUADebug::onBtnBrowse() void LLFloaterLUADebug::onBtnRun() { + if (mExecuting) + { + LL_DEBUGS("Lua") << "recursive call to onBtnRun()" << LL_ENDL; + return; + } + TempSet executing(mExecuting, true); std::vector<std::string> filenames; std::string filepath = mScriptPath->getText(); if (!filepath.empty()) @@ -105,6 +123,12 @@ void LLFloaterLUADebug::onBtnRun() void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames) { + if (mExecuting) + { + LL_DEBUGS("Lua") << "recursive call to runSelectedScript()" << LL_ENDL; + return; + } + TempSet executing(mExecuting, true); mResultOutput->setValue(""); std::string filepath = filenames[0]; diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 7418174570..4d9e2fabca 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -66,6 +66,7 @@ private: LLLineEditor* mLineInput; LLLineEditor* mScriptPath; LuaState mState; + bool mExecuting{ false }; }; #endif // LL_LLFLOATERLUADEBUG_H -- cgit v1.2.3 From 6f50aa0e87804ceebce93e29dba4ce073c70cb62 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 12 Jun 2024 17:22:18 -0400 Subject: Provide LUA Debug Console feedback for user typing LUA string. When the user explicitly types 'return expression[, expression]...' we convert the result of the expressions to LLSD and format them into the LUA Debug Console, which serves as a useful acknowledgment. But until now, if the user neither invoked print() nor ran a 'return' statement, the LUA Debug Console output remained empty. This could be a little disconcerting: you click Execute, or press Enter, and apparently nothing happens. You must either monitor viewer log output, or simply trust that the Lua snippet ran. When there are no 'return' results, at least emit 'ok'. But when the user is entering a series of no-output commands, vary the 'ok' output by appending a counter: 'ok 1', 'ok 2' etc. --- indra/newview/llfloaterluadebug.cpp | 8 +++++++- indra/newview/llfloaterluadebug.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 6da28aef5e..f715327ec8 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -153,13 +153,19 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) mResultOutput->endOfDoc(); return; } + if (count == 0) + { + // no results + mResultOutput->pasteTextWithLinebreaks(stringize("ok ", ++mAck)); + return; + } if (count == 1) { // single result mResultOutput->pasteTextWithLinebreaks(stringize(result)); return; } - // 0 or multiple results + // multiple results const char* sep = ""; for (const auto& item : llsd::inArray(result)) { diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 4d9e2fabca..ae30b7cf25 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -66,6 +66,7 @@ private: LLLineEditor* mLineInput; LLLineEditor* mScriptPath; LuaState mState; + U32 mAck{ 0 }; bool mExecuting{ false }; }; -- cgit v1.2.3 From 7603ba216f35b44327c7fe9ed0a77d69356e0395 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 12 Jun 2024 17:32:51 -0400 Subject: Avoid messing up Lua's global namespace in 'require' modules. --- indra/newview/scripts/lua/LLChat.lua | 2 +- indra/newview/scripts/lua/LLDebugSettings.lua | 2 +- indra/newview/scripts/lua/LLFloaterAbout.lua | 2 +- indra/newview/scripts/lua/LLGesture.lua | 2 +- indra/newview/scripts/lua/popup.lua | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/LLChat.lua b/indra/newview/scripts/lua/LLChat.lua index 7db538e837..78dca765e8 100644 --- a/indra/newview/scripts/lua/LLChat.lua +++ b/indra/newview/scripts/lua/LLChat.lua @@ -1,4 +1,4 @@ -leap = require 'leap' +local leap = require 'leap' local LLChat = {} diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index c250019a00..cff1a63c21 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,4 +1,4 @@ -leap = require 'leap' +local leap = require 'leap' local LLDebugSettings = {} diff --git a/indra/newview/scripts/lua/LLFloaterAbout.lua b/indra/newview/scripts/lua/LLFloaterAbout.lua index 44afee2e5c..a6e42d364f 100644 --- a/indra/newview/scripts/lua/LLFloaterAbout.lua +++ b/indra/newview/scripts/lua/LLFloaterAbout.lua @@ -1,6 +1,6 @@ -- Engage the LLFloaterAbout LLEventAPI -leap = require 'leap' +local leap = require 'leap' local LLFloaterAbout = {} diff --git a/indra/newview/scripts/lua/LLGesture.lua b/indra/newview/scripts/lua/LLGesture.lua index cb410446d7..343b611e2c 100644 --- a/indra/newview/scripts/lua/LLGesture.lua +++ b/indra/newview/scripts/lua/LLGesture.lua @@ -1,6 +1,6 @@ -- Engage the LLGesture LLEventAPI -leap = require 'leap' +local leap = require 'leap' local LLGesture = {} diff --git a/indra/newview/scripts/lua/popup.lua b/indra/newview/scripts/lua/popup.lua index 9eecc46753..8a01ab7836 100644 --- a/indra/newview/scripts/lua/popup.lua +++ b/indra/newview/scripts/lua/popup.lua @@ -1,4 +1,4 @@ -leap = require 'leap' +local leap = require 'leap' -- notification is any name defined in notifications.xml as -- <notification name=> -- cgit v1.2.3 From 81a153da87f56e4db0a38ebb94a9c72471e0b002 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 14 Jun 2024 15:39:35 +0300 Subject: Add nearby chat listener --- indra/newview/llfloaterimnearbychatlistener.cpp | 40 ++++++++++++++++++++++ indra/newview/llfloaterimnearbychatlistener.h | 7 ++++ indra/newview/llluamanager.cpp | 2 +- indra/newview/llviewermessage.cpp | 5 +++ indra/newview/scripts/lua/LLChatListener.lua | 41 +++++++++++++++++++++++ indra/newview/scripts/lua/test_LLChatListener.lua | 27 +++++++++++++++ 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 indra/newview/scripts/lua/LLChatListener.lua create mode 100644 indra/newview/scripts/lua/test_LLChatListener.lua (limited to 'indra/newview') diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index 0618741cc4..78642bce21 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -33,6 +33,7 @@ #include "llagent.h" #include "llchat.h" +#include "llluamanager.h" #include "llviewercontrol.h" #include "stringize.h" @@ -49,6 +50,35 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() "[\"channel\"] chat channel number [default = 0]\n" "[\"type\"] chat type \"whisper\", \"normal\", \"shout\" [default = \"normal\"]", &LLFloaterIMNearbyChatListener::sendChat); + + add("listen", + "Start listening to the Nearby chat, chat messages will be resent to the script event pump", + &LLFloaterIMNearbyChatListener::listenChat, + llsd::map("coro_name", LLSD(), "reply", LLSD())); + + add("stopListening", + "Stop listening to the Nearby chat", + &LLFloaterIMNearbyChatListener::stopListeningChat, + llsd::map("coro_name", LLSD())); + + mOutConnection = LLEventPumps::instance().obtain("LLNearbyChat").listen("LLFloaterIMNearbyChatListener", [this](const LLSD &data) + { + std::map<std::string, std::string> reply_pumps = mReplyPumps; + std::map<std::string, std::string> scripts = LLLUAmanager::getScriptNames(); + for (auto &it : reply_pumps) + { + //check if listener script is still running + if (scripts.find(it.first) != scripts.end()) + { + LLEventPumps::instance().obtain(it.second).post(data); + } + else + { + mReplyPumps.erase(it.first); + } + } + return false; + }); } @@ -103,3 +133,13 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) gSavedSettings.getBOOL("PlayChatAnim")); } + +void LLFloaterIMNearbyChatListener::listenChat(LLSD const &chat_data) +{ + mReplyPumps[chat_data["coro_name"].asString()] = chat_data["reply"].asString(); +} + +void LLFloaterIMNearbyChatListener::stopListeningChat(LLSD const &chat_data) +{ + mReplyPumps.erase(chat_data["coro_name"].asString()); +} diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index 18a8bacfaa..a466db8e5f 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -43,7 +43,14 @@ public: private: void sendChat(LLSD const & chat_data); + void listenChat(LLSD const &chat_data); + void stopListeningChat(LLSD const &chat_data); + F64 mLastThrottleTime{ 0.0 }; + + LLTempBoundListener mOutConnection; + std::map<std::string, std::string> mReplyPumps; + }; #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 97779a12ad..d8e53f3e69 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -128,7 +128,7 @@ lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLSD data{ lua_tollsd(L, 2) }; lua_pop(L, 2); LL_DEBUGS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL; - LLEventPumps::instance().obtain(pumpname).post(data); + LLEventPumps::instance().obtain(pumpname).post(data.with("coro_name", LLCoros::getName())); return 0; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 01d4695eda..26b088e390 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2749,6 +2749,11 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) msg_notify["from_id"] = chat.mFromID; msg_notify["source_type"] = chat.mSourceType; on_new_message(msg_notify); + + + msg_notify["chat_type"] = chat.mChatType; + msg_notify["message"] = mesg; + LLEventPumps::instance().obtain("LLNearbyChat").post(msg_notify); } } diff --git a/indra/newview/scripts/lua/LLChatListener.lua b/indra/newview/scripts/lua/LLChatListener.lua new file mode 100644 index 0000000000..d615ae5dbc --- /dev/null +++ b/indra/newview/scripts/lua/LLChatListener.lua @@ -0,0 +1,41 @@ +local fiber = require 'fiber' +local inspect = require 'inspect' + +local LLChatListener = {} +local waitfor = {} + +function LLChatListener:new() + local obj = setmetatable({}, self) + self.__index = self + obj.name = 'Chat_listener' + + return obj +end + +function LLChatListener:handleMessages(event_data) + --print(inspect(event_data)) + return true +end + +function LLChatListener:start() + waitfor = leap.WaitFor:new(-1, self.name) + function waitfor:filter(pump, data) + return data + end + + fiber.launch(self.name, function() + event = waitfor:wait() + while event and self:handleMessages(event) do + event = waitfor:wait() + end + end) + + leap.send('LLChatBar', {op='listen'}) +end + +function LLChatListener:stop() + leap.send('LLChatBar', {op='stopListening'}) + waitfor:close() +end + +return LLChatListener diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua new file mode 100644 index 0000000000..2c7b1dc3e5 --- /dev/null +++ b/indra/newview/scripts/lua/test_LLChatListener.lua @@ -0,0 +1,27 @@ +local LLChatListener = require 'LLChatListener' +local LLChat = require 'LLChat' + +function openOrEcho(message) + local floater_name = string.match(message, "^open%s+(%w+)") + if floater_name then + leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) + else + LLChat.sendNearby('Echo: ' .. message) + end +end + +local listener = LLChatListener:new() + +function listener:handleMessages(event_data) + if string.find(event_data.message, '[LUA]') then + return true + elseif event_data.message == 'stop' then + LLChat.sendNearby('Closing echo script.') + return false + else + openOrEcho(event_data.message) + end + return LLChatListener.handleMessages(self, event_data) +end + +listener:start() -- cgit v1.2.3 From f7137765438f149cbae6f3b18da45dce75a25336 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 14 Jun 2024 12:16:12 -0400 Subject: Move Lua modules for 'require' to indra/newview/scripts/lua/require. Make viewer_manifest.py copy them into the viewer install image. Make the require() function look for them there. --- indra/newview/llluamanager.cpp | 4 +- indra/newview/scripts/lua/ErrorQueue.lua | 37 -- indra/newview/scripts/lua/Floater.lua | 146 ------ indra/newview/scripts/lua/LLChat.lua | 17 - indra/newview/scripts/lua/LLDebugSettings.lua | 17 - indra/newview/scripts/lua/LLFloaterAbout.lua | 11 - indra/newview/scripts/lua/LLGesture.lua | 23 - indra/newview/scripts/lua/Queue.lua | 51 -- indra/newview/scripts/lua/UI.lua | 125 ----- indra/newview/scripts/lua/WaitQueue.lua | 88 ---- indra/newview/scripts/lua/coro.lua | 67 --- indra/newview/scripts/lua/fiber.lua | 340 ------------- indra/newview/scripts/lua/inspect.lua | 371 -------------- indra/newview/scripts/lua/leap.lua | 550 --------------------- indra/newview/scripts/lua/printf.lua | 19 - indra/newview/scripts/lua/require/ErrorQueue.lua | 37 ++ indra/newview/scripts/lua/require/Floater.lua | 146 ++++++ indra/newview/scripts/lua/require/LLChat.lua | 17 + .../scripts/lua/require/LLDebugSettings.lua | 17 + .../newview/scripts/lua/require/LLFloaterAbout.lua | 11 + indra/newview/scripts/lua/require/LLGesture.lua | 23 + indra/newview/scripts/lua/require/Queue.lua | 51 ++ indra/newview/scripts/lua/require/UI.lua | 125 +++++ indra/newview/scripts/lua/require/WaitQueue.lua | 88 ++++ indra/newview/scripts/lua/require/coro.lua | 67 +++ indra/newview/scripts/lua/require/fiber.lua | 340 +++++++++++++ indra/newview/scripts/lua/require/inspect.lua | 371 ++++++++++++++ indra/newview/scripts/lua/require/leap.lua | 550 +++++++++++++++++++++ indra/newview/scripts/lua/require/printf.lua | 19 + indra/newview/scripts/lua/require/startup.lua | 100 ++++ indra/newview/scripts/lua/require/timers.lua | 104 ++++ indra/newview/scripts/lua/require/util.lua | 69 +++ indra/newview/scripts/lua/startup.lua | 100 ---- indra/newview/scripts/lua/timers.lua | 104 ---- indra/newview/scripts/lua/util.lua | 69 --- indra/newview/viewer_manifest.py | 4 +- 36 files changed, 2140 insertions(+), 2138 deletions(-) delete mode 100644 indra/newview/scripts/lua/ErrorQueue.lua delete mode 100644 indra/newview/scripts/lua/Floater.lua delete mode 100644 indra/newview/scripts/lua/LLChat.lua delete mode 100644 indra/newview/scripts/lua/LLDebugSettings.lua delete mode 100644 indra/newview/scripts/lua/LLFloaterAbout.lua delete mode 100644 indra/newview/scripts/lua/LLGesture.lua delete mode 100644 indra/newview/scripts/lua/Queue.lua delete mode 100644 indra/newview/scripts/lua/UI.lua delete mode 100644 indra/newview/scripts/lua/WaitQueue.lua delete mode 100644 indra/newview/scripts/lua/coro.lua delete mode 100644 indra/newview/scripts/lua/fiber.lua delete mode 100644 indra/newview/scripts/lua/inspect.lua delete mode 100644 indra/newview/scripts/lua/leap.lua delete mode 100644 indra/newview/scripts/lua/printf.lua create mode 100644 indra/newview/scripts/lua/require/ErrorQueue.lua create mode 100644 indra/newview/scripts/lua/require/Floater.lua create mode 100644 indra/newview/scripts/lua/require/LLChat.lua create mode 100644 indra/newview/scripts/lua/require/LLDebugSettings.lua create mode 100644 indra/newview/scripts/lua/require/LLFloaterAbout.lua create mode 100644 indra/newview/scripts/lua/require/LLGesture.lua create mode 100644 indra/newview/scripts/lua/require/Queue.lua create mode 100644 indra/newview/scripts/lua/require/UI.lua create mode 100644 indra/newview/scripts/lua/require/WaitQueue.lua create mode 100644 indra/newview/scripts/lua/require/coro.lua create mode 100644 indra/newview/scripts/lua/require/fiber.lua create mode 100644 indra/newview/scripts/lua/require/inspect.lua create mode 100644 indra/newview/scripts/lua/require/leap.lua create mode 100644 indra/newview/scripts/lua/require/printf.lua create mode 100644 indra/newview/scripts/lua/require/startup.lua create mode 100644 indra/newview/scripts/lua/require/timers.lua create mode 100644 indra/newview/scripts/lua/require/util.lua delete mode 100644 indra/newview/scripts/lua/startup.lua delete mode 100644 indra/newview/scripts/lua/timers.lua delete mode 100644 indra/newview/scripts/lua/util.lua (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 6f72eb4142..5aa47d7566 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -386,10 +386,10 @@ void LLRequireResolver::findModule() std::vector<fsyspath> lib_paths { - gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"), + gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua", "require"), #ifdef LL_TEST // Build-time tests don't have the app bundle - use source tree. - fsyspath(__FILE__).parent_path() / "scripts" / "lua", + fsyspath(__FILE__).parent_path() / "scripts" / "lua" / "require", #endif }; diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua deleted file mode 100644 index e6e9a5ef48..0000000000 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ /dev/null @@ -1,37 +0,0 @@ --- ErrorQueue isa WaitQueue with the added feature that a producer can push an --- error through the queue. Once that error is dequeued, every consumer will --- raise that error. - -local WaitQueue = require('WaitQueue') -local function dbg(...) end --- local dbg = require('printf') -local util = require('util') - -local ErrorQueue = WaitQueue() - -util.classctor(ErrorQueue) - -function ErrorQueue:Error(message) - -- Setting Error() is a marker, like closing the queue. Once we reach the - -- error, every subsequent Dequeue() call will raise the same error. - dbg('Setting self._closed to %q', message) - self._closed = message - self:_wake_waiters() -end - -function ErrorQueue:Dequeue() - local value = WaitQueue.Dequeue(self) - dbg('ErrorQueue:Dequeue: base Dequeue() got %s', value) - if value ~= nil then - -- queue not yet closed, show caller - return value - end - if self._closed == true then - -- WaitQueue:close() sets true: queue has only been closed, tell caller - return nil - end - -- self._closed is a message set by Error() - error(self._closed) -end - -return ErrorQueue diff --git a/indra/newview/scripts/lua/Floater.lua b/indra/newview/scripts/lua/Floater.lua deleted file mode 100644 index d057a74386..0000000000 --- a/indra/newview/scripts/lua/Floater.lua +++ /dev/null @@ -1,146 +0,0 @@ --- Floater base class - -local leap = require 'leap' -local fiber = require 'fiber' -local util = require 'util' - --- list of all the events that a LLLuaFloater might send -local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events -local event_set = {} -for _, event in pairs(event_list) do - event_set[event] = true -end - -local function _event(event_name) - if not event_set[event_name] then - error("Incorrect event name: " .. event_name, 3) - end - return event_name -end - --- --------------------------------------------------------------------------- -local Floater = {} - --- Pass: --- relative file path to floater's XUI definition file --- optional: sign up for additional events for defined control --- {<control_name>={action1, action2, ...}} -function Floater:new(path, extra) - local obj = setmetatable({}, self) - self.__index = self - - local path_parts = string.split(path, '/') - obj.name = 'Floater ' .. path_parts[#path_parts] - - obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)} - if extra then - -- validate each of the actions for each specified control - for control, actions in pairs(extra) do - for _, action in pairs(actions) do - _event(action) - end - end - obj._command.extra_events = extra - end - - return obj -end - -util.classctor(Floater) - -function Floater:show() - -- leap.eventstream() returns the first response, and launches a - -- background fiber to call the passed callback with all subsequent - -- responses. - local event = leap.eventstream( - 'LLFloaterReg', - self._command, - -- handleEvents() returns false when done. - -- eventstream() expects a true return when done. - function(event) return not self:handleEvents(event) end) - self._pump = event.command_name - -- we might need the returned reqid to cancel the eventstream() fiber - self.reqid = event.reqid - - -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if - -- subclass has a post_build() method. Honor the convention that if - -- handleEvents() returns false, we're done. - if not self:handleEvents(event) then - return - end -end - -function Floater:post(action) - leap.send(self._pump, action) -end - -function Floater:request(action) - return leap.request(self._pump, action) -end - --- local inspect = require 'inspect' - -function Floater:handleEvents(event_data) - local event = event_data.event - if event_set[event] == nil then - LL.print_warning(string.format('%s received unknown event %q', self.name, event)) - end - - -- Before checking for a general (e.g.) commit() method, first look for - -- commit_ctrl_name(): in other words, concatenate the event name with the - -- ctrl_name, with an underscore between. If there exists such a specific - -- method, call that. - local handler, ret - if event_data.ctrl_name then - local specific = event .. '_' .. event_data.ctrl_name - handler = self[specific] - if handler then - ret = handler(self, event_data) - -- Avoid 'return ret or true' because we explicitly want to allow - -- the handler to return false. - if ret ~= nil then - return ret - else - return true - end - end - end - - -- No specific "event_on_ctrl()" method found; try just "event()" - handler = self[event] - if handler then - ret = handler(self, event_data) - if ret ~= nil then - return ret - end --- else --- print(string.format('%s ignoring event %s', self.name, inspect(event_data))) - end - - -- We check for event() method before recognizing floater_close in case - -- the consumer needs to react specially to closing the floater. Now that - -- we've checked, recognize it ourselves. Returning false terminates the - -- anonymous fiber function launched by leap.eventstream(). - if event == _event('floater_close') then - LL.print_warning(self.name .. ' closed') - return false - end - return true -end - --- onCtrl() permits a different dispatch style in which the general event() --- method explicitly calls (e.g.) --- self:onCtrl(event_data, { --- ctrl_name=function() --- self:post(...) --- end, --- ... --- }) -function Floater:onCtrl(event_data, ctrl_map) - local handler = ctrl_map[event_data.ctrl_name] - if handler then - handler() - end -end - -return Floater diff --git a/indra/newview/scripts/lua/LLChat.lua b/indra/newview/scripts/lua/LLChat.lua deleted file mode 100644 index 78dca765e8..0000000000 --- a/indra/newview/scripts/lua/LLChat.lua +++ /dev/null @@ -1,17 +0,0 @@ -local leap = require 'leap' - -local LLChat = {} - -function LLChat.sendNearby(msg) - leap.send('LLChatBar', {op='sendChat', message=msg}) -end - -function LLChat.sendWhisper(msg) - leap.send('LLChatBar', {op='sendChat', type='whisper', message=msg}) -end - -function LLChat.sendShout(msg) - leap.send('LLChatBar', {op='sendChat', type='shout', message=msg}) -end - -return LLChat diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua deleted file mode 100644 index cff1a63c21..0000000000 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ /dev/null @@ -1,17 +0,0 @@ -local leap = require 'leap' - -local LLDebugSettings = {} - -function LLDebugSettings.set(name, value) - leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value}) -end - -function LLDebugSettings.toggle(name) - leap.request('LLViewerControl', {op='toggle', group='Global', key=name}) -end - -function LLDebugSettings.get(name) - return leap.request('LLViewerControl', {op='get', group='Global', key=name})['value'] -end - -return LLDebugSettings diff --git a/indra/newview/scripts/lua/LLFloaterAbout.lua b/indra/newview/scripts/lua/LLFloaterAbout.lua deleted file mode 100644 index a6e42d364f..0000000000 --- a/indra/newview/scripts/lua/LLFloaterAbout.lua +++ /dev/null @@ -1,11 +0,0 @@ --- Engage the LLFloaterAbout LLEventAPI - -local leap = require 'leap' - -local LLFloaterAbout = {} - -function LLFloaterAbout.getInfo() - return leap.request('LLFloaterAbout', {op='getInfo'}) -end - -return LLFloaterAbout diff --git a/indra/newview/scripts/lua/LLGesture.lua b/indra/newview/scripts/lua/LLGesture.lua deleted file mode 100644 index 343b611e2c..0000000000 --- a/indra/newview/scripts/lua/LLGesture.lua +++ /dev/null @@ -1,23 +0,0 @@ --- Engage the LLGesture LLEventAPI - -local leap = require 'leap' - -local LLGesture = {} - -function LLGesture.getActiveGestures() - return leap.request('LLGesture', {op='getActiveGestures'})['gestures'] -end - -function LLGesture.isGesturePlaying(id) - return leap.request('LLGesture', {op='isGesturePlaying', id=id})['playing'] -end - -function LLGesture.startGesture(id) - leap.send('LLGesture', {op='startGesture', id=id}) -end - -function LLGesture.stopGesture(id) - leap.send('LLGesture', {op='stopGesture', id=id}) -end - -return LLGesture diff --git a/indra/newview/scripts/lua/Queue.lua b/indra/newview/scripts/lua/Queue.lua deleted file mode 100644 index 5bc72e4057..0000000000 --- a/indra/newview/scripts/lua/Queue.lua +++ /dev/null @@ -1,51 +0,0 @@ --- from https://create.roblox.com/docs/luau/queues#implementing-queues, --- amended per https://www.lua.org/pil/16.1.html - --- While coding some scripting in Lua --- I found that I needed a queua --- I thought of linked list --- But had to resist --- For fear it might be too obscua. - -local util = require 'util' - -local Queue = {} - -function Queue:new() - local obj = setmetatable({}, self) - self.__index = self - - obj._first = 0 - obj._last = -1 - obj._queue = {} - - return obj -end - -util.classctor(Queue) - --- Check if the queue is empty -function Queue:IsEmpty() - return self._first > self._last -end - --- Add a value to the queue -function Queue:Enqueue(value) - local last = self._last + 1 - self._last = last - self._queue[last] = value -end - --- Remove a value from the queue -function Queue:Dequeue() - if self:IsEmpty() then - return nil - end - local first = self._first - local value = self._queue[first] - self._queue[first] = nil - self._first = first + 1 - return value -end - -return Queue diff --git a/indra/newview/scripts/lua/UI.lua b/indra/newview/scripts/lua/UI.lua deleted file mode 100644 index eb1a4017c7..0000000000 --- a/indra/newview/scripts/lua/UI.lua +++ /dev/null @@ -1,125 +0,0 @@ --- Engage the viewer's UI - -local leap = require 'leap' -local Timer = (require 'timers').Timer -local mapargs = require 'mapargs' - -local UI = {} - --- *************************************************************************** --- registered menu actions --- *************************************************************************** -function UI.call(func, parameter) - -- 'call' is fire-and-forget - leap.request('UI', {op='call', ['function']=func, parameter=parameter}) -end - -function UI.getValue(path) - return leap.request('UI', {op='getValue', path=path})['value'] -end - --- *************************************************************************** --- UI views --- *************************************************************************** --- Either: --- wreq{op='Something', a=1, b=2, ...} --- or: --- (args should be local, as this wreq() call modifies it) --- local args = {a=1, b=2, ...} --- wreq('Something', args) -local function wreq(op_or_data, data_if_op) - if data_if_op ~= nil then - -- this is the wreq(op, data) form - data_if_op.op = op_or_data - op_or_data = data_if_op - end - return leap.request('LLWindow', op_or_data) -end - --- omit 'parent' to list all view paths -function UI.listviews(parent) - return wreq{op='getPaths', under=parent} -end - -function UI.viewinfo(path) - return wreq{op='getInfo', path=path} -end - --- *************************************************************************** --- mouse actions --- *************************************************************************** --- pass a table: --- UI.click{path=path --- [, button='LEFT' | 'CENTER' | 'RIGHT'] --- [, x=x, y=y] --- [, hold=duration]} -function UI.click(...) - local args = mapargs('path,button,x,y,hold', ...) - args.button = args.button or 'LEFT' - local hold = args.hold or 1.0 - wreq('mouseMove', args) - wreq('mouseDown', args) - Timer(hold, 'wait') - wreq('mouseUp', args) -end - --- pass a table as for UI.click() -function UI.doubleclick(...) - local args = mapargs('path,button,x,y', ...) - args.button = args.button or 'LEFT' - wreq('mouseDown', args) - wreq('mouseUp', args) - wreq('mouseDown', args) - wreq('mouseUp', args) -end - --- UI.drag{path=, xoff=, yoff=} -function UI.drag(...) - local args = mapargs('path,xoff,yoff', ...) - -- query the specified path - local rect = UI.viewinfo(args.path).rect - local centerx = math.floor(rect.left + (rect.right - rect.left)/2) - local centery = math.floor(rect.bottom + (rect.top - rect.bottom)/2) - wreq{op='mouseMove', path=args.path, x=centerx, y=centery} - wreq{op='mouseDown', path=args.path, button='LEFT'} - wreq{op='mouseMove', path=args.path, x=centerx + args.xoff, y=centery + args.yoff} - wreq{op='mouseUp', path=args.path, button='LEFT'} -end - --- *************************************************************************** --- keyboard actions --- *************************************************************************** --- pass a table: --- UI.keypress{ --- [path=path] -- if omitted, default input field --- [, char='x'] -- requires one of char, keycode, keysym --- [, keycode=120] --- keysym per https://github.com/secondlife/viewer/blob/main/indra/llwindow/llkeyboard.cpp#L68-L124 --- [, keysym='Enter'] --- [, mask={'SHIFT', 'CTL', 'ALT', 'MAC_CONTROL'}] -- some subset of these --- } -function UI.keypress(...) - local args = mapargs('path,char,keycode,keysym,mask', ...) - if args.char == '\n' then - args.char = nil - args.keysym = 'Enter' - end - return wreq('keyDown', args) -end - --- UI.type{text=, path=} -function UI.type(...) - local args = mapargs('text,path', ...) - if #args.text > 0 then - -- The caller's path may be specified in a way that requires recursively - -- searching parts of the LLView tree. No point in doing that more than - -- once. Capture the actual path found by that first call and use that for - -- subsequent calls. - local path = UI.keypress{path=args.path, char=string.sub(args.text, 1, 1)}.path - for i = 2, #args.text do - UI.keypress{path=path, char=string.sub(args.text, i, i)} - end - end -end - -return UI diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua deleted file mode 100644 index 7e10d03295..0000000000 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ /dev/null @@ -1,88 +0,0 @@ --- WaitQueue isa Queue with the added feature that when the queue is empty, --- the Dequeue() operation blocks the calling coroutine until some other --- coroutine Enqueue()s a new value. - -local fiber = require('fiber') -local Queue = require('Queue') -local util = require('util') - -local function dbg(...) end --- local dbg = require('printf') - -local WaitQueue = Queue() - -function WaitQueue:new() - local obj = Queue() - setmetatable(obj, self) - self.__index = self - - obj._waiters = {} - obj._closed = false - return obj -end - -util.classctor(WaitQueue) - -function WaitQueue:Enqueue(value) - if self._closed then - error("can't Enqueue() on closed Queue") - end - -- can't simply call Queue:Enqueue(value)! That calls the method on the - -- Queue class definition, instead of calling Queue:Enqueue() on self. - -- Hand-expand the Queue:Enqueue() syntactic sugar. - Queue.Enqueue(self, value) - self:_wake_waiters() -end - -function WaitQueue:_wake_waiters() - -- WaitQueue is designed to support multi-producer, multi-consumer use - -- cases. With multiple consumers, if more than one is trying to - -- Dequeue() from an empty WaitQueue, we'll have multiple waiters. - -- Unlike OS threads, with cooperative concurrency it doesn't make sense - -- to "notify all": we need wake only one of the waiting Dequeue() - -- callers. - if ((not self:IsEmpty()) or self._closed) and next(self._waiters) then - -- Pop the oldest waiting coroutine instead of the most recent, for - -- more-or-less round robin fairness. But skip any coroutines that - -- have gone dead in the meantime. - local waiter = table.remove(self._waiters, 1) - while waiter and fiber.status(waiter) == "dead" do - waiter = table.remove(self._waiters, 1) - end - -- do we still have at least one waiting coroutine? - if waiter then - -- don't pass the head item: let the resumed coroutine retrieve it - fiber.wake(waiter) - end - end -end - -function WaitQueue:Dequeue() - while self:IsEmpty() do - -- Don't check for closed until the queue is empty: producer can close - -- the queue while there are still items left, and we want the - -- consumer(s) to retrieve those last few items. - if self._closed then - dbg('WaitQueue:Dequeue(): closed') - return nil - end - dbg('WaitQueue:Dequeue(): waiting') - -- add the running coroutine to the list of waiters - dbg('WaitQueue:Dequeue() running %s', tostring(coroutine.running() or 'main')) - table.insert(self._waiters, fiber.running()) - -- then let somebody else run - fiber.wait() - end - -- here we're sure this queue isn't empty - dbg('WaitQueue:Dequeue() calling Queue.Dequeue()') - return Queue.Dequeue(self) -end - -function WaitQueue:close() - self._closed = true - -- close() is like Enqueueing an end marker. If there are waiting - -- consumers, give them a chance to see we're closed. - self:_wake_waiters() -end - -return WaitQueue diff --git a/indra/newview/scripts/lua/coro.lua b/indra/newview/scripts/lua/coro.lua deleted file mode 100644 index 616a797e95..0000000000 --- a/indra/newview/scripts/lua/coro.lua +++ /dev/null @@ -1,67 +0,0 @@ --- Manage Lua coroutines - -local coro = {} - -coro._coros = {} - --- Launch a Lua coroutine: create and resume. --- Returns: new coroutine, values yielded or returned from initial resume() --- If initial resume() encountered an error, propagates the error. -function coro.launch(func, ...) - local co = coroutine.create(func) - table.insert(coro._coros, co) - return co, coro.resume(co, ...) -end - --- resume() wrapper to propagate errors -function coro.resume(co, ...) - -- if there's an idiom other than table.pack() to assign an arbitrary - -- number of return values, I don't yet know it - local ok_result = table.pack(coroutine.resume(co, ...)) - if not ok_result[1] then - -- if [1] is false, then [2] is the error message - error(ok_result[2]) - end - -- ok is true, whew, just return the rest of the values - return table.unpack(ok_result, 2) -end - --- yield to other coroutines even if you don't know whether you're in a --- created coroutine or the main coroutine -function coro.yield(...) - if coroutine.running() then - -- this is a real coroutine, yield normally - return coroutine.yield(...) - else - -- This is the main coroutine: coroutine.yield() doesn't work. - -- But we can take a spin through previously-launched coroutines. - -- Walk a copy of coro._coros in case any of these coroutines launches - -- another: next() forbids creating new entries during traversal. - for co in coro._live_coros_iter, table.clone(coro._coros) do - coro.resume(co) - end - end -end - --- Walk coro._coros table, returning running or suspended coroutines. --- Once a coroutine becomes dead, remove it from _coros and don't return it. -function coro._live_coros() - return coro._live_coros_iter, coro._coros -end - --- iterator function for _live_coros() -function coro._live_coros_iter(t, idx) - local k, co = next(t, idx) - while k and coroutine.status(co) == 'dead' do --- t[k] = nil - -- See coro.yield(): sometimes we traverse a copy of _coros, but if we - -- discover a dead coroutine in that copy, delete it from _coros - -- anyway. Deleting it from a temporary copy does nothing. - coro._coros[k] = nil - coroutine.close(co) - k, co = next(t, k) - end - return co -end - -return coro diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua deleted file mode 100644 index cae27b936b..0000000000 --- a/indra/newview/scripts/lua/fiber.lua +++ /dev/null @@ -1,340 +0,0 @@ --- Organize Lua coroutines into fibers. - --- In this usage, the difference between coroutines and fibers is that fibers --- have a scheduler. Yielding a fiber means allowing other fibers, plural, to --- run: it's more than just returning control to the specific Lua thread that --- resumed the running coroutine. - --- fiber.launch() creates a new fiber ready to run. --- fiber.status() reports (augmented) status of the passed fiber: instead of --- 'suspended', it returns either 'ready' or 'waiting' --- fiber.yield() allows other fibers to run, but leaves the calling fiber --- ready to run. --- fiber.wait() marks the running fiber not ready, and resumes other fibers. --- fiber.wake() marks the designated suspended fiber ready to run, but does --- not yet resume it. --- fiber.run() runs all current fibers until all have terminated (successfully --- or with an error). - -local printf = require 'printf' -local function dbg(...) end --- local dbg = printf -local coro = require 'coro' - -local fiber = {} - --- The tables in which we track fibers must have weak keys so dead fibers --- can be garbage-collected. -local weak_values = {__mode='v'} -local weak_keys = {__mode='k'} - --- Track each current fiber as being either ready to run or not ready --- (waiting). wait() moves the running fiber from ready to waiting; wake() --- moves the designated fiber from waiting back to ready. --- The ready table is used as a list so yield() can go round robin. -local ready = setmetatable({'main'}, weak_keys) --- The waiting table is used as a set because order doesn't matter. -local waiting = setmetatable({}, weak_keys) - --- Every fiber has a name, for diagnostic purposes. Names must be unique. --- A colliding name will be suffixed with an integer. --- Predefine 'main' with our marker so nobody else claims that name. -local names = setmetatable({main='main'}, weak_keys) -local byname = setmetatable({main='main'}, weak_values) --- each colliding name has its own distinct suffix counter -local suffix = {} - --- Specify a nullary idle() callback to be called whenever there are no ready --- fibers but there are waiting fibers. The idle() callback is responsible for --- changing zero or more waiting fibers to ready fibers by calling --- fiber.wake(), although a given call may leave them all still waiting. --- When there are no ready fibers, it's a good idea for the idle() function to --- return control to a higher-level execution agent. Simply returning without --- changing any fiber's status will spin the CPU. --- The idle() callback can return non-nil to exit fiber.run() with that value. -function fiber._idle() - error('fiber.yield(): you must first call set_idle(nullary idle() function)') -end - -function fiber.set_idle(func) - fiber._idle = func -end - --- Launch a new Lua fiber, ready to run. -function fiber.launch(name, func, ...) - local args = table.pack(...) - local co = coroutine.create(function() func(table.unpack(args)) end) - -- a new fiber is ready to run - table.insert(ready, co) - local namekey = name - while byname[namekey] do - if not suffix[name] then - suffix[name] = 1 - end - suffix[name] += 1 - namekey = name .. tostring(suffix[name]) - end - -- found a namekey not yet in byname: set it - byname[namekey] = co - -- and remember it as this fiber's name - names[co] = namekey --- dbg('launch(%s)', namekey) --- dbg('byname[%s] = %s', namekey, tostring(byname[namekey])) --- dbg('names[%s] = %s', tostring(co), names[co]) --- dbg('ready[-1] = %s', tostring(ready[#ready])) -end - --- for debugging -function format_all() - output = {} - table.insert(output, 'Ready fibers:' .. if next(ready) then '' else ' none') - for _, co in pairs(ready) do - table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co))) - end - table.insert(output, 'Waiting fibers:' .. if next(waiting) then '' else ' none') - for co in pairs(waiting) do - table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co))) - end - return table.concat(output, '\n') -end - -function fiber.print_all() - print(format_all()) -end - --- return either the running coroutine or, if called from the main thread, --- 'main' -function fiber.running() - return coroutine.running() or 'main' -end - --- Query a fiber's name (nil for the running fiber) -function fiber.get_name(co) - return names[co or fiber.running()] or 'unknown' -end - --- Query status of the passed fiber -function fiber.status(co) - local running = coroutine.running() - if (not co) or co == running then - -- silly to ask the status of the running fiber: it's 'running' - return 'running' - end - if co ~= 'main' then - -- for any coroutine but main, consult coroutine.status() - local status = coroutine.status(co) - if status ~= 'suspended' then - return status - end - -- here co is suspended, answer needs further refinement - else - -- co == 'main' - if not running then - -- asking about 'main' from the main fiber - return 'running' - end - -- asking about 'main' from some other fiber, so presumably main is suspended - end - -- here we know co is suspended -- but is it ready to run? - if waiting[co] then - return 'waiting' - end - -- not waiting should imply ready: sanity check - if table.find(ready, co) then - return 'ready' - end - -- Calls within yield() between popping the next ready fiber and - -- re-appending it to the list are in this state. Once we're done - -- debugging yield(), we could reinstate either of the below. --- error(string.format('fiber.status(%s) is stumped', fiber.get_name(co))) --- print(string.format('*** fiber.status(%s) is stumped', fiber.get_name(co))) - return '(unknown)' -end - --- change the running fiber's status to waiting -local function set_waiting() - -- if called from the main fiber, inject a 'main' marker into the list - co = fiber.running() - -- delete from ready list - local i = table.find(ready, co) - if i then - table.remove(ready, i) - end - -- add to waiting list - waiting[co] = true -end - --- Suspend the current fiber until some other fiber calls fiber.wake() on it -function fiber.wait() - dbg('Fiber %q waiting', fiber.get_name()) - set_waiting() - -- now yield to other fibers - fiber.yield() -end - --- Mark a suspended fiber as being ready to run -function fiber.wake(co) - if not waiting[co] then - error(string.format('fiber.wake(%s) but status=%s, ready=%s, waiting=%s', - names[co], fiber.status(co), ready[co], waiting[co])) - end - -- delete from waiting list - waiting[co] = nil - -- add to end of ready list - table.insert(ready, co) - dbg('Fiber %q ready', fiber.get_name(co)) - -- but don't yet resume it: that happens next time we reach yield() -end - --- pop and return the next not-dead fiber in the ready list, or nil if none remain -local function live_ready_iter() - -- don't write: - -- for co in table.remove, ready, 1 - -- because it would keep passing a new second parameter! - for co in function() return table.remove(ready, 1) end do - dbg('%s live_ready_iter() sees %s, status %s', - fiber.get_name(), fiber.get_name(co), fiber.status(co)) - -- keep removing the head entry until we find one that's not dead, - -- discarding any dead coroutines along the way - if co == 'main' or coroutine.status(co) ~= 'dead' then - dbg('%s live_ready_iter() returning %s', - fiber.get_name(), fiber.get_name(co)) - return co - end - end - dbg('%s live_ready_iter() returning nil', fiber.get_name()) - return nil -end - --- prune the set of waiting fibers -local function prune_waiting() - for waiter in pairs(waiting) do - if waiter ~= 'main' and coroutine.status(waiter) == 'dead' then - waiting[waiter] = nil - end - end -end - --- Run other ready fibers, leaving this one ready, returning after a cycle. --- Returns: --- * true, nil if there remain other live fibers, whether ready or waiting, --- but it's our turn to run --- * false, nil if this is the only remaining fiber --- * nil, x if configured idle() callback returns non-nil x -local function scheduler() - dbg('scheduler():\n%s', format_all()) - -- scheduler() is asymmetric because Lua distinguishes the main thread - -- from other coroutines. The main thread can't yield; it can only resume - -- other coroutines. So although an arbitrary coroutine could resume still - -- other arbitrary coroutines, it could NOT resume the main thread because - -- the main thread can't yield. Therefore, scheduler() delegates its real - -- processing to the main thread. If called from a coroutine, pass control - -- back to the main thread. - if coroutine.running() then - -- this is a real coroutine, yield normally to main thread - coroutine.yield() - -- main certainly still exists - return true - end - - -- This is the main fiber: coroutine.yield() doesn't work. - -- Instead, resume each of the ready fibers. - -- Prune the set of waiting fibers after every time fiber business logic - -- runs (i.e. other fibers might have terminated or hit error), such as - -- here on entry. - prune_waiting() - local others, idle_stop - repeat - for co in live_ready_iter do - -- seize the opportunity to make sure the viewer isn't shutting down - LL.check_stop() - -- before we re-append co, is it the only remaining entry? - others = next(ready) - -- co is live, re-append it to the ready list - table.insert(ready, co) - if co == 'main' then - -- Since we know the caller is the main fiber, it's our turn. - -- Tell caller if there are other ready or waiting fibers. - return others or next(waiting) - end - -- not main, but some other ready coroutine: - -- use coro.resume() so we'll propagate any error encountered - coro.resume(co) - prune_waiting() - end - -- Here there are no ready fibers. Are there any waiting fibers? - if not next(waiting) then - return false - end - -- there are waiting fibers: call consumer's configured idle() function - idle_stop = fiber._idle() - if idle_stop ~= nil then - return nil, idle_stop - end - prune_waiting() - -- loop "forever", that is, until: - -- * main is ready, or - -- * there are neither ready fibers nor waiting fibers, or - -- * fiber._idle() returned non-nil - until false -end - --- Let other fibers run. This is useful in either of two cases: --- * fiber.wait() calls this to run other fibers while this one is waiting. --- fiber.yield() (and therefore fiber.wait()) works from the main thread as --- well as from explicitly-launched fibers, without the caller having to --- care. --- * A long-running fiber that doesn't often call fiber.wait() should sprinkle --- in fiber.yield() calls to interleave processing on other fibers. -function fiber.yield() - -- The difference between this and fiber.run() is that fiber.yield() - -- assumes its caller has work to do. yield() returns to its caller as - -- soon as scheduler() pops this fiber from the ready list. fiber.run() - -- continues looping until all other fibers have terminated, or the - -- set_idle() callback tells it to stop. - local others, idle_done = scheduler() - -- scheduler() returns either if we're ready, or if idle_done ~= nil. - if idle_done ~= nil then - -- Returning normally from yield() means the caller can carry on with - -- its pending work. But in this case scheduler() returned because the - -- configured set_idle() function interrupted it -- not because we're - -- actually ready. Don't return normally. - error('fiber.set_idle() interrupted yield() with: ' .. tostring(idle_done)) - end - -- We're ready! Just return to caller. In this situation we don't care - -- whether there are other ready fibers. - dbg('fiber.yield() returning to %s (%sothers are ready)', - fiber.get_name(), ((not others) and "no " or "")) -end - --- Run fibers until all but main have terminated: return nil. --- Or until configured idle() callback returns x ~= nil: return x. -function fiber.run() - -- A fiber calling run() is not also doing other useful work. Remove the - -- calling fiber from the ready list. Otherwise yield() would keep seeing - -- that our caller is ready and return to us, instead of realizing that - -- all coroutines are waiting and call idle(). But don't say we're - -- waiting, either, because then when all other fibers have terminated - -- we'd call idle() forever waiting for something to make us ready again. - local i = table.find(ready, fiber.running()) - if i then - table.remove(ready, i) - end - local others, idle_done - repeat - dbg('%s calling fiber.run() calling scheduler()', fiber.get_name()) - others, idle_done = scheduler() - dbg("%s fiber.run()'s scheduler() returned %s, %s", fiber.get_name(), - tostring(others), tostring(idle_done)) - until (not others) - dbg('%s fiber.run() done', fiber.get_name()) - -- For whatever it's worth, put our own fiber back in the ready list. - table.insert(ready, fiber.running()) - -- Once there are no more waiting fibers, and the only ready fiber is - -- us, return to caller. All previously-launched fibers are done. Possibly - -- the chunk is done, or the chunk may decide to launch a new batch of - -- fibers. - return idle_done -end - -return fiber diff --git a/indra/newview/scripts/lua/inspect.lua b/indra/newview/scripts/lua/inspect.lua deleted file mode 100644 index 9900a0b81b..0000000000 --- a/indra/newview/scripts/lua/inspect.lua +++ /dev/null @@ -1,371 +0,0 @@ -local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table -local inspect = {Options = {}, } - - - - - - - - - - - - - - - - - -inspect._VERSION = 'inspect.lua 3.1.0' -inspect._URL = 'http://github.com/kikito/inspect.lua' -inspect._DESCRIPTION = 'human-readable representations of tables' -inspect._LICENSE = [[ - MIT LICENSE - - Copyright (c) 2022 Enrique García Cota - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]] -inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end }) -inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end }) - -local tostring = tostring -local rep = string.rep -local match = string.match -local char = string.char -local gsub = string.gsub -local fmt = string.format - -local _rawget -if rawget then - _rawget = rawget -else - _rawget = function(t, k) return t[k] end -end - -local function rawpairs(t) - return next, t, nil -end - - - -local function smartQuote(str) - if match(str, '"') and not match(str, "'") then - return "'" .. str .. "'" - end - return '"' .. gsub(str, '"', '\\"') .. '"' -end - - -local shortControlCharEscapes = { - ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", - ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127", -} -local longControlCharEscapes = { ["\127"] = "\127" } -for i = 0, 31 do - local ch = char(i) - if not shortControlCharEscapes[ch] then - shortControlCharEscapes[ch] = "\\" .. i - longControlCharEscapes[ch] = fmt("\\%03d", i) - end -end - -local function escape(str) - return (gsub(gsub(gsub(str, "\\", "\\\\"), - "(%c)%f[0-9]", longControlCharEscapes), - "%c", shortControlCharEscapes)) -end - -local luaKeywords = { - ['and'] = true, - ['break'] = true, - ['do'] = true, - ['else'] = true, - ['elseif'] = true, - ['end'] = true, - ['false'] = true, - ['for'] = true, - ['function'] = true, - ['goto'] = true, - ['if'] = true, - ['in'] = true, - ['local'] = true, - ['nil'] = true, - ['not'] = true, - ['or'] = true, - ['repeat'] = true, - ['return'] = true, - ['then'] = true, - ['true'] = true, - ['until'] = true, - ['while'] = true, -} - -local function isIdentifier(str) - return type(str) == "string" and - not not str:match("^[_%a][_%a%d]*$") and - not luaKeywords[str] -end - -local flr = math.floor -local function isSequenceKey(k, sequenceLength) - return type(k) == "number" and - flr(k) == k and - 1 <= (k) and - k <= sequenceLength -end - -local defaultTypeOrders = { - ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, - ['function'] = 5, ['userdata'] = 6, ['thread'] = 7, -} - -local function sortKeys(a, b) - local ta, tb = type(a), type(b) - - - if ta == tb and (ta == 'string' or ta == 'number') then - return (a) < (b) - end - - local dta = defaultTypeOrders[ta] or 100 - local dtb = defaultTypeOrders[tb] or 100 - - - return dta == dtb and ta < tb or dta < dtb -end - -local function getKeys(t) - - local seqLen = 1 - while _rawget(t, seqLen) ~= nil do - seqLen = seqLen + 1 - end - seqLen = seqLen - 1 - - local keys, keysLen = {}, 0 - for k in rawpairs(t) do - if not isSequenceKey(k, seqLen) then - keysLen = keysLen + 1 - keys[keysLen] = k - end - end - table.sort(keys, sortKeys) - return keys, keysLen, seqLen -end - -local function countCycles(x, cycles) - if type(x) == "table" then - if cycles[x] then - cycles[x] = cycles[x] + 1 - else - cycles[x] = 1 - for k, v in rawpairs(x) do - countCycles(k, cycles) - countCycles(v, cycles) - end - countCycles(getmetatable(x), cycles) - end - end -end - -local function makePath(path, a, b) - local newPath = {} - local len = #path - for i = 1, len do newPath[i] = path[i] end - - newPath[len + 1] = a - newPath[len + 2] = b - - return newPath -end - - -local function processRecursive(process, - item, - path, - visited) - if item == nil then return nil end - if visited[item] then return visited[item] end - - local processed = process(item, path) - if type(processed) == "table" then - local processedCopy = {} - visited[item] = processedCopy - local processedKey - - for k, v in rawpairs(processed) do - processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) - if processedKey ~= nil then - processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) - end - end - - local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) - if type(mt) ~= 'table' then mt = nil end - setmetatable(processedCopy, mt) - processed = processedCopy - end - return processed -end - -local function puts(buf, str) - buf.n = buf.n + 1 - buf[buf.n] = str -end - - - -local Inspector = {} - - - - - - - - - - -local Inspector_mt = { __index = Inspector } - -local function tabify(inspector) - puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level)) -end - -function Inspector:getId(v) - local id = self.ids[v] - local ids = self.ids - if not id then - local tv = type(v) - id = (ids[tv] or 0) + 1 - ids[v], ids[tv] = id, id - end - return tostring(id) -end - -function Inspector:putValue(v) - local buf = self.buf - local tv = type(v) - if tv == 'string' then - puts(buf, smartQuote(escape(v))) - elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or - tv == 'cdata' or tv == 'ctype' then - puts(buf, tostring(v)) - elseif tv == 'table' and not self.ids[v] then - local t = v - - if t == inspect.KEY or t == inspect.METATABLE then - puts(buf, tostring(t)) - elseif self.level >= self.depth then - puts(buf, '{...}') - else - if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end - - local keys, keysLen, seqLen = getKeys(t) - - puts(buf, '{') - self.level = self.level + 1 - - for i = 1, seqLen + keysLen do - if i > 1 then puts(buf, ',') end - if i <= seqLen then - puts(buf, ' ') - self:putValue(t[i]) - else - local k = keys[i - seqLen] - tabify(self) - if isIdentifier(k) then - puts(buf, k) - else - puts(buf, "[") - self:putValue(k) - puts(buf, "]") - end - puts(buf, ' = ') - self:putValue(t[k]) - end - end - - local mt = getmetatable(t) - if type(mt) == 'table' then - if seqLen + keysLen > 0 then puts(buf, ',') end - tabify(self) - puts(buf, '<metatable> = ') - self:putValue(mt) - end - - self.level = self.level - 1 - - if keysLen > 0 or type(mt) == 'table' then - tabify(self) - elseif seqLen > 0 then - puts(buf, ' ') - end - - puts(buf, '}') - end - - else - puts(buf, fmt('<%s %d>', tv, self:getId(v))) - end -end - - - - -function inspect.inspect(root, options) - options = options or {} - - local depth = options.depth or (math.huge) - local newline = options.newline or '\n' - local indent = options.indent or ' ' - local process = options.process - - if process then - root = processRecursive(process, root, {}, {}) - end - - local cycles = {} - countCycles(root, cycles) - - local inspector = setmetatable({ - buf = { n = 0 }, - ids = {}, - cycles = cycles, - depth = depth, - level = 0, - newline = newline, - indent = indent, - }, Inspector_mt) - - inspector:putValue(root) - - return table.concat(inspector.buf) -end - -setmetatable(inspect, { - __call = function(_, root, options) - return inspect.inspect(root, options) - end, -}) - -return inspect diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua deleted file mode 100644 index 82f91ce9e9..0000000000 --- a/indra/newview/scripts/lua/leap.lua +++ /dev/null @@ -1,550 +0,0 @@ --- Lua implementation of LEAP (LLSD Event API Plugin) protocol --- --- This module supports Lua scripts run by the Second Life viewer. --- --- LEAP protocol passes LLSD objects, converted to/from Lua tables, in both --- directions. A typical LLSD object is a map containing keys 'pump' and --- 'data'. --- --- The viewer's Lua post_to(pump, data) function posts 'data' to the --- LLEventPump 'pump'. This is typically used to engage an LLEventAPI method. --- --- Similarly, the viewer gives each Lua script its own LLEventPump with a --- unique name. That name is returned by get_event_pumps(). Every event --- received on that LLEventPump is queued for retrieval by get_event_next(), --- which returns (pump, data): the name of the LLEventPump on which the event --- was received and the received event data. When the queue is empty, --- get_event_next() blocks the calling Lua script until the next event is --- received. --- --- Usage: --- 1. Launch some number of Lua coroutines. The code in each coroutine may --- call leap.send(), leap.request() or leap.generate(). leap.send() returns --- immediately ("fire and forget"). leap.request() blocks the calling --- coroutine until it receives and returns the viewer's response to its --- request. leap.generate() expects an arbitrary number of responses to the --- original request. --- 2. To handle events from the viewer other than direct responses to --- requests, instantiate a leap.WaitFor object with a filter(pump, data) --- override method that returns non-nil for desired events. A coroutine may --- call wait() on any such WaitFor. --- 3. Once the coroutines have been launched, call leap.process() on the main --- coroutine. process() retrieves incoming events from the viewer and --- dispatches them to waiting request() or generate() calls, or to --- appropriate WaitFor instances. process() returns when either --- get_event_next() raises an error or the viewer posts nil to the script's --- reply pump to indicate it's done. --- 4. Alternatively, a running coroutine may call leap.done() to break out of --- leap.process(). process() won't notice until the next event from the --- viewer, though. - -local fiber = require('fiber') -local ErrorQueue = require('ErrorQueue') -local inspect = require('inspect') -local function dbg(...) end --- local dbg = require('printf') -local util = require('util') - -local leap = {} - --- reply: string name of reply LLEventPump. Any events the viewer posts to --- this pump will be queued for get_event_next(). We usually specify it as the --- reply pump for requests to internal viewer services. --- command: string name of command LLEventPump. post_to(command, ...) --- engages LLLeapListener operations such as listening on a specified other --- LLEventPump, etc. -local reply, command = LL.get_event_pumps() --- Dict of features added to the LEAP protocol since baseline implementation. --- Before engaging a new feature that might break an older viewer, we can --- check for the presence of that feature key. This table is solely about the --- LEAP protocol itself, the way we communicate with the viewer. To discover --- whether a given listener exists, or supports a particular operation, use --- command's "getAPI" operation. --- For Lua, command's "getFeatures" operation suffices? --- leap._features = {} - --- Each outstanding request() or generate() call has a corresponding --- WaitForReqid object (later in this module) to handle the --- response(s). If an incoming event contains an echoed ["reqid"] key, --- we can look up the appropriate WaitForReqid object more efficiently --- in a dict than by tossing such objects into the usual waitfors list. --- Note: the ["reqid"] must be unique, otherwise we could end up --- replacing an earlier WaitForReqid object in pending with a --- later one. That means that no incoming event will ever be given to --- the old WaitForReqid object. Any coroutine waiting on the discarded --- WaitForReqid object would therefore wait forever. --- pending is NOT a weak table because the caller of request() or generate() --- never sees the WaitForReqid object. pending holds the only reference, so --- it should NOT be garbage-collected. -local pending = {} --- Our consumer will instantiate some number of WaitFor subclass objects. --- As these are traversed in descending priority order, we must keep --- them in a list. --- Anyone who instantiates a WaitFor subclass object should retain a reference --- to it. Once the consuming script drops the reference, allow Lua to --- garbage-collect the WaitFor despite its entry in waitfors. -local weak_values = {__mode='v'} -local waitfors = setmetatable({}, weak_values) --- It has been suggested that we should use UUIDs as ["reqid"] values, --- since UUIDs are guaranteed unique. However, as the "namespace" for --- ["reqid"] values is our very own reply pump, we can get away with --- an integer. -leap._reqid = 0 --- break leap.process() loop -leap._done = false - --- get the name of the reply pump -function leap.replypump() - return reply -end - --- get the name of the command pump -function leap.cmdpump() - return command -end - --- Fire and forget. Send the specified request LLSD, expecting no reply. --- In fact, should the request produce an eventual reply, it will be --- treated as an unsolicited event. --- --- See also request(), generate(). -function leap.send(pump, data, reqid) - local data = data - if type(data) == 'table' then - data = table.clone(data) - data['reply'] = reply - if reqid ~= nil then - data['reqid'] = reqid - end - end - dbg('leap.send(%s, %s) calling post_on()', pump, data) - LL.post_on(pump, data) -end - --- common setup code shared by request() and generate() -local function requestSetup(pump, data) - -- invent a new, unique reqid - leap._reqid += 1 - local reqid = leap._reqid - -- Instantiate a new WaitForReqid object. The priority is irrelevant - -- because, unlike the WaitFor base class, WaitForReqid does not - -- self-register on our waitfors list. Instead, capture the new - -- WaitForReqid object in pending so dispatch() can find it. - local waitfor = leap.WaitForReqid(reqid) - pending[reqid] = waitfor - -- Pass reqid to send() to stamp it into (a copy of) the request data. - dbg('requestSetup(%s, %s) storing %s', pump, data, waitfor.name) - leap.send(pump, data, reqid) - return reqid, waitfor -end - --- Send the specified request LLSD, expecting exactly one reply. Block --- the calling coroutine until we receive that reply. --- --- Every request() (or generate()) LLSD block we send will get stamped --- with a distinct ["reqid"] value. The requested event API must echo the --- same ["reqid"] field in each reply associated with that request. This way --- we can correctly dispatch interleaved replies from different requests. --- --- If the desired event API doesn't support the ["reqid"] echo convention, --- you should use send() instead -- since request() or generate() would --- wait forever for a reply stamped with that ["reqid"] -- and intercept --- any replies using WaitFor. --- --- Unless the request data already contains a ["reply"] key, we insert --- reply=self.replypump to try to ensure that the expected reply will be --- returned over the socket. --- --- See also send(), generate(). -function leap.request(pump, data) - local reqid, waitfor = requestSetup(pump, data) - dbg('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor)) - local ok, response = pcall(waitfor.wait, waitfor) - dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) - -- kill off temporary WaitForReqid object, even if error - pending[reqid] = nil - if not ok then - error(response) - elseif response.error then - error(response.error) - else - return response - end -end - --- Send the specified request LLSD, expecting an arbitrary number of replies. --- Each one is returned on request. --- --- Usage: --- sequence = leap.generate(pump, data) --- repeat --- response = sequence.next() --- until last(response) --- (last() means whatever test the caller wants to perform on response) --- sequence.done() --- --- See request() remarks about ["reqid"]. --- --- Note: this seems like a prime use case for Lua coroutines. But in a script --- using fibers.lua, a "wild" coroutine confuses the fiber scheduler. If --- generate() were itself a coroutine, it would call WaitForReqid:wait(), --- which would yield -- thereby resuming generate() WITHOUT waiting. -function leap.generate(pump, data, checklast) - -- Invent a new, unique reqid. Arrange to handle incoming events - -- bearing that reqid. Stamp the outbound request with that reqid, and - -- send it. - local reqid, waitfor = requestSetup(pump, data) - return { - next = function() - dbg('leap.generate(%s).next() about to wait on %s', reqid, tostring(waitfor)) - local ok, response = pcall(waitfor.wait, waitfor) - dbg('leap.generate(%s).next() got %s: %s', reqid, ok, response) - if not ok then - error(response) - elseif response.error then - error(response.error) - else - return response - end - end, - done = function() - -- cleanup consists of removing our WaitForReqid from pending - pending[reqid] = nil - end - } -end - --- Send the specified request LLSD, expecting an immediate reply followed by --- an arbitrary number of subsequent replies with the same reqid. Block the --- calling coroutine until the first (immediate) reply, but launch a separate --- fiber on which to call the passed callback with later replies. --- --- Once the callback returns true, the background fiber terminates. -function leap.eventstream(pump, data, callback) - local reqid, waitfor = requestSetup(pump, data) - local response = waitfor:wait() - if response.error then - -- clean up our WaitForReqid - waitfor:close() - error(response.error) - end - -- No error, so far so good: - -- call the callback with the first response just in case - dbg('leap.eventstream(%s): first callback', reqid) - local ok, done = pcall(callback, response) - dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) - if not ok then - -- clean up our WaitForReqid - waitfor:close() - error(done) - end - if done then - return response - end - -- callback didn't throw an error, and didn't say stop, - -- so set up to handle subsequent events - -- TODO: distinguish "daemon" fibers that can be terminated even if waiting - fiber.launch( - pump, - function () - local ok, done - local nth = 1 - repeat - event = waitfor:wait() - if not event then - -- wait() returns nil once the queue is closed (e.g. cancelreq()) - ok, done = true, true - else - nth += 1 - dbg('leap.eventstream(%s): callback %d', reqid, nth) - ok, done = pcall(callback, event) - dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) - end - -- not ok means callback threw an error (caught as 'done') - -- done means callback succeeded but wants to stop - until (not ok) or done - -- once we break this loop, clean up our WaitForReqid - waitfor:close() - if not ok then - -- can't reflect the error back to our caller - LL.print_warning(fiber.get_name() .. ': ' .. done) - end - end) - return response -end - --- we might want to clean up after leap.eventstream() even if the callback has --- not yet returned true -function leap.cancelreq(reqid) - dbg('cancelreq(%s)', reqid) - local waitfor = pending[reqid] - if waitfor ~= nil then - -- close() removes the pending entry and also closes the queue, - -- breaking the background fiber's wait loop. - dbg('cancelreq(%s) canceling %s', reqid, waitfor.name) - waitfor:close() - end -end - -local function cleanup(message) - -- We're done: clean up all pending coroutines. - -- Iterate over copies of the pending and waitfors tables, since the - -- close() operation modifies the real tables. - for i, waitfor in pairs(table.clone(pending)) do - waitfor:close() - end - for i, waitfor in pairs(table.clone(waitfors)) do - waitfor:close() - end -end - --- Handle an incoming (pump, data) event with no recognizable ['reqid'] -local function unsolicited(pump, data) - -- we maintain waitfors in descending priority order, so the first waitfor - -- to claim this event is the one with the highest priority - for i, waitfor in pairs(waitfors) do - dbg('unsolicited() checking %s', waitfor.name) - if waitfor:handle(pump, data) then - return - end - end - LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', - pump, inspect(data))) -end - --- Route incoming (pump, data) event to the appropriate waiting coroutine. -local function dispatch(pump, data) - local reqid = data['reqid'] - -- if the response has no 'reqid', it's not from request() or generate() - if reqid == nil then --- dbg('dispatch() found no reqid; calling unsolicited(%s, %s)', pump, data) - return unsolicited(pump, data) - end - -- have reqid; do we have a WaitForReqid? - local waitfor = pending[reqid] - if waitfor == nil then --- dbg('dispatch() found no WaitForReqid(%s); calling unsolicited(%s, %s)', reqid, pump, data) - return unsolicited(pump, data) - end - -- found the right WaitForReqid object, let it handle the event --- dbg('dispatch() calling %s.handle(%s, %s)', waitfor.name, pump, data) - waitfor:handle(pump, data) -end - --- We configure fiber.set_idle() function. fiber.yield() calls the configured --- idle callback whenever there are waiting fibers but no ready fibers. In --- our case, that means it's time to fetch another incoming viewer event. -fiber.set_idle(function () - -- If someone has called leap.done(), then tell fiber.yield() to break loop. - if leap._done then - cleanup('done') - return 'done' - end - dbg('leap.idle() calling get_event_next()') - local ok, pump, data = pcall(LL.get_event_next) - dbg('leap.idle() got %s: %s, %s', ok, pump, data) - -- ok false means get_event_next() raised a Lua error, pump is message - if not ok then - cleanup(pump) - error(pump) - end - -- data nil means get_event_next() returned (pump, LLSD()) to indicate done - if not data then - cleanup('end') - return 'end' - end - -- got a real pump, data pair - dispatch(pump, data) - -- return to fiber.yield(): any incoming message might result in one or - -- more fibers becoming ready -end) - -function leap.done() - leap._done = true -end - --- called by WaitFor.enable() -local function registerWaitFor(waitfor) - table.insert(waitfors, waitfor) - -- keep waitfors sorted in descending order of specified priority - table.sort(waitfors, - function (lhs, rhs) return lhs.priority > rhs.priority end) -end - --- called by WaitFor.disable() -local function unregisterWaitFor(waitfor) - local i = table.find(waitfors, waitfor) - if i ~= nil then - waitfors[i] = nil - end -end - --- ****************************************************************************** --- WaitFor and friends --- ****************************************************************************** - --- An unsolicited event is handled by the highest-priority WaitFor subclass --- object willing to accept it. If no such object is found, the unsolicited --- event is discarded. --- --- * First, instantiate a WaitFor subclass object to register its interest in --- some incoming event(s). WaitFor instances are self-registering; merely --- instantiating the object suffices. --- * Any coroutine may call a given WaitFor object's wait() method. This blocks --- the calling coroutine until a suitable event arrives. --- * WaitFor's constructor accepts a float priority. Every incoming event --- (other than those claimed by request() or generate()) is passed to each --- extant WaitFor.filter() method in descending priority order. The first --- such filter() to return nontrivial data claims that event. --- * At that point, the blocked wait() call on that WaitFor object returns the --- item returned by filter(). --- * WaitFor contains a queue. Multiple arriving events claimed by that WaitFor --- object's filter() method are added to the queue. Naturally, until the --- queue is empty, calling wait() immediately returns the front entry. --- --- It's reasonable to instantiate a WaitFor subclass whose filter() method --- unconditionally returns the incoming event, and whose priority places it --- last in the list. This object will enqueue every unsolicited event left --- unclaimed by other WaitFor subclass objects. --- --- It's not strictly necessary to associate a WaitFor object with exactly one --- coroutine. You might have multiple "worker" coroutines drawing from the same --- WaitFor object, useful if the work being done per event might itself involve --- "blocking" operations. Or a given coroutine might sample a number of WaitFor --- objects in round-robin fashion... etc. etc. Nonetheless, it's --- straightforward to designate one coroutine for each WaitFor object. - --- --------------------------------- WaitFor --------------------------------- -leap.WaitFor = { _id=0 } - -function leap.WaitFor.tostring(self) - -- Lua (sub)classes have no name; can't prefix with that - return self.name -end - -function leap.WaitFor:new(priority, name) - local obj = setmetatable({__tostring=leap.WaitFor.tostring}, self) - self.__index = self - - obj.priority = priority - if name then - obj.name = name - else - self._id += 1 - obj.name = 'WaitFor' .. self._id - end - obj._queue = ErrorQueue() - obj._registered = false - -- if no priority, then don't enable() - remember 0 is truthy - if priority then - obj:enable() - end - - return obj -end - -util.classctor(leap.WaitFor) - --- Re-enable a disable()d WaitFor object. New WaitFor objects are --- enable()d by default. -function leap.WaitFor:enable() - if not self._registered then - registerWaitFor(self) - self._registered = true - end -end - --- Disable an enable()d WaitFor object. -function leap.WaitFor:disable() - if self._registered then - unregisterWaitFor(self) - self._registered = false - end -end - --- Block the calling coroutine until a suitable unsolicited event (one --- for which filter() returns the event) arrives. -function leap.WaitFor:wait() - dbg('%s about to wait', self.name) - local item = self._queue:Dequeue() - dbg('%s got %s', self.name, item) - return item -end - --- Override filter() to examine the incoming event in whatever way --- makes sense. --- --- Return nil to ignore this event. --- --- To claim the event, return the item you want placed in the queue. --- Typically you'd write: --- return data --- or perhaps --- return {pump=pump, data=data} --- or some variation. -function leap.WaitFor:filter(pump, data) - error('You must override the WaitFor.filter() method') -end - --- called by unsolicited() for each WaitFor in waitfors -function leap.WaitFor:handle(pump, data) - local item = self:filter(pump, data) - dbg('%s.filter() returned %s', self.name, item) - -- if this item doesn't pass the filter, we're not interested - if not item then - return false - end - -- okay, filter() claims this event - self:process(item) - return true -end - --- called by WaitFor:handle() for an accepted event -function leap.WaitFor:process(item) - self._queue:Enqueue(item) -end - --- called by cleanup() at end -function leap.WaitFor:close() - self:disable() - self._queue:close() -end - --- called by leap.process() when get_event_next() raises an error -function leap.WaitFor:exception(message) - LL.print_warning(self.name .. ' error: ' .. message) - self._queue:Error(message) -end - --- ------------------------------ WaitForReqid ------------------------------- -leap.WaitForReqid = leap.WaitFor() - -function leap.WaitForReqid:new(reqid) - -- priority is meaningless, since this object won't be added to the - -- priority-sorted waitfors list. Use the reqid as the debugging name - -- string. - local obj = leap.WaitFor(nil, 'WaitForReqid(' .. reqid .. ')') - setmetatable(obj, self) - self.__index = self - - obj.reqid = reqid - - return obj -end - -util.classctor(leap.WaitForReqid) - -function leap.WaitForReqid:filter(pump, data) - -- Because we expect to directly look up the WaitForReqid object of - -- interest based on the incoming ["reqid"] value, it's not necessary - -- to test the event again. Accept every such event. - return data -end - -function leap.WaitForReqid:close() - -- remove this entry from pending table - pending[self.reqid] = nil - self._queue:close() -end - -return leap diff --git a/indra/newview/scripts/lua/printf.lua b/indra/newview/scripts/lua/printf.lua deleted file mode 100644 index e84b2024df..0000000000 --- a/indra/newview/scripts/lua/printf.lua +++ /dev/null @@ -1,19 +0,0 @@ --- printf(...) is short for print(string.format(...)) - -local inspect = require 'inspect' - -local function printf(format, ...) - -- string.format() only handles numbers and strings. - -- Convert anything else to string using the inspect module. - local args = {} - for _, arg in pairs(table.pack(...)) do - if type(arg) == 'number' or type(arg) == 'string' then - table.insert(args, arg) - else - table.insert(args, inspect(arg)) - end - end - print(string.format(format, table.unpack(args))) -end - -return printf diff --git a/indra/newview/scripts/lua/require/ErrorQueue.lua b/indra/newview/scripts/lua/require/ErrorQueue.lua new file mode 100644 index 0000000000..e6e9a5ef48 --- /dev/null +++ b/indra/newview/scripts/lua/require/ErrorQueue.lua @@ -0,0 +1,37 @@ +-- ErrorQueue isa WaitQueue with the added feature that a producer can push an +-- error through the queue. Once that error is dequeued, every consumer will +-- raise that error. + +local WaitQueue = require('WaitQueue') +local function dbg(...) end +-- local dbg = require('printf') +local util = require('util') + +local ErrorQueue = WaitQueue() + +util.classctor(ErrorQueue) + +function ErrorQueue:Error(message) + -- Setting Error() is a marker, like closing the queue. Once we reach the + -- error, every subsequent Dequeue() call will raise the same error. + dbg('Setting self._closed to %q', message) + self._closed = message + self:_wake_waiters() +end + +function ErrorQueue:Dequeue() + local value = WaitQueue.Dequeue(self) + dbg('ErrorQueue:Dequeue: base Dequeue() got %s', value) + if value ~= nil then + -- queue not yet closed, show caller + return value + end + if self._closed == true then + -- WaitQueue:close() sets true: queue has only been closed, tell caller + return nil + end + -- self._closed is a message set by Error() + error(self._closed) +end + +return ErrorQueue diff --git a/indra/newview/scripts/lua/require/Floater.lua b/indra/newview/scripts/lua/require/Floater.lua new file mode 100644 index 0000000000..d057a74386 --- /dev/null +++ b/indra/newview/scripts/lua/require/Floater.lua @@ -0,0 +1,146 @@ +-- Floater base class + +local leap = require 'leap' +local fiber = require 'fiber' +local util = require 'util' + +-- list of all the events that a LLLuaFloater might send +local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events +local event_set = {} +for _, event in pairs(event_list) do + event_set[event] = true +end + +local function _event(event_name) + if not event_set[event_name] then + error("Incorrect event name: " .. event_name, 3) + end + return event_name +end + +-- --------------------------------------------------------------------------- +local Floater = {} + +-- Pass: +-- relative file path to floater's XUI definition file +-- optional: sign up for additional events for defined control +-- {<control_name>={action1, action2, ...}} +function Floater:new(path, extra) + local obj = setmetatable({}, self) + self.__index = self + + local path_parts = string.split(path, '/') + obj.name = 'Floater ' .. path_parts[#path_parts] + + obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)} + if extra then + -- validate each of the actions for each specified control + for control, actions in pairs(extra) do + for _, action in pairs(actions) do + _event(action) + end + end + obj._command.extra_events = extra + end + + return obj +end + +util.classctor(Floater) + +function Floater:show() + -- leap.eventstream() returns the first response, and launches a + -- background fiber to call the passed callback with all subsequent + -- responses. + local event = leap.eventstream( + 'LLFloaterReg', + self._command, + -- handleEvents() returns false when done. + -- eventstream() expects a true return when done. + function(event) return not self:handleEvents(event) end) + self._pump = event.command_name + -- we might need the returned reqid to cancel the eventstream() fiber + self.reqid = event.reqid + + -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if + -- subclass has a post_build() method. Honor the convention that if + -- handleEvents() returns false, we're done. + if not self:handleEvents(event) then + return + end +end + +function Floater:post(action) + leap.send(self._pump, action) +end + +function Floater:request(action) + return leap.request(self._pump, action) +end + +-- local inspect = require 'inspect' + +function Floater:handleEvents(event_data) + local event = event_data.event + if event_set[event] == nil then + LL.print_warning(string.format('%s received unknown event %q', self.name, event)) + end + + -- Before checking for a general (e.g.) commit() method, first look for + -- commit_ctrl_name(): in other words, concatenate the event name with the + -- ctrl_name, with an underscore between. If there exists such a specific + -- method, call that. + local handler, ret + if event_data.ctrl_name then + local specific = event .. '_' .. event_data.ctrl_name + handler = self[specific] + if handler then + ret = handler(self, event_data) + -- Avoid 'return ret or true' because we explicitly want to allow + -- the handler to return false. + if ret ~= nil then + return ret + else + return true + end + end + end + + -- No specific "event_on_ctrl()" method found; try just "event()" + handler = self[event] + if handler then + ret = handler(self, event_data) + if ret ~= nil then + return ret + end +-- else +-- print(string.format('%s ignoring event %s', self.name, inspect(event_data))) + end + + -- We check for event() method before recognizing floater_close in case + -- the consumer needs to react specially to closing the floater. Now that + -- we've checked, recognize it ourselves. Returning false terminates the + -- anonymous fiber function launched by leap.eventstream(). + if event == _event('floater_close') then + LL.print_warning(self.name .. ' closed') + return false + end + return true +end + +-- onCtrl() permits a different dispatch style in which the general event() +-- method explicitly calls (e.g.) +-- self:onCtrl(event_data, { +-- ctrl_name=function() +-- self:post(...) +-- end, +-- ... +-- }) +function Floater:onCtrl(event_data, ctrl_map) + local handler = ctrl_map[event_data.ctrl_name] + if handler then + handler() + end +end + +return Floater diff --git a/indra/newview/scripts/lua/require/LLChat.lua b/indra/newview/scripts/lua/require/LLChat.lua new file mode 100644 index 0000000000..78dca765e8 --- /dev/null +++ b/indra/newview/scripts/lua/require/LLChat.lua @@ -0,0 +1,17 @@ +local leap = require 'leap' + +local LLChat = {} + +function LLChat.sendNearby(msg) + leap.send('LLChatBar', {op='sendChat', message=msg}) +end + +function LLChat.sendWhisper(msg) + leap.send('LLChatBar', {op='sendChat', type='whisper', message=msg}) +end + +function LLChat.sendShout(msg) + leap.send('LLChatBar', {op='sendChat', type='shout', message=msg}) +end + +return LLChat diff --git a/indra/newview/scripts/lua/require/LLDebugSettings.lua b/indra/newview/scripts/lua/require/LLDebugSettings.lua new file mode 100644 index 0000000000..cff1a63c21 --- /dev/null +++ b/indra/newview/scripts/lua/require/LLDebugSettings.lua @@ -0,0 +1,17 @@ +local leap = require 'leap' + +local LLDebugSettings = {} + +function LLDebugSettings.set(name, value) + leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value}) +end + +function LLDebugSettings.toggle(name) + leap.request('LLViewerControl', {op='toggle', group='Global', key=name}) +end + +function LLDebugSettings.get(name) + return leap.request('LLViewerControl', {op='get', group='Global', key=name})['value'] +end + +return LLDebugSettings diff --git a/indra/newview/scripts/lua/require/LLFloaterAbout.lua b/indra/newview/scripts/lua/require/LLFloaterAbout.lua new file mode 100644 index 0000000000..a6e42d364f --- /dev/null +++ b/indra/newview/scripts/lua/require/LLFloaterAbout.lua @@ -0,0 +1,11 @@ +-- Engage the LLFloaterAbout LLEventAPI + +local leap = require 'leap' + +local LLFloaterAbout = {} + +function LLFloaterAbout.getInfo() + return leap.request('LLFloaterAbout', {op='getInfo'}) +end + +return LLFloaterAbout diff --git a/indra/newview/scripts/lua/require/LLGesture.lua b/indra/newview/scripts/lua/require/LLGesture.lua new file mode 100644 index 0000000000..343b611e2c --- /dev/null +++ b/indra/newview/scripts/lua/require/LLGesture.lua @@ -0,0 +1,23 @@ +-- Engage the LLGesture LLEventAPI + +local leap = require 'leap' + +local LLGesture = {} + +function LLGesture.getActiveGestures() + return leap.request('LLGesture', {op='getActiveGestures'})['gestures'] +end + +function LLGesture.isGesturePlaying(id) + return leap.request('LLGesture', {op='isGesturePlaying', id=id})['playing'] +end + +function LLGesture.startGesture(id) + leap.send('LLGesture', {op='startGesture', id=id}) +end + +function LLGesture.stopGesture(id) + leap.send('LLGesture', {op='stopGesture', id=id}) +end + +return LLGesture diff --git a/indra/newview/scripts/lua/require/Queue.lua b/indra/newview/scripts/lua/require/Queue.lua new file mode 100644 index 0000000000..5bc72e4057 --- /dev/null +++ b/indra/newview/scripts/lua/require/Queue.lua @@ -0,0 +1,51 @@ +-- from https://create.roblox.com/docs/luau/queues#implementing-queues, +-- amended per https://www.lua.org/pil/16.1.html + +-- While coding some scripting in Lua +-- I found that I needed a queua +-- I thought of linked list +-- But had to resist +-- For fear it might be too obscua. + +local util = require 'util' + +local Queue = {} + +function Queue:new() + local obj = setmetatable({}, self) + self.__index = self + + obj._first = 0 + obj._last = -1 + obj._queue = {} + + return obj +end + +util.classctor(Queue) + +-- Check if the queue is empty +function Queue:IsEmpty() + return self._first > self._last +end + +-- Add a value to the queue +function Queue:Enqueue(value) + local last = self._last + 1 + self._last = last + self._queue[last] = value +end + +-- Remove a value from the queue +function Queue:Dequeue() + if self:IsEmpty() then + return nil + end + local first = self._first + local value = self._queue[first] + self._queue[first] = nil + self._first = first + 1 + return value +end + +return Queue diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua new file mode 100644 index 0000000000..eb1a4017c7 --- /dev/null +++ b/indra/newview/scripts/lua/require/UI.lua @@ -0,0 +1,125 @@ +-- Engage the viewer's UI + +local leap = require 'leap' +local Timer = (require 'timers').Timer +local mapargs = require 'mapargs' + +local UI = {} + +-- *************************************************************************** +-- registered menu actions +-- *************************************************************************** +function UI.call(func, parameter) + -- 'call' is fire-and-forget + leap.request('UI', {op='call', ['function']=func, parameter=parameter}) +end + +function UI.getValue(path) + return leap.request('UI', {op='getValue', path=path})['value'] +end + +-- *************************************************************************** +-- UI views +-- *************************************************************************** +-- Either: +-- wreq{op='Something', a=1, b=2, ...} +-- or: +-- (args should be local, as this wreq() call modifies it) +-- local args = {a=1, b=2, ...} +-- wreq('Something', args) +local function wreq(op_or_data, data_if_op) + if data_if_op ~= nil then + -- this is the wreq(op, data) form + data_if_op.op = op_or_data + op_or_data = data_if_op + end + return leap.request('LLWindow', op_or_data) +end + +-- omit 'parent' to list all view paths +function UI.listviews(parent) + return wreq{op='getPaths', under=parent} +end + +function UI.viewinfo(path) + return wreq{op='getInfo', path=path} +end + +-- *************************************************************************** +-- mouse actions +-- *************************************************************************** +-- pass a table: +-- UI.click{path=path +-- [, button='LEFT' | 'CENTER' | 'RIGHT'] +-- [, x=x, y=y] +-- [, hold=duration]} +function UI.click(...) + local args = mapargs('path,button,x,y,hold', ...) + args.button = args.button or 'LEFT' + local hold = args.hold or 1.0 + wreq('mouseMove', args) + wreq('mouseDown', args) + Timer(hold, 'wait') + wreq('mouseUp', args) +end + +-- pass a table as for UI.click() +function UI.doubleclick(...) + local args = mapargs('path,button,x,y', ...) + args.button = args.button or 'LEFT' + wreq('mouseDown', args) + wreq('mouseUp', args) + wreq('mouseDown', args) + wreq('mouseUp', args) +end + +-- UI.drag{path=, xoff=, yoff=} +function UI.drag(...) + local args = mapargs('path,xoff,yoff', ...) + -- query the specified path + local rect = UI.viewinfo(args.path).rect + local centerx = math.floor(rect.left + (rect.right - rect.left)/2) + local centery = math.floor(rect.bottom + (rect.top - rect.bottom)/2) + wreq{op='mouseMove', path=args.path, x=centerx, y=centery} + wreq{op='mouseDown', path=args.path, button='LEFT'} + wreq{op='mouseMove', path=args.path, x=centerx + args.xoff, y=centery + args.yoff} + wreq{op='mouseUp', path=args.path, button='LEFT'} +end + +-- *************************************************************************** +-- keyboard actions +-- *************************************************************************** +-- pass a table: +-- UI.keypress{ +-- [path=path] -- if omitted, default input field +-- [, char='x'] -- requires one of char, keycode, keysym +-- [, keycode=120] +-- keysym per https://github.com/secondlife/viewer/blob/main/indra/llwindow/llkeyboard.cpp#L68-L124 +-- [, keysym='Enter'] +-- [, mask={'SHIFT', 'CTL', 'ALT', 'MAC_CONTROL'}] -- some subset of these +-- } +function UI.keypress(...) + local args = mapargs('path,char,keycode,keysym,mask', ...) + if args.char == '\n' then + args.char = nil + args.keysym = 'Enter' + end + return wreq('keyDown', args) +end + +-- UI.type{text=, path=} +function UI.type(...) + local args = mapargs('text,path', ...) + if #args.text > 0 then + -- The caller's path may be specified in a way that requires recursively + -- searching parts of the LLView tree. No point in doing that more than + -- once. Capture the actual path found by that first call and use that for + -- subsequent calls. + local path = UI.keypress{path=args.path, char=string.sub(args.text, 1, 1)}.path + for i = 2, #args.text do + UI.keypress{path=path, char=string.sub(args.text, i, i)} + end + end +end + +return UI diff --git a/indra/newview/scripts/lua/require/WaitQueue.lua b/indra/newview/scripts/lua/require/WaitQueue.lua new file mode 100644 index 0000000000..7e10d03295 --- /dev/null +++ b/indra/newview/scripts/lua/require/WaitQueue.lua @@ -0,0 +1,88 @@ +-- WaitQueue isa Queue with the added feature that when the queue is empty, +-- the Dequeue() operation blocks the calling coroutine until some other +-- coroutine Enqueue()s a new value. + +local fiber = require('fiber') +local Queue = require('Queue') +local util = require('util') + +local function dbg(...) end +-- local dbg = require('printf') + +local WaitQueue = Queue() + +function WaitQueue:new() + local obj = Queue() + setmetatable(obj, self) + self.__index = self + + obj._waiters = {} + obj._closed = false + return obj +end + +util.classctor(WaitQueue) + +function WaitQueue:Enqueue(value) + if self._closed then + error("can't Enqueue() on closed Queue") + end + -- can't simply call Queue:Enqueue(value)! That calls the method on the + -- Queue class definition, instead of calling Queue:Enqueue() on self. + -- Hand-expand the Queue:Enqueue() syntactic sugar. + Queue.Enqueue(self, value) + self:_wake_waiters() +end + +function WaitQueue:_wake_waiters() + -- WaitQueue is designed to support multi-producer, multi-consumer use + -- cases. With multiple consumers, if more than one is trying to + -- Dequeue() from an empty WaitQueue, we'll have multiple waiters. + -- Unlike OS threads, with cooperative concurrency it doesn't make sense + -- to "notify all": we need wake only one of the waiting Dequeue() + -- callers. + if ((not self:IsEmpty()) or self._closed) and next(self._waiters) then + -- Pop the oldest waiting coroutine instead of the most recent, for + -- more-or-less round robin fairness. But skip any coroutines that + -- have gone dead in the meantime. + local waiter = table.remove(self._waiters, 1) + while waiter and fiber.status(waiter) == "dead" do + waiter = table.remove(self._waiters, 1) + end + -- do we still have at least one waiting coroutine? + if waiter then + -- don't pass the head item: let the resumed coroutine retrieve it + fiber.wake(waiter) + end + end +end + +function WaitQueue:Dequeue() + while self:IsEmpty() do + -- Don't check for closed until the queue is empty: producer can close + -- the queue while there are still items left, and we want the + -- consumer(s) to retrieve those last few items. + if self._closed then + dbg('WaitQueue:Dequeue(): closed') + return nil + end + dbg('WaitQueue:Dequeue(): waiting') + -- add the running coroutine to the list of waiters + dbg('WaitQueue:Dequeue() running %s', tostring(coroutine.running() or 'main')) + table.insert(self._waiters, fiber.running()) + -- then let somebody else run + fiber.wait() + end + -- here we're sure this queue isn't empty + dbg('WaitQueue:Dequeue() calling Queue.Dequeue()') + return Queue.Dequeue(self) +end + +function WaitQueue:close() + self._closed = true + -- close() is like Enqueueing an end marker. If there are waiting + -- consumers, give them a chance to see we're closed. + self:_wake_waiters() +end + +return WaitQueue diff --git a/indra/newview/scripts/lua/require/coro.lua b/indra/newview/scripts/lua/require/coro.lua new file mode 100644 index 0000000000..616a797e95 --- /dev/null +++ b/indra/newview/scripts/lua/require/coro.lua @@ -0,0 +1,67 @@ +-- Manage Lua coroutines + +local coro = {} + +coro._coros = {} + +-- Launch a Lua coroutine: create and resume. +-- Returns: new coroutine, values yielded or returned from initial resume() +-- If initial resume() encountered an error, propagates the error. +function coro.launch(func, ...) + local co = coroutine.create(func) + table.insert(coro._coros, co) + return co, coro.resume(co, ...) +end + +-- resume() wrapper to propagate errors +function coro.resume(co, ...) + -- if there's an idiom other than table.pack() to assign an arbitrary + -- number of return values, I don't yet know it + local ok_result = table.pack(coroutine.resume(co, ...)) + if not ok_result[1] then + -- if [1] is false, then [2] is the error message + error(ok_result[2]) + end + -- ok is true, whew, just return the rest of the values + return table.unpack(ok_result, 2) +end + +-- yield to other coroutines even if you don't know whether you're in a +-- created coroutine or the main coroutine +function coro.yield(...) + if coroutine.running() then + -- this is a real coroutine, yield normally + return coroutine.yield(...) + else + -- This is the main coroutine: coroutine.yield() doesn't work. + -- But we can take a spin through previously-launched coroutines. + -- Walk a copy of coro._coros in case any of these coroutines launches + -- another: next() forbids creating new entries during traversal. + for co in coro._live_coros_iter, table.clone(coro._coros) do + coro.resume(co) + end + end +end + +-- Walk coro._coros table, returning running or suspended coroutines. +-- Once a coroutine becomes dead, remove it from _coros and don't return it. +function coro._live_coros() + return coro._live_coros_iter, coro._coros +end + +-- iterator function for _live_coros() +function coro._live_coros_iter(t, idx) + local k, co = next(t, idx) + while k and coroutine.status(co) == 'dead' do +-- t[k] = nil + -- See coro.yield(): sometimes we traverse a copy of _coros, but if we + -- discover a dead coroutine in that copy, delete it from _coros + -- anyway. Deleting it from a temporary copy does nothing. + coro._coros[k] = nil + coroutine.close(co) + k, co = next(t, k) + end + return co +end + +return coro diff --git a/indra/newview/scripts/lua/require/fiber.lua b/indra/newview/scripts/lua/require/fiber.lua new file mode 100644 index 0000000000..cae27b936b --- /dev/null +++ b/indra/newview/scripts/lua/require/fiber.lua @@ -0,0 +1,340 @@ +-- Organize Lua coroutines into fibers. + +-- In this usage, the difference between coroutines and fibers is that fibers +-- have a scheduler. Yielding a fiber means allowing other fibers, plural, to +-- run: it's more than just returning control to the specific Lua thread that +-- resumed the running coroutine. + +-- fiber.launch() creates a new fiber ready to run. +-- fiber.status() reports (augmented) status of the passed fiber: instead of +-- 'suspended', it returns either 'ready' or 'waiting' +-- fiber.yield() allows other fibers to run, but leaves the calling fiber +-- ready to run. +-- fiber.wait() marks the running fiber not ready, and resumes other fibers. +-- fiber.wake() marks the designated suspended fiber ready to run, but does +-- not yet resume it. +-- fiber.run() runs all current fibers until all have terminated (successfully +-- or with an error). + +local printf = require 'printf' +local function dbg(...) end +-- local dbg = printf +local coro = require 'coro' + +local fiber = {} + +-- The tables in which we track fibers must have weak keys so dead fibers +-- can be garbage-collected. +local weak_values = {__mode='v'} +local weak_keys = {__mode='k'} + +-- Track each current fiber as being either ready to run or not ready +-- (waiting). wait() moves the running fiber from ready to waiting; wake() +-- moves the designated fiber from waiting back to ready. +-- The ready table is used as a list so yield() can go round robin. +local ready = setmetatable({'main'}, weak_keys) +-- The waiting table is used as a set because order doesn't matter. +local waiting = setmetatable({}, weak_keys) + +-- Every fiber has a name, for diagnostic purposes. Names must be unique. +-- A colliding name will be suffixed with an integer. +-- Predefine 'main' with our marker so nobody else claims that name. +local names = setmetatable({main='main'}, weak_keys) +local byname = setmetatable({main='main'}, weak_values) +-- each colliding name has its own distinct suffix counter +local suffix = {} + +-- Specify a nullary idle() callback to be called whenever there are no ready +-- fibers but there are waiting fibers. The idle() callback is responsible for +-- changing zero or more waiting fibers to ready fibers by calling +-- fiber.wake(), although a given call may leave them all still waiting. +-- When there are no ready fibers, it's a good idea for the idle() function to +-- return control to a higher-level execution agent. Simply returning without +-- changing any fiber's status will spin the CPU. +-- The idle() callback can return non-nil to exit fiber.run() with that value. +function fiber._idle() + error('fiber.yield(): you must first call set_idle(nullary idle() function)') +end + +function fiber.set_idle(func) + fiber._idle = func +end + +-- Launch a new Lua fiber, ready to run. +function fiber.launch(name, func, ...) + local args = table.pack(...) + local co = coroutine.create(function() func(table.unpack(args)) end) + -- a new fiber is ready to run + table.insert(ready, co) + local namekey = name + while byname[namekey] do + if not suffix[name] then + suffix[name] = 1 + end + suffix[name] += 1 + namekey = name .. tostring(suffix[name]) + end + -- found a namekey not yet in byname: set it + byname[namekey] = co + -- and remember it as this fiber's name + names[co] = namekey +-- dbg('launch(%s)', namekey) +-- dbg('byname[%s] = %s', namekey, tostring(byname[namekey])) +-- dbg('names[%s] = %s', tostring(co), names[co]) +-- dbg('ready[-1] = %s', tostring(ready[#ready])) +end + +-- for debugging +function format_all() + output = {} + table.insert(output, 'Ready fibers:' .. if next(ready) then '' else ' none') + for _, co in pairs(ready) do + table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co))) + end + table.insert(output, 'Waiting fibers:' .. if next(waiting) then '' else ' none') + for co in pairs(waiting) do + table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co))) + end + return table.concat(output, '\n') +end + +function fiber.print_all() + print(format_all()) +end + +-- return either the running coroutine or, if called from the main thread, +-- 'main' +function fiber.running() + return coroutine.running() or 'main' +end + +-- Query a fiber's name (nil for the running fiber) +function fiber.get_name(co) + return names[co or fiber.running()] or 'unknown' +end + +-- Query status of the passed fiber +function fiber.status(co) + local running = coroutine.running() + if (not co) or co == running then + -- silly to ask the status of the running fiber: it's 'running' + return 'running' + end + if co ~= 'main' then + -- for any coroutine but main, consult coroutine.status() + local status = coroutine.status(co) + if status ~= 'suspended' then + return status + end + -- here co is suspended, answer needs further refinement + else + -- co == 'main' + if not running then + -- asking about 'main' from the main fiber + return 'running' + end + -- asking about 'main' from some other fiber, so presumably main is suspended + end + -- here we know co is suspended -- but is it ready to run? + if waiting[co] then + return 'waiting' + end + -- not waiting should imply ready: sanity check + if table.find(ready, co) then + return 'ready' + end + -- Calls within yield() between popping the next ready fiber and + -- re-appending it to the list are in this state. Once we're done + -- debugging yield(), we could reinstate either of the below. +-- error(string.format('fiber.status(%s) is stumped', fiber.get_name(co))) +-- print(string.format('*** fiber.status(%s) is stumped', fiber.get_name(co))) + return '(unknown)' +end + +-- change the running fiber's status to waiting +local function set_waiting() + -- if called from the main fiber, inject a 'main' marker into the list + co = fiber.running() + -- delete from ready list + local i = table.find(ready, co) + if i then + table.remove(ready, i) + end + -- add to waiting list + waiting[co] = true +end + +-- Suspend the current fiber until some other fiber calls fiber.wake() on it +function fiber.wait() + dbg('Fiber %q waiting', fiber.get_name()) + set_waiting() + -- now yield to other fibers + fiber.yield() +end + +-- Mark a suspended fiber as being ready to run +function fiber.wake(co) + if not waiting[co] then + error(string.format('fiber.wake(%s) but status=%s, ready=%s, waiting=%s', + names[co], fiber.status(co), ready[co], waiting[co])) + end + -- delete from waiting list + waiting[co] = nil + -- add to end of ready list + table.insert(ready, co) + dbg('Fiber %q ready', fiber.get_name(co)) + -- but don't yet resume it: that happens next time we reach yield() +end + +-- pop and return the next not-dead fiber in the ready list, or nil if none remain +local function live_ready_iter() + -- don't write: + -- for co in table.remove, ready, 1 + -- because it would keep passing a new second parameter! + for co in function() return table.remove(ready, 1) end do + dbg('%s live_ready_iter() sees %s, status %s', + fiber.get_name(), fiber.get_name(co), fiber.status(co)) + -- keep removing the head entry until we find one that's not dead, + -- discarding any dead coroutines along the way + if co == 'main' or coroutine.status(co) ~= 'dead' then + dbg('%s live_ready_iter() returning %s', + fiber.get_name(), fiber.get_name(co)) + return co + end + end + dbg('%s live_ready_iter() returning nil', fiber.get_name()) + return nil +end + +-- prune the set of waiting fibers +local function prune_waiting() + for waiter in pairs(waiting) do + if waiter ~= 'main' and coroutine.status(waiter) == 'dead' then + waiting[waiter] = nil + end + end +end + +-- Run other ready fibers, leaving this one ready, returning after a cycle. +-- Returns: +-- * true, nil if there remain other live fibers, whether ready or waiting, +-- but it's our turn to run +-- * false, nil if this is the only remaining fiber +-- * nil, x if configured idle() callback returns non-nil x +local function scheduler() + dbg('scheduler():\n%s', format_all()) + -- scheduler() is asymmetric because Lua distinguishes the main thread + -- from other coroutines. The main thread can't yield; it can only resume + -- other coroutines. So although an arbitrary coroutine could resume still + -- other arbitrary coroutines, it could NOT resume the main thread because + -- the main thread can't yield. Therefore, scheduler() delegates its real + -- processing to the main thread. If called from a coroutine, pass control + -- back to the main thread. + if coroutine.running() then + -- this is a real coroutine, yield normally to main thread + coroutine.yield() + -- main certainly still exists + return true + end + + -- This is the main fiber: coroutine.yield() doesn't work. + -- Instead, resume each of the ready fibers. + -- Prune the set of waiting fibers after every time fiber business logic + -- runs (i.e. other fibers might have terminated or hit error), such as + -- here on entry. + prune_waiting() + local others, idle_stop + repeat + for co in live_ready_iter do + -- seize the opportunity to make sure the viewer isn't shutting down + LL.check_stop() + -- before we re-append co, is it the only remaining entry? + others = next(ready) + -- co is live, re-append it to the ready list + table.insert(ready, co) + if co == 'main' then + -- Since we know the caller is the main fiber, it's our turn. + -- Tell caller if there are other ready or waiting fibers. + return others or next(waiting) + end + -- not main, but some other ready coroutine: + -- use coro.resume() so we'll propagate any error encountered + coro.resume(co) + prune_waiting() + end + -- Here there are no ready fibers. Are there any waiting fibers? + if not next(waiting) then + return false + end + -- there are waiting fibers: call consumer's configured idle() function + idle_stop = fiber._idle() + if idle_stop ~= nil then + return nil, idle_stop + end + prune_waiting() + -- loop "forever", that is, until: + -- * main is ready, or + -- * there are neither ready fibers nor waiting fibers, or + -- * fiber._idle() returned non-nil + until false +end + +-- Let other fibers run. This is useful in either of two cases: +-- * fiber.wait() calls this to run other fibers while this one is waiting. +-- fiber.yield() (and therefore fiber.wait()) works from the main thread as +-- well as from explicitly-launched fibers, without the caller having to +-- care. +-- * A long-running fiber that doesn't often call fiber.wait() should sprinkle +-- in fiber.yield() calls to interleave processing on other fibers. +function fiber.yield() + -- The difference between this and fiber.run() is that fiber.yield() + -- assumes its caller has work to do. yield() returns to its caller as + -- soon as scheduler() pops this fiber from the ready list. fiber.run() + -- continues looping until all other fibers have terminated, or the + -- set_idle() callback tells it to stop. + local others, idle_done = scheduler() + -- scheduler() returns either if we're ready, or if idle_done ~= nil. + if idle_done ~= nil then + -- Returning normally from yield() means the caller can carry on with + -- its pending work. But in this case scheduler() returned because the + -- configured set_idle() function interrupted it -- not because we're + -- actually ready. Don't return normally. + error('fiber.set_idle() interrupted yield() with: ' .. tostring(idle_done)) + end + -- We're ready! Just return to caller. In this situation we don't care + -- whether there are other ready fibers. + dbg('fiber.yield() returning to %s (%sothers are ready)', + fiber.get_name(), ((not others) and "no " or "")) +end + +-- Run fibers until all but main have terminated: return nil. +-- Or until configured idle() callback returns x ~= nil: return x. +function fiber.run() + -- A fiber calling run() is not also doing other useful work. Remove the + -- calling fiber from the ready list. Otherwise yield() would keep seeing + -- that our caller is ready and return to us, instead of realizing that + -- all coroutines are waiting and call idle(). But don't say we're + -- waiting, either, because then when all other fibers have terminated + -- we'd call idle() forever waiting for something to make us ready again. + local i = table.find(ready, fiber.running()) + if i then + table.remove(ready, i) + end + local others, idle_done + repeat + dbg('%s calling fiber.run() calling scheduler()', fiber.get_name()) + others, idle_done = scheduler() + dbg("%s fiber.run()'s scheduler() returned %s, %s", fiber.get_name(), + tostring(others), tostring(idle_done)) + until (not others) + dbg('%s fiber.run() done', fiber.get_name()) + -- For whatever it's worth, put our own fiber back in the ready list. + table.insert(ready, fiber.running()) + -- Once there are no more waiting fibers, and the only ready fiber is + -- us, return to caller. All previously-launched fibers are done. Possibly + -- the chunk is done, or the chunk may decide to launch a new batch of + -- fibers. + return idle_done +end + +return fiber diff --git a/indra/newview/scripts/lua/require/inspect.lua b/indra/newview/scripts/lua/require/inspect.lua new file mode 100644 index 0000000000..9900a0b81b --- /dev/null +++ b/indra/newview/scripts/lua/require/inspect.lua @@ -0,0 +1,371 @@ +local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table +local inspect = {Options = {}, } + + + + + + + + + + + + + + + + + +inspect._VERSION = 'inspect.lua 3.1.0' +inspect._URL = 'http://github.com/kikito/inspect.lua' +inspect._DESCRIPTION = 'human-readable representations of tables' +inspect._LICENSE = [[ + MIT LICENSE + + Copyright (c) 2022 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] +inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end }) +inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end }) + +local tostring = tostring +local rep = string.rep +local match = string.match +local char = string.char +local gsub = string.gsub +local fmt = string.format + +local _rawget +if rawget then + _rawget = rawget +else + _rawget = function(t, k) return t[k] end +end + +local function rawpairs(t) + return next, t, nil +end + + + +local function smartQuote(str) + if match(str, '"') and not match(str, "'") then + return "'" .. str .. "'" + end + return '"' .. gsub(str, '"', '\\"') .. '"' +end + + +local shortControlCharEscapes = { + ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", + ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127", +} +local longControlCharEscapes = { ["\127"] = "\127" } +for i = 0, 31 do + local ch = char(i) + if not shortControlCharEscapes[ch] then + shortControlCharEscapes[ch] = "\\" .. i + longControlCharEscapes[ch] = fmt("\\%03d", i) + end +end + +local function escape(str) + return (gsub(gsub(gsub(str, "\\", "\\\\"), + "(%c)%f[0-9]", longControlCharEscapes), + "%c", shortControlCharEscapes)) +end + +local luaKeywords = { + ['and'] = true, + ['break'] = true, + ['do'] = true, + ['else'] = true, + ['elseif'] = true, + ['end'] = true, + ['false'] = true, + ['for'] = true, + ['function'] = true, + ['goto'] = true, + ['if'] = true, + ['in'] = true, + ['local'] = true, + ['nil'] = true, + ['not'] = true, + ['or'] = true, + ['repeat'] = true, + ['return'] = true, + ['then'] = true, + ['true'] = true, + ['until'] = true, + ['while'] = true, +} + +local function isIdentifier(str) + return type(str) == "string" and + not not str:match("^[_%a][_%a%d]*$") and + not luaKeywords[str] +end + +local flr = math.floor +local function isSequenceKey(k, sequenceLength) + return type(k) == "number" and + flr(k) == k and + 1 <= (k) and + k <= sequenceLength +end + +local defaultTypeOrders = { + ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, + ['function'] = 5, ['userdata'] = 6, ['thread'] = 7, +} + +local function sortKeys(a, b) + local ta, tb = type(a), type(b) + + + if ta == tb and (ta == 'string' or ta == 'number') then + return (a) < (b) + end + + local dta = defaultTypeOrders[ta] or 100 + local dtb = defaultTypeOrders[tb] or 100 + + + return dta == dtb and ta < tb or dta < dtb +end + +local function getKeys(t) + + local seqLen = 1 + while _rawget(t, seqLen) ~= nil do + seqLen = seqLen + 1 + end + seqLen = seqLen - 1 + + local keys, keysLen = {}, 0 + for k in rawpairs(t) do + if not isSequenceKey(k, seqLen) then + keysLen = keysLen + 1 + keys[keysLen] = k + end + end + table.sort(keys, sortKeys) + return keys, keysLen, seqLen +end + +local function countCycles(x, cycles) + if type(x) == "table" then + if cycles[x] then + cycles[x] = cycles[x] + 1 + else + cycles[x] = 1 + for k, v in rawpairs(x) do + countCycles(k, cycles) + countCycles(v, cycles) + end + countCycles(getmetatable(x), cycles) + end + end +end + +local function makePath(path, a, b) + local newPath = {} + local len = #path + for i = 1, len do newPath[i] = path[i] end + + newPath[len + 1] = a + newPath[len + 2] = b + + return newPath +end + + +local function processRecursive(process, + item, + path, + visited) + if item == nil then return nil end + if visited[item] then return visited[item] end + + local processed = process(item, path) + if type(processed) == "table" then + local processedCopy = {} + visited[item] = processedCopy + local processedKey + + for k, v in rawpairs(processed) do + processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) + if processedKey ~= nil then + processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) + end + end + + local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) + if type(mt) ~= 'table' then mt = nil end + setmetatable(processedCopy, mt) + processed = processedCopy + end + return processed +end + +local function puts(buf, str) + buf.n = buf.n + 1 + buf[buf.n] = str +end + + + +local Inspector = {} + + + + + + + + + + +local Inspector_mt = { __index = Inspector } + +local function tabify(inspector) + puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level)) +end + +function Inspector:getId(v) + local id = self.ids[v] + local ids = self.ids + if not id then + local tv = type(v) + id = (ids[tv] or 0) + 1 + ids[v], ids[tv] = id, id + end + return tostring(id) +end + +function Inspector:putValue(v) + local buf = self.buf + local tv = type(v) + if tv == 'string' then + puts(buf, smartQuote(escape(v))) + elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or + tv == 'cdata' or tv == 'ctype' then + puts(buf, tostring(v)) + elseif tv == 'table' and not self.ids[v] then + local t = v + + if t == inspect.KEY or t == inspect.METATABLE then + puts(buf, tostring(t)) + elseif self.level >= self.depth then + puts(buf, '{...}') + else + if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end + + local keys, keysLen, seqLen = getKeys(t) + + puts(buf, '{') + self.level = self.level + 1 + + for i = 1, seqLen + keysLen do + if i > 1 then puts(buf, ',') end + if i <= seqLen then + puts(buf, ' ') + self:putValue(t[i]) + else + local k = keys[i - seqLen] + tabify(self) + if isIdentifier(k) then + puts(buf, k) + else + puts(buf, "[") + self:putValue(k) + puts(buf, "]") + end + puts(buf, ' = ') + self:putValue(t[k]) + end + end + + local mt = getmetatable(t) + if type(mt) == 'table' then + if seqLen + keysLen > 0 then puts(buf, ',') end + tabify(self) + puts(buf, '<metatable> = ') + self:putValue(mt) + end + + self.level = self.level - 1 + + if keysLen > 0 or type(mt) == 'table' then + tabify(self) + elseif seqLen > 0 then + puts(buf, ' ') + end + + puts(buf, '}') + end + + else + puts(buf, fmt('<%s %d>', tv, self:getId(v))) + end +end + + + + +function inspect.inspect(root, options) + options = options or {} + + local depth = options.depth or (math.huge) + local newline = options.newline or '\n' + local indent = options.indent or ' ' + local process = options.process + + if process then + root = processRecursive(process, root, {}, {}) + end + + local cycles = {} + countCycles(root, cycles) + + local inspector = setmetatable({ + buf = { n = 0 }, + ids = {}, + cycles = cycles, + depth = depth, + level = 0, + newline = newline, + indent = indent, + }, Inspector_mt) + + inspector:putValue(root) + + return table.concat(inspector.buf) +end + +setmetatable(inspect, { + __call = function(_, root, options) + return inspect.inspect(root, options) + end, +}) + +return inspect diff --git a/indra/newview/scripts/lua/require/leap.lua b/indra/newview/scripts/lua/require/leap.lua new file mode 100644 index 0000000000..82f91ce9e9 --- /dev/null +++ b/indra/newview/scripts/lua/require/leap.lua @@ -0,0 +1,550 @@ +-- Lua implementation of LEAP (LLSD Event API Plugin) protocol +-- +-- This module supports Lua scripts run by the Second Life viewer. +-- +-- LEAP protocol passes LLSD objects, converted to/from Lua tables, in both +-- directions. A typical LLSD object is a map containing keys 'pump' and +-- 'data'. +-- +-- The viewer's Lua post_to(pump, data) function posts 'data' to the +-- LLEventPump 'pump'. This is typically used to engage an LLEventAPI method. +-- +-- Similarly, the viewer gives each Lua script its own LLEventPump with a +-- unique name. That name is returned by get_event_pumps(). Every event +-- received on that LLEventPump is queued for retrieval by get_event_next(), +-- which returns (pump, data): the name of the LLEventPump on which the event +-- was received and the received event data. When the queue is empty, +-- get_event_next() blocks the calling Lua script until the next event is +-- received. +-- +-- Usage: +-- 1. Launch some number of Lua coroutines. The code in each coroutine may +-- call leap.send(), leap.request() or leap.generate(). leap.send() returns +-- immediately ("fire and forget"). leap.request() blocks the calling +-- coroutine until it receives and returns the viewer's response to its +-- request. leap.generate() expects an arbitrary number of responses to the +-- original request. +-- 2. To handle events from the viewer other than direct responses to +-- requests, instantiate a leap.WaitFor object with a filter(pump, data) +-- override method that returns non-nil for desired events. A coroutine may +-- call wait() on any such WaitFor. +-- 3. Once the coroutines have been launched, call leap.process() on the main +-- coroutine. process() retrieves incoming events from the viewer and +-- dispatches them to waiting request() or generate() calls, or to +-- appropriate WaitFor instances. process() returns when either +-- get_event_next() raises an error or the viewer posts nil to the script's +-- reply pump to indicate it's done. +-- 4. Alternatively, a running coroutine may call leap.done() to break out of +-- leap.process(). process() won't notice until the next event from the +-- viewer, though. + +local fiber = require('fiber') +local ErrorQueue = require('ErrorQueue') +local inspect = require('inspect') +local function dbg(...) end +-- local dbg = require('printf') +local util = require('util') + +local leap = {} + +-- reply: string name of reply LLEventPump. Any events the viewer posts to +-- this pump will be queued for get_event_next(). We usually specify it as the +-- reply pump for requests to internal viewer services. +-- command: string name of command LLEventPump. post_to(command, ...) +-- engages LLLeapListener operations such as listening on a specified other +-- LLEventPump, etc. +local reply, command = LL.get_event_pumps() +-- Dict of features added to the LEAP protocol since baseline implementation. +-- Before engaging a new feature that might break an older viewer, we can +-- check for the presence of that feature key. This table is solely about the +-- LEAP protocol itself, the way we communicate with the viewer. To discover +-- whether a given listener exists, or supports a particular operation, use +-- command's "getAPI" operation. +-- For Lua, command's "getFeatures" operation suffices? +-- leap._features = {} + +-- Each outstanding request() or generate() call has a corresponding +-- WaitForReqid object (later in this module) to handle the +-- response(s). If an incoming event contains an echoed ["reqid"] key, +-- we can look up the appropriate WaitForReqid object more efficiently +-- in a dict than by tossing such objects into the usual waitfors list. +-- Note: the ["reqid"] must be unique, otherwise we could end up +-- replacing an earlier WaitForReqid object in pending with a +-- later one. That means that no incoming event will ever be given to +-- the old WaitForReqid object. Any coroutine waiting on the discarded +-- WaitForReqid object would therefore wait forever. +-- pending is NOT a weak table because the caller of request() or generate() +-- never sees the WaitForReqid object. pending holds the only reference, so +-- it should NOT be garbage-collected. +local pending = {} +-- Our consumer will instantiate some number of WaitFor subclass objects. +-- As these are traversed in descending priority order, we must keep +-- them in a list. +-- Anyone who instantiates a WaitFor subclass object should retain a reference +-- to it. Once the consuming script drops the reference, allow Lua to +-- garbage-collect the WaitFor despite its entry in waitfors. +local weak_values = {__mode='v'} +local waitfors = setmetatable({}, weak_values) +-- It has been suggested that we should use UUIDs as ["reqid"] values, +-- since UUIDs are guaranteed unique. However, as the "namespace" for +-- ["reqid"] values is our very own reply pump, we can get away with +-- an integer. +leap._reqid = 0 +-- break leap.process() loop +leap._done = false + +-- get the name of the reply pump +function leap.replypump() + return reply +end + +-- get the name of the command pump +function leap.cmdpump() + return command +end + +-- Fire and forget. Send the specified request LLSD, expecting no reply. +-- In fact, should the request produce an eventual reply, it will be +-- treated as an unsolicited event. +-- +-- See also request(), generate(). +function leap.send(pump, data, reqid) + local data = data + if type(data) == 'table' then + data = table.clone(data) + data['reply'] = reply + if reqid ~= nil then + data['reqid'] = reqid + end + end + dbg('leap.send(%s, %s) calling post_on()', pump, data) + LL.post_on(pump, data) +end + +-- common setup code shared by request() and generate() +local function requestSetup(pump, data) + -- invent a new, unique reqid + leap._reqid += 1 + local reqid = leap._reqid + -- Instantiate a new WaitForReqid object. The priority is irrelevant + -- because, unlike the WaitFor base class, WaitForReqid does not + -- self-register on our waitfors list. Instead, capture the new + -- WaitForReqid object in pending so dispatch() can find it. + local waitfor = leap.WaitForReqid(reqid) + pending[reqid] = waitfor + -- Pass reqid to send() to stamp it into (a copy of) the request data. + dbg('requestSetup(%s, %s) storing %s', pump, data, waitfor.name) + leap.send(pump, data, reqid) + return reqid, waitfor +end + +-- Send the specified request LLSD, expecting exactly one reply. Block +-- the calling coroutine until we receive that reply. +-- +-- Every request() (or generate()) LLSD block we send will get stamped +-- with a distinct ["reqid"] value. The requested event API must echo the +-- same ["reqid"] field in each reply associated with that request. This way +-- we can correctly dispatch interleaved replies from different requests. +-- +-- If the desired event API doesn't support the ["reqid"] echo convention, +-- you should use send() instead -- since request() or generate() would +-- wait forever for a reply stamped with that ["reqid"] -- and intercept +-- any replies using WaitFor. +-- +-- Unless the request data already contains a ["reply"] key, we insert +-- reply=self.replypump to try to ensure that the expected reply will be +-- returned over the socket. +-- +-- See also send(), generate(). +function leap.request(pump, data) + local reqid, waitfor = requestSetup(pump, data) + dbg('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor)) + local ok, response = pcall(waitfor.wait, waitfor) + dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) + -- kill off temporary WaitForReqid object, even if error + pending[reqid] = nil + if not ok then + error(response) + elseif response.error then + error(response.error) + else + return response + end +end + +-- Send the specified request LLSD, expecting an arbitrary number of replies. +-- Each one is returned on request. +-- +-- Usage: +-- sequence = leap.generate(pump, data) +-- repeat +-- response = sequence.next() +-- until last(response) +-- (last() means whatever test the caller wants to perform on response) +-- sequence.done() +-- +-- See request() remarks about ["reqid"]. +-- +-- Note: this seems like a prime use case for Lua coroutines. But in a script +-- using fibers.lua, a "wild" coroutine confuses the fiber scheduler. If +-- generate() were itself a coroutine, it would call WaitForReqid:wait(), +-- which would yield -- thereby resuming generate() WITHOUT waiting. +function leap.generate(pump, data, checklast) + -- Invent a new, unique reqid. Arrange to handle incoming events + -- bearing that reqid. Stamp the outbound request with that reqid, and + -- send it. + local reqid, waitfor = requestSetup(pump, data) + return { + next = function() + dbg('leap.generate(%s).next() about to wait on %s', reqid, tostring(waitfor)) + local ok, response = pcall(waitfor.wait, waitfor) + dbg('leap.generate(%s).next() got %s: %s', reqid, ok, response) + if not ok then + error(response) + elseif response.error then + error(response.error) + else + return response + end + end, + done = function() + -- cleanup consists of removing our WaitForReqid from pending + pending[reqid] = nil + end + } +end + +-- Send the specified request LLSD, expecting an immediate reply followed by +-- an arbitrary number of subsequent replies with the same reqid. Block the +-- calling coroutine until the first (immediate) reply, but launch a separate +-- fiber on which to call the passed callback with later replies. +-- +-- Once the callback returns true, the background fiber terminates. +function leap.eventstream(pump, data, callback) + local reqid, waitfor = requestSetup(pump, data) + local response = waitfor:wait() + if response.error then + -- clean up our WaitForReqid + waitfor:close() + error(response.error) + end + -- No error, so far so good: + -- call the callback with the first response just in case + dbg('leap.eventstream(%s): first callback', reqid) + local ok, done = pcall(callback, response) + dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) + if not ok then + -- clean up our WaitForReqid + waitfor:close() + error(done) + end + if done then + return response + end + -- callback didn't throw an error, and didn't say stop, + -- so set up to handle subsequent events + -- TODO: distinguish "daemon" fibers that can be terminated even if waiting + fiber.launch( + pump, + function () + local ok, done + local nth = 1 + repeat + event = waitfor:wait() + if not event then + -- wait() returns nil once the queue is closed (e.g. cancelreq()) + ok, done = true, true + else + nth += 1 + dbg('leap.eventstream(%s): callback %d', reqid, nth) + ok, done = pcall(callback, event) + dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) + end + -- not ok means callback threw an error (caught as 'done') + -- done means callback succeeded but wants to stop + until (not ok) or done + -- once we break this loop, clean up our WaitForReqid + waitfor:close() + if not ok then + -- can't reflect the error back to our caller + LL.print_warning(fiber.get_name() .. ': ' .. done) + end + end) + return response +end + +-- we might want to clean up after leap.eventstream() even if the callback has +-- not yet returned true +function leap.cancelreq(reqid) + dbg('cancelreq(%s)', reqid) + local waitfor = pending[reqid] + if waitfor ~= nil then + -- close() removes the pending entry and also closes the queue, + -- breaking the background fiber's wait loop. + dbg('cancelreq(%s) canceling %s', reqid, waitfor.name) + waitfor:close() + end +end + +local function cleanup(message) + -- We're done: clean up all pending coroutines. + -- Iterate over copies of the pending and waitfors tables, since the + -- close() operation modifies the real tables. + for i, waitfor in pairs(table.clone(pending)) do + waitfor:close() + end + for i, waitfor in pairs(table.clone(waitfors)) do + waitfor:close() + end +end + +-- Handle an incoming (pump, data) event with no recognizable ['reqid'] +local function unsolicited(pump, data) + -- we maintain waitfors in descending priority order, so the first waitfor + -- to claim this event is the one with the highest priority + for i, waitfor in pairs(waitfors) do + dbg('unsolicited() checking %s', waitfor.name) + if waitfor:handle(pump, data) then + return + end + end + LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', + pump, inspect(data))) +end + +-- Route incoming (pump, data) event to the appropriate waiting coroutine. +local function dispatch(pump, data) + local reqid = data['reqid'] + -- if the response has no 'reqid', it's not from request() or generate() + if reqid == nil then +-- dbg('dispatch() found no reqid; calling unsolicited(%s, %s)', pump, data) + return unsolicited(pump, data) + end + -- have reqid; do we have a WaitForReqid? + local waitfor = pending[reqid] + if waitfor == nil then +-- dbg('dispatch() found no WaitForReqid(%s); calling unsolicited(%s, %s)', reqid, pump, data) + return unsolicited(pump, data) + end + -- found the right WaitForReqid object, let it handle the event +-- dbg('dispatch() calling %s.handle(%s, %s)', waitfor.name, pump, data) + waitfor:handle(pump, data) +end + +-- We configure fiber.set_idle() function. fiber.yield() calls the configured +-- idle callback whenever there are waiting fibers but no ready fibers. In +-- our case, that means it's time to fetch another incoming viewer event. +fiber.set_idle(function () + -- If someone has called leap.done(), then tell fiber.yield() to break loop. + if leap._done then + cleanup('done') + return 'done' + end + dbg('leap.idle() calling get_event_next()') + local ok, pump, data = pcall(LL.get_event_next) + dbg('leap.idle() got %s: %s, %s', ok, pump, data) + -- ok false means get_event_next() raised a Lua error, pump is message + if not ok then + cleanup(pump) + error(pump) + end + -- data nil means get_event_next() returned (pump, LLSD()) to indicate done + if not data then + cleanup('end') + return 'end' + end + -- got a real pump, data pair + dispatch(pump, data) + -- return to fiber.yield(): any incoming message might result in one or + -- more fibers becoming ready +end) + +function leap.done() + leap._done = true +end + +-- called by WaitFor.enable() +local function registerWaitFor(waitfor) + table.insert(waitfors, waitfor) + -- keep waitfors sorted in descending order of specified priority + table.sort(waitfors, + function (lhs, rhs) return lhs.priority > rhs.priority end) +end + +-- called by WaitFor.disable() +local function unregisterWaitFor(waitfor) + local i = table.find(waitfors, waitfor) + if i ~= nil then + waitfors[i] = nil + end +end + +-- ****************************************************************************** +-- WaitFor and friends +-- ****************************************************************************** + +-- An unsolicited event is handled by the highest-priority WaitFor subclass +-- object willing to accept it. If no such object is found, the unsolicited +-- event is discarded. +-- +-- * First, instantiate a WaitFor subclass object to register its interest in +-- some incoming event(s). WaitFor instances are self-registering; merely +-- instantiating the object suffices. +-- * Any coroutine may call a given WaitFor object's wait() method. This blocks +-- the calling coroutine until a suitable event arrives. +-- * WaitFor's constructor accepts a float priority. Every incoming event +-- (other than those claimed by request() or generate()) is passed to each +-- extant WaitFor.filter() method in descending priority order. The first +-- such filter() to return nontrivial data claims that event. +-- * At that point, the blocked wait() call on that WaitFor object returns the +-- item returned by filter(). +-- * WaitFor contains a queue. Multiple arriving events claimed by that WaitFor +-- object's filter() method are added to the queue. Naturally, until the +-- queue is empty, calling wait() immediately returns the front entry. +-- +-- It's reasonable to instantiate a WaitFor subclass whose filter() method +-- unconditionally returns the incoming event, and whose priority places it +-- last in the list. This object will enqueue every unsolicited event left +-- unclaimed by other WaitFor subclass objects. +-- +-- It's not strictly necessary to associate a WaitFor object with exactly one +-- coroutine. You might have multiple "worker" coroutines drawing from the same +-- WaitFor object, useful if the work being done per event might itself involve +-- "blocking" operations. Or a given coroutine might sample a number of WaitFor +-- objects in round-robin fashion... etc. etc. Nonetheless, it's +-- straightforward to designate one coroutine for each WaitFor object. + +-- --------------------------------- WaitFor --------------------------------- +leap.WaitFor = { _id=0 } + +function leap.WaitFor.tostring(self) + -- Lua (sub)classes have no name; can't prefix with that + return self.name +end + +function leap.WaitFor:new(priority, name) + local obj = setmetatable({__tostring=leap.WaitFor.tostring}, self) + self.__index = self + + obj.priority = priority + if name then + obj.name = name + else + self._id += 1 + obj.name = 'WaitFor' .. self._id + end + obj._queue = ErrorQueue() + obj._registered = false + -- if no priority, then don't enable() - remember 0 is truthy + if priority then + obj:enable() + end + + return obj +end + +util.classctor(leap.WaitFor) + +-- Re-enable a disable()d WaitFor object. New WaitFor objects are +-- enable()d by default. +function leap.WaitFor:enable() + if not self._registered then + registerWaitFor(self) + self._registered = true + end +end + +-- Disable an enable()d WaitFor object. +function leap.WaitFor:disable() + if self._registered then + unregisterWaitFor(self) + self._registered = false + end +end + +-- Block the calling coroutine until a suitable unsolicited event (one +-- for which filter() returns the event) arrives. +function leap.WaitFor:wait() + dbg('%s about to wait', self.name) + local item = self._queue:Dequeue() + dbg('%s got %s', self.name, item) + return item +end + +-- Override filter() to examine the incoming event in whatever way +-- makes sense. +-- +-- Return nil to ignore this event. +-- +-- To claim the event, return the item you want placed in the queue. +-- Typically you'd write: +-- return data +-- or perhaps +-- return {pump=pump, data=data} +-- or some variation. +function leap.WaitFor:filter(pump, data) + error('You must override the WaitFor.filter() method') +end + +-- called by unsolicited() for each WaitFor in waitfors +function leap.WaitFor:handle(pump, data) + local item = self:filter(pump, data) + dbg('%s.filter() returned %s', self.name, item) + -- if this item doesn't pass the filter, we're not interested + if not item then + return false + end + -- okay, filter() claims this event + self:process(item) + return true +end + +-- called by WaitFor:handle() for an accepted event +function leap.WaitFor:process(item) + self._queue:Enqueue(item) +end + +-- called by cleanup() at end +function leap.WaitFor:close() + self:disable() + self._queue:close() +end + +-- called by leap.process() when get_event_next() raises an error +function leap.WaitFor:exception(message) + LL.print_warning(self.name .. ' error: ' .. message) + self._queue:Error(message) +end + +-- ------------------------------ WaitForReqid ------------------------------- +leap.WaitForReqid = leap.WaitFor() + +function leap.WaitForReqid:new(reqid) + -- priority is meaningless, since this object won't be added to the + -- priority-sorted waitfors list. Use the reqid as the debugging name + -- string. + local obj = leap.WaitFor(nil, 'WaitForReqid(' .. reqid .. ')') + setmetatable(obj, self) + self.__index = self + + obj.reqid = reqid + + return obj +end + +util.classctor(leap.WaitForReqid) + +function leap.WaitForReqid:filter(pump, data) + -- Because we expect to directly look up the WaitForReqid object of + -- interest based on the incoming ["reqid"] value, it's not necessary + -- to test the event again. Accept every such event. + return data +end + +function leap.WaitForReqid:close() + -- remove this entry from pending table + pending[self.reqid] = nil + self._queue:close() +end + +return leap diff --git a/indra/newview/scripts/lua/require/printf.lua b/indra/newview/scripts/lua/require/printf.lua new file mode 100644 index 0000000000..e84b2024df --- /dev/null +++ b/indra/newview/scripts/lua/require/printf.lua @@ -0,0 +1,19 @@ +-- printf(...) is short for print(string.format(...)) + +local inspect = require 'inspect' + +local function printf(format, ...) + -- string.format() only handles numbers and strings. + -- Convert anything else to string using the inspect module. + local args = {} + for _, arg in pairs(table.pack(...)) do + if type(arg) == 'number' or type(arg) == 'string' then + table.insert(args, arg) + else + table.insert(args, inspect(arg)) + end + end + print(string.format(format, table.unpack(args))) +end + +return printf diff --git a/indra/newview/scripts/lua/require/startup.lua b/indra/newview/scripts/lua/require/startup.lua new file mode 100644 index 0000000000..c3040f94b8 --- /dev/null +++ b/indra/newview/scripts/lua/require/startup.lua @@ -0,0 +1,100 @@ +-- query, wait for or mandate a particular viewer startup state + +-- During startup, the viewer steps through a sequence of numbered (and named) +-- states. This can be used to detect when, for instance, the login screen is +-- displayed, or when the viewer has finished logging in and is fully +-- in-world. + +local fiber = require 'fiber' +local leap = require 'leap' +local inspect = require 'inspect' +local function dbg(...) end +-- local dbg = require 'printf' + +-- --------------------------------------------------------------------------- +local startup = {} + +-- Get the list of startup states from the viewer. +local bynum = leap.request('LLStartUp', {op='getStateTable'})['table'] + +local byname = setmetatable( + {}, + -- set metatable to throw an error if you look up invalid state name + {__index=function(t, k) + local v = rawget(t, k) + if v then + return v + end + error(string.format('startup module passed invalid state %q', k), 2) + end}) + +-- derive byname as a lookup table to find the 0-based index for a given name +for i, name in pairs(bynum) do + -- the viewer's states are 0-based, not 1-based like Lua indexes + byname[name] = i - 1 +end +-- dbg('startup states: %s', inspect(byname)) + +-- specialize a WaitFor to track the viewer's startup state +local startup_pump = 'StartupState' +local waitfor = leap.WaitFor(0, startup_pump) +function waitfor:filter(pump, data) + if pump == self.name then + return data + end +end + +function waitfor:process(data) + -- keep updating startup._state for interested parties + startup._state = data.str + dbg('startup updating state to %q', data.str) + -- now pass data along to base-class method to queue + leap.WaitFor.process(self, data) +end + +-- listen for StartupState events +leap.request(leap.cmdpump(), + {op='listen', source=startup_pump, listener='startup.lua', tweak=true}) +-- poke LLStartUp to make sure we get an event +leap.send('LLStartUp', {op='postStartupState'}) + +-- --------------------------------------------------------------------------- +-- wait for response from postStartupState +while not startup._state do + dbg('startup.state() waiting for first StartupState event') + waitfor:wait() +end + +-- return a list of all known startup states +function startup.list() + return bynum +end + +-- report whether state with string name 'left' is before string name 'right' +function startup.before(left, right) + return byname[left] < byname[right] +end + +-- report the viewer's current startup state +function startup.state() + return startup._state +end + +-- error if script is called before specified state string name +function startup.ensure(state) + if startup.before(startup.state(), state) then + -- tell error() to pretend this error was thrown by our caller + error('must not be called before startup state ' .. state, 2) + end +end + +-- block calling fiber until viewer has reached state with specified string name +function startup.wait(state) + dbg('startup.wait(%q)', state) + while startup.before(startup.state(), state) do + local item = waitfor:wait() + dbg('startup.wait(%q) sees %s', state, item) + end +end + +return startup diff --git a/indra/newview/scripts/lua/require/timers.lua b/indra/newview/scripts/lua/require/timers.lua new file mode 100644 index 0000000000..e4938078dc --- /dev/null +++ b/indra/newview/scripts/lua/require/timers.lua @@ -0,0 +1,104 @@ +-- Access to the viewer's time-delay facilities + +local leap = require 'leap' +local util = require 'util' + +local timers = {} + +local function dbg(...) end +-- local dbg = require 'printf' + +timers.Timer = {} + +-- delay: time in seconds until callback +-- callback: 'wait', or function to call when timer fires (self:tick if nil) +-- iterate: if non-nil, call callback repeatedly until it returns non-nil +-- (ignored if 'wait') +function timers.Timer:new(delay, callback, iterate) + local obj = setmetatable({}, self) + self.__index = self + + if callback == 'wait' then + dbg('scheduleAfter(%d):', delay) + sequence = leap.generate('Timers', {op='scheduleAfter', after=delay}) + -- ignore the immediate return + dbg('scheduleAfter(%d) -> %s', delay, + sequence.next()) + -- this call is where we wait for real + dbg('next():') + dbg('next() -> %s', + sequence.next()) + sequence.done() + return + end + + callback = callback or function() obj:tick() end + + local first = true + if iterate then + obj.id = leap.eventstream( + 'Timers', + {op='scheduleEvery', every=delay}, + function (event) + local reqid = event.reqid + if first then + first = false + dbg('timer(%s) first callback', reqid) + -- discard the first (immediate) response: don't call callback + return nil + else + dbg('timer(%s) nth callback', reqid) + return callback(event) + end + end + ).reqid + else + obj.id = leap.eventstream( + 'Timers', + {op='scheduleAfter', after=delay}, + function (event) + -- Arrange to return nil the first time, true the second. This + -- callback is called immediately with the response to + -- 'scheduleAfter', and if we immediately returned true, we'd + -- be done, and the subsequent timer event would be discarded. + if first then + first = false + -- Caller doesn't expect an immediate callback. + return nil + else + callback(event) + -- Since caller doesn't want to iterate, the value + -- returned by the callback is irrelevant: just stop after + -- this one and only call. + return true + end + end + ).reqid + end + + return obj +end + +util.classctor(timers.Timer) + +function timers.Timer:tick() + error('Pass a callback to Timer:new(), or override Timer:tick()') +end + +function timers.Timer:cancel() + local ok = leap.request('Timers', {op='cancel', id=self.id}).ok + leap.cancelreq(self.id) + return ok +end + +function timers.Timer:isRunning() + return leap.request('Timers', {op='isRunning', id=self.id}).running +end + +-- returns (true, seconds left) for a live timer, else (false, 0) +function timers.Timer:timeUntilCall() + local result = leap.request('Timers', {op='timeUntilCall', id=self.id}) + return result.ok, result.remaining +end + +return timers diff --git a/indra/newview/scripts/lua/require/util.lua b/indra/newview/scripts/lua/require/util.lua new file mode 100644 index 0000000000..bfbfc8637c --- /dev/null +++ b/indra/newview/scripts/lua/require/util.lua @@ -0,0 +1,69 @@ +-- utility functions, in alpha order + +local util = {} + +-- Allow MyClass(ctor args...) equivalent to MyClass:new(ctor args...) +-- Usage: +-- local MyClass = {} +-- function MyClass:new(...) +-- ... +-- end +-- ... +-- util.classctor(MyClass) +-- or if your constructor is named something other than MyClass:new(), e.g. +-- MyClass:construct(): +-- util.classctor(MyClass, MyClass.construct) +-- return MyClass +function util.classctor(class, ctor) + -- get the metatable for the passed class + local mt = getmetatable(class) + if mt == nil then + -- if it doesn't already have a metatable, then create one + mt = {} + setmetatable(class, mt) + end + -- now that class has a metatable, set its __call method to the specified + -- constructor method (class.new if not specified) + mt.__call = ctor or class.new +end + +-- check if array-like table contains certain value +function util.contains(t, v) + return table.find(t, v) ~= nil +end + +-- reliable count of the number of entries in table t +-- (since #t is unreliable) +function util.count(t) + local count = 0 + for _ in pairs(t) do + count += 1 + end + return count +end + +-- cheap test whether table t is empty +function util.empty(t) + return not next(t) +end + +-- recursive table equality +function util.equal(t1, t2) + if not (type(t1) == 'table' and type(t2) == 'table') then + return t1 == t2 + end + -- both t1 and t2 are tables: get modifiable copy of t2 + local temp = table.clone(t2) + for k, v in pairs(t1) do + -- if any key in t1 doesn't have same value in t2, not equal + if not util.equal(v, temp[k]) then + return false + end + -- temp[k] == t1[k], delete temp[k] + temp[k] = nil + end + -- All keys in t1 have equal values in t2; t2 == t1 if there are no extra keys in t2 + return util.empty(temp) +end + +return util diff --git a/indra/newview/scripts/lua/startup.lua b/indra/newview/scripts/lua/startup.lua deleted file mode 100644 index c3040f94b8..0000000000 --- a/indra/newview/scripts/lua/startup.lua +++ /dev/null @@ -1,100 +0,0 @@ --- query, wait for or mandate a particular viewer startup state - --- During startup, the viewer steps through a sequence of numbered (and named) --- states. This can be used to detect when, for instance, the login screen is --- displayed, or when the viewer has finished logging in and is fully --- in-world. - -local fiber = require 'fiber' -local leap = require 'leap' -local inspect = require 'inspect' -local function dbg(...) end --- local dbg = require 'printf' - --- --------------------------------------------------------------------------- -local startup = {} - --- Get the list of startup states from the viewer. -local bynum = leap.request('LLStartUp', {op='getStateTable'})['table'] - -local byname = setmetatable( - {}, - -- set metatable to throw an error if you look up invalid state name - {__index=function(t, k) - local v = rawget(t, k) - if v then - return v - end - error(string.format('startup module passed invalid state %q', k), 2) - end}) - --- derive byname as a lookup table to find the 0-based index for a given name -for i, name in pairs(bynum) do - -- the viewer's states are 0-based, not 1-based like Lua indexes - byname[name] = i - 1 -end --- dbg('startup states: %s', inspect(byname)) - --- specialize a WaitFor to track the viewer's startup state -local startup_pump = 'StartupState' -local waitfor = leap.WaitFor(0, startup_pump) -function waitfor:filter(pump, data) - if pump == self.name then - return data - end -end - -function waitfor:process(data) - -- keep updating startup._state for interested parties - startup._state = data.str - dbg('startup updating state to %q', data.str) - -- now pass data along to base-class method to queue - leap.WaitFor.process(self, data) -end - --- listen for StartupState events -leap.request(leap.cmdpump(), - {op='listen', source=startup_pump, listener='startup.lua', tweak=true}) --- poke LLStartUp to make sure we get an event -leap.send('LLStartUp', {op='postStartupState'}) - --- --------------------------------------------------------------------------- --- wait for response from postStartupState -while not startup._state do - dbg('startup.state() waiting for first StartupState event') - waitfor:wait() -end - --- return a list of all known startup states -function startup.list() - return bynum -end - --- report whether state with string name 'left' is before string name 'right' -function startup.before(left, right) - return byname[left] < byname[right] -end - --- report the viewer's current startup state -function startup.state() - return startup._state -end - --- error if script is called before specified state string name -function startup.ensure(state) - if startup.before(startup.state(), state) then - -- tell error() to pretend this error was thrown by our caller - error('must not be called before startup state ' .. state, 2) - end -end - --- block calling fiber until viewer has reached state with specified string name -function startup.wait(state) - dbg('startup.wait(%q)', state) - while startup.before(startup.state(), state) do - local item = waitfor:wait() - dbg('startup.wait(%q) sees %s', state, item) - end -end - -return startup diff --git a/indra/newview/scripts/lua/timers.lua b/indra/newview/scripts/lua/timers.lua deleted file mode 100644 index e4938078dc..0000000000 --- a/indra/newview/scripts/lua/timers.lua +++ /dev/null @@ -1,104 +0,0 @@ --- Access to the viewer's time-delay facilities - -local leap = require 'leap' -local util = require 'util' - -local timers = {} - -local function dbg(...) end --- local dbg = require 'printf' - -timers.Timer = {} - --- delay: time in seconds until callback --- callback: 'wait', or function to call when timer fires (self:tick if nil) --- iterate: if non-nil, call callback repeatedly until it returns non-nil --- (ignored if 'wait') -function timers.Timer:new(delay, callback, iterate) - local obj = setmetatable({}, self) - self.__index = self - - if callback == 'wait' then - dbg('scheduleAfter(%d):', delay) - sequence = leap.generate('Timers', {op='scheduleAfter', after=delay}) - -- ignore the immediate return - dbg('scheduleAfter(%d) -> %s', delay, - sequence.next()) - -- this call is where we wait for real - dbg('next():') - dbg('next() -> %s', - sequence.next()) - sequence.done() - return - end - - callback = callback or function() obj:tick() end - - local first = true - if iterate then - obj.id = leap.eventstream( - 'Timers', - {op='scheduleEvery', every=delay}, - function (event) - local reqid = event.reqid - if first then - first = false - dbg('timer(%s) first callback', reqid) - -- discard the first (immediate) response: don't call callback - return nil - else - dbg('timer(%s) nth callback', reqid) - return callback(event) - end - end - ).reqid - else - obj.id = leap.eventstream( - 'Timers', - {op='scheduleAfter', after=delay}, - function (event) - -- Arrange to return nil the first time, true the second. This - -- callback is called immediately with the response to - -- 'scheduleAfter', and if we immediately returned true, we'd - -- be done, and the subsequent timer event would be discarded. - if first then - first = false - -- Caller doesn't expect an immediate callback. - return nil - else - callback(event) - -- Since caller doesn't want to iterate, the value - -- returned by the callback is irrelevant: just stop after - -- this one and only call. - return true - end - end - ).reqid - end - - return obj -end - -util.classctor(timers.Timer) - -function timers.Timer:tick() - error('Pass a callback to Timer:new(), or override Timer:tick()') -end - -function timers.Timer:cancel() - local ok = leap.request('Timers', {op='cancel', id=self.id}).ok - leap.cancelreq(self.id) - return ok -end - -function timers.Timer:isRunning() - return leap.request('Timers', {op='isRunning', id=self.id}).running -end - --- returns (true, seconds left) for a live timer, else (false, 0) -function timers.Timer:timeUntilCall() - local result = leap.request('Timers', {op='timeUntilCall', id=self.id}) - return result.ok, result.remaining -end - -return timers diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua deleted file mode 100644 index bfbfc8637c..0000000000 --- a/indra/newview/scripts/lua/util.lua +++ /dev/null @@ -1,69 +0,0 @@ --- utility functions, in alpha order - -local util = {} - --- Allow MyClass(ctor args...) equivalent to MyClass:new(ctor args...) --- Usage: --- local MyClass = {} --- function MyClass:new(...) --- ... --- end --- ... --- util.classctor(MyClass) --- or if your constructor is named something other than MyClass:new(), e.g. --- MyClass:construct(): --- util.classctor(MyClass, MyClass.construct) --- return MyClass -function util.classctor(class, ctor) - -- get the metatable for the passed class - local mt = getmetatable(class) - if mt == nil then - -- if it doesn't already have a metatable, then create one - mt = {} - setmetatable(class, mt) - end - -- now that class has a metatable, set its __call method to the specified - -- constructor method (class.new if not specified) - mt.__call = ctor or class.new -end - --- check if array-like table contains certain value -function util.contains(t, v) - return table.find(t, v) ~= nil -end - --- reliable count of the number of entries in table t --- (since #t is unreliable) -function util.count(t) - local count = 0 - for _ in pairs(t) do - count += 1 - end - return count -end - --- cheap test whether table t is empty -function util.empty(t) - return not next(t) -end - --- recursive table equality -function util.equal(t1, t2) - if not (type(t1) == 'table' and type(t2) == 'table') then - return t1 == t2 - end - -- both t1 and t2 are tables: get modifiable copy of t2 - local temp = table.clone(t2) - for k, v in pairs(t1) do - -- if any key in t1 doesn't have same value in t2, not equal - if not util.equal(v, temp[k]) then - return false - end - -- temp[k] == t1[k], delete temp[k] - temp[k] = nil - end - -- All keys in t1 have equal values in t2; t2 == t1 if there are no extra keys in t2 - return util.empty(temp) -end - -return util diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 53039fbd99..20dced2341 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -169,6 +169,8 @@ class ViewerManifest(LLManifest): with self.prefix(src_dst="scripts/lua"): self.path("*.lua") self.path("*.xml") + with self.prefix(src_dst='require'): + self.path("*.lua") #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing @@ -285,7 +287,7 @@ class ViewerManifest(LLManifest): # A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names names = [] for line in lines : - if re.match("\S", line) : + if re.match(r"\S", line) : names.append(line.rstrip()) # It's not fair to always put the same people at the head of the list random.shuffle(names) -- cgit v1.2.3 From c4fc76efefd12c7cb1224dc8a748da2958f4a7f0 Mon Sep 17 00:00:00 2001 From: AiraYumi <aira.youme@airanyumi.net> Date: Thu, 13 Jun 2024 10:39:05 +0900 Subject: Revert "Replace LL_X11 and LL_FLTK to LL_LINUX" --- indra/newview/lldirpicker.cpp | 12 ++++++------ indra/newview/lldirpicker.h | 2 +- indra/newview/llfilepicker.cpp | 6 +++--- indra/newview/llfilepicker.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 957bd6a4d3..75875551f4 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -41,7 +41,7 @@ # include "llfilepicker.h" #endif -#ifdef LL_LINUX +#ifdef LL_FLTK #include "FL/Fl.H" #include "FL/Fl_Native_File_Chooser.H" #endif @@ -197,7 +197,7 @@ LLDirPicker::LLDirPicker() : mFileName(NULL), mLocked(false) { -#ifndef LL_LINUX +#ifndef LL_FLTK mFilePicker = new LLFilePicker(); #endif reset(); @@ -205,7 +205,7 @@ LLDirPicker::LLDirPicker() : LLDirPicker::~LLDirPicker() { -#ifndef LL_LINUX +#ifndef LL_FLTK delete mFilePicker; #endif } @@ -213,7 +213,7 @@ LLDirPicker::~LLDirPicker() void LLDirPicker::reset() { -#ifndef LL_LINUX +#ifndef LL_FLTK if (mFilePicker) mFilePicker->reset(); #else @@ -231,7 +231,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) return FALSE; } -#ifdef LL_LINUX +#ifdef LL_FLTK gViewerWindow->getWindow()->beforeDialog(); Fl_Native_File_Chooser flDlg; flDlg.title(LLTrans::getString("choose_the_directory").c_str()); @@ -254,7 +254,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) std::string LLDirPicker::getDirName() { -#ifndef LL_LINUX +#ifndef LL_FLTK if (mFilePicker) { return mFilePicker->getFirstFile(); diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 5a3316d500..bcc7792c1a 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -80,7 +80,7 @@ private: #if LL_LINUX || LL_DARWIN // On Linux we just implement LLDirPicker on top of LLFilePicker -#ifndef LL_LINUX +#ifndef LL_FLTK LLFilePicker *mFilePicker; #endif #endif diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 5be987f92a..d6f3727643 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -40,7 +40,7 @@ #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers #endif // LL_SDL -#ifdef LL_LINUX +#ifdef LL_FLTK #include "FL/Fl.H" #include "FL/Fl_Native_File_Chooser.H" #endif @@ -1101,7 +1101,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, #elif LL_LINUX -#if LL_LINUX +#if LL_FLTK BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, const std::string& filename, @@ -1410,7 +1410,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, return FALSE; } -#endif // LL_LINUX +#endif // LL_FLTK #else // not implemented diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index ddf3d7ca16..1ca4137ac6 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -172,7 +172,7 @@ private: void *userdata); #endif -#if LL_LINUX +#if LL_FLTK enum EType { eSaveFile, eOpenFile, eOpenMultiple -- cgit v1.2.3 From bfadb935560003e94197a0c9532a7ba086c6720a Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Fri, 14 Jun 2024 22:00:57 +0300 Subject: Linux build fix (#1774) --- indra/newview/llfilepicker.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index d2c041249b..aaf6c5cc8d 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1291,6 +1291,9 @@ bool LLFilePicker::openFileDialog( int32_t filter, bool blocking, EType aType ) case FFLOAD_MATERIAL_TEXTURE: file_dialog_filter = "*.{gltf,glb,tga,bmp,jpg,jpeg,png}"; file_type = "image_files"; + break; + case FFLOAD_HDRI: + file_dialog_filter = "*.exr"; } if (aType == EType::eOpenMultiple) -- cgit v1.2.3 From 5155ee94b912337ed0edb3b910a6e68d9a8cd994 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Mon, 17 Jun 2024 12:36:12 +0200 Subject: #1080 BugSplat Crash: LLAppViewer::initStrings() - show crash reason --- indra/newview/llappviewer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 77d9bc305a..3fe769c1e9 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2998,9 +2998,10 @@ void LLAppViewer::initStrings() std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) { + std::string crash_reason; if (strings_path_full.empty()) { - LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; + crash_reason = "The file '" + strings_file + "' is not found"; } else { @@ -3008,24 +3009,23 @@ void LLAppViewer::initStrings() int rc = LLFile::stat(strings_path_full, &st); if (rc != 0) { - LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; + crash_reason = "The file '" + strings_path_full + "' failed to get status. Error code: " + std::to_string(rc); } else if (S_ISDIR(st.st_mode)) { - LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; + crash_reason = "The filename '" + strings_path_full + "' is a directory name"; } else { - LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; + crash_reason = "The filename '" + strings_path_full + "' doesn't seem to be a regular file name"; } } // initial check to make sure files are there failed gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Viewer failed to find localization and UI files." - << " Please reinstall viewer from https://secondlife.com/support/downloads" - << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; + LL_ERRS() << "Viewer failed to open some of localization and UI files." + << " " << crash_reason << "." << LL_ENDL; } LLTransUtil::parseStrings(strings_file, default_trans_args); LLTransUtil::parseLanguageStrings("language_settings.xml"); -- cgit v1.2.3 From 5b6a5c757deaba3c2b361eb49f2e61630fe3eb47 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 17 Jun 2024 11:18:09 -0400 Subject: Store script's LuaListener in userdata in lua_State's Registry. Instead of deriving LuaListener from LLInstanceTracker with an int key, generating a unique int key and storing that key in the Registry, use new lua_emplace<LuaState>() to store the LuaListener directly in a Lua userdata object in the Lua Registry. Because lua_emplace<T>() uses LL.atexit() to guarantee that ~LuaState will destroy the T object, we no longer need ~LuaState() to make a special call specifically to destroy the LuaListener, if any. So we no longer need LuaState::getListener() separate from obtainListener(). Since LuaListener is no longer an LLInstanceTracker subclass, make LuaState::obtainListener() return LuaListener& rather than LuaListener::ptr_t. --- indra/newview/llluamanager.cpp | 10 +++++----- indra/newview/tests/llluamanager_test.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 5aa47d7566..8b6f7a4698 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -139,10 +139,10 @@ lua_function(get_event_pumps, "post_on(commandpump, ...) to engage LLEventAPI operations (see helpleap()).") { luaL_checkstack(L, 2, nullptr); - auto listener{ LuaState::obtainListener(L) }; + auto& listener{ LuaState::obtainListener(L) }; // return the reply pump name and the command pump name on caller's lua_State - lua_pushstdstring(L, listener->getReplyName()); - lua_pushstdstring(L, listener->getCommandName()); + lua_pushstdstring(L, listener.getReplyName()); + lua_pushstdstring(L, listener.getCommandName()); return 2; } @@ -153,8 +153,8 @@ lua_function(get_event_next, "event becomes available.") { luaL_checkstack(L, 2, nullptr); - auto listener{ LuaState::obtainListener(L) }; - const auto& [pump, data]{ listener->getNext() }; + auto& listener{ LuaState::obtainListener(L) }; + const auto& [pump, data]{ listener.getNext() }; lua_pushstdstring(L, pump); lua_pushllsd(L, data); lluau::set_interrupts_counter(L, 0); diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index cf1bf25b5c..2d525f7913 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -398,7 +398,7 @@ namespace tut LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); - auto replyname{ L.obtainListener()->getReplyName() }; + auto replyname{ L.obtainListener().getReplyName() }; auto& replypump{ LLEventPumps::instance().obtain(replyname) }; // LuaState::expr() periodically interrupts a running chunk to ensure // the rest of our coroutines get cycles. Nonetheless, for this test -- cgit v1.2.3 From a65bc46b138b89200586b29fe729cbc7b0f0c8c4 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Mon, 17 Jun 2024 17:25:45 +0200 Subject: Fix shaders broken in merge --- indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl | 2 -- .../app_settings/shaders/class3/deferred/reflectionProbeF.glsl | 2 +- .../newview/app_settings/shaders/class3/deferred/softenLightF.glsl | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 94d5664815..e9f849a8c0 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -79,8 +79,6 @@ float getAmbientClamp(); void mirrorClip(vec3 pos); -void mirrorClip(vec3 pos); - void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index ae3188cebd..47ec8fba55 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -452,7 +452,7 @@ void boxIntersectionDebug( in vec3 ro, in vec3 p, vec3 boxSize, inout vec4 col) void boxIntersectDebug(vec3 origin, vec3 pos, mat4 i, inout vec4 col) { - mat4 clipToLocal = refBox[i]; + mat4 clipToLocal = i; // transform into unit cube space origin = (clipToLocal * vec4(origin, 1.0)).xyz; diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 8db04f2c18..494a69efd0 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -169,7 +169,7 @@ void main() if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - vec3 orm = texture(specularRect, tc).rgb; + vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; float ao = orm.r; @@ -179,7 +179,7 @@ void main() float gloss = 1.0 - perceptualRoughness; sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss, false, amblit_linear); - + adjustIrradiance(irradiance, ambocc); vec3 diffuseColor; @@ -215,7 +215,7 @@ void main() vec3 legacyenv = vec3(0); sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, norm.xyz, spec.a, envIntensity, false, amblit_linear); - + adjustIrradiance(irradiance, ambocc); // apply lambertian IBL only (see pbrIbl) -- cgit v1.2.3 From b2d484d7258508f0f82098ff113fa636554d67b8 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 17 Jun 2024 20:05:56 +0300 Subject: Remove useless 'coro_name' info --- indra/newview/llfloaterimnearbychatlistener.cpp | 9 ++++----- indra/newview/llluamanager.cpp | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index 78642bce21..e61bf5ffc2 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -54,12 +54,11 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() add("listen", "Start listening to the Nearby chat, chat messages will be resent to the script event pump", &LLFloaterIMNearbyChatListener::listenChat, - llsd::map("coro_name", LLSD(), "reply", LLSD())); + llsd::map("reply", LLSD())); add("stopListening", "Stop listening to the Nearby chat", - &LLFloaterIMNearbyChatListener::stopListeningChat, - llsd::map("coro_name", LLSD())); + &LLFloaterIMNearbyChatListener::stopListeningChat); mOutConnection = LLEventPumps::instance().obtain("LLNearbyChat").listen("LLFloaterIMNearbyChatListener", [this](const LLSD &data) { @@ -136,10 +135,10 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) void LLFloaterIMNearbyChatListener::listenChat(LLSD const &chat_data) { - mReplyPumps[chat_data["coro_name"].asString()] = chat_data["reply"].asString(); + mReplyPumps[LLCoros::getName()] = chat_data["reply"].asString(); } void LLFloaterIMNearbyChatListener::stopListeningChat(LLSD const &chat_data) { - mReplyPumps.erase(chat_data["coro_name"].asString()); + mReplyPumps.erase(LLCoros::getName()); } diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index d8e53f3e69..97779a12ad 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -128,7 +128,7 @@ lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLSD data{ lua_tollsd(L, 2) }; lua_pop(L, 2); LL_DEBUGS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL; - LLEventPumps::instance().obtain(pumpname).post(data.with("coro_name", LLCoros::getName())); + LLEventPumps::instance().obtain(pumpname).post(data); return 0; } -- cgit v1.2.3 From e26727e03bb02d26b3f0d83f748dbd8eb88e4940 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 18 Jun 2024 13:13:39 -0400 Subject: Remove special-case ~LuaState() code to call fiber.run(). Instead, make fiber.lua call LL.atexit(fiber.run) to schedule that final run() call at ~LuaState() time using the generic mechanism. Append an explicit fiber.run() call to a specific test in llluamanager_test.cpp because the test code wants to interact with multiple Lua fibers *before* we destroy the LuaState. --- indra/newview/scripts/lua/require/fiber.lua | 6 ++++++ indra/newview/tests/llluamanager_test.cpp | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/fiber.lua b/indra/newview/scripts/lua/require/fiber.lua index cae27b936b..b3c684dd67 100644 --- a/indra/newview/scripts/lua/require/fiber.lua +++ b/indra/newview/scripts/lua/require/fiber.lua @@ -337,4 +337,10 @@ function fiber.run() return idle_done end +-- Make sure we finish up with a call to run(). That allows a consuming script +-- to kick off some number of fibers, do some work on the main thread and then +-- fall off the end of the script without explicitly calling fiber.run(). +-- run() ensures the rest of the fibers run to completion (or error). +LL.atexit(fiber.run) + return fiber diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 2d525f7913..206dbd9e71 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -385,6 +385,12 @@ namespace tut "fiber.launch('catch_special', drain, catch_special)\n" "fiber.launch('requester(a)', requester, 'a')\n" "fiber.launch('requester(b)', requester, 'b')\n" + // A script can normally count on an implicit fiber.run() call + // because fiber.lua calls LL.atexit(fiber.run). But atexit() + // functions are called by ~LuaState(), which (in the code below) + // won't be called until *after* we expect to interact with the + // various fibers. So make an explicit call for test purposes. + "fiber.run()\n" ); LLSD requests; -- cgit v1.2.3 From c6001e6a20389b4d32813c7f61b56ff79f575723 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 18 Jun 2024 18:01:39 -0400 Subject: Improve diagnostic output from running 'require' module. --- indra/newview/llluamanager.cpp | 75 +++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 27 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 8b6f7a4698..3ed72c34f3 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -454,45 +454,70 @@ bool LLRequireResolver::findModuleImpl(const std::string& absolutePath) void LLRequireResolver::runModule(const std::string& desc, const std::string& code) { // Here we just loaded a new module 'code', need to run it and get its result. - // Module needs to run in a new thread, isolated from the rest. - // Note: we create ML on main thread so that it doesn't inherit environment of L. - lua_State *GL = lua_mainthread(L); -// lua_State *ML = lua_newthread(GL); - // Try loading modules on Lua's main thread instead. - lua_State *ML = GL; - // lua_newthread() pushed the new thread object on GL's stack. Move to L's. -// lua_xmove(GL, L, 1); - - // new thread needs to have the globals sandboxed -// luaL_sandboxthread(ML); + lua_State *ML = lua_mainthread(L); { // If loadstring() returns (! LUA_OK) then there's an error message on // the stack. If it returns LUA_OK then the newly-loaded module code // is on the stack. - if (lluau::loadstring(ML, desc, code) == LUA_OK) + LL_DEBUGS("Lua") << "Loading module " << desc << LL_ENDL; + if (lluau::loadstring(ML, desc, code) != LUA_OK) { - // luau uses Lua 5.3's version of lua_resume(): - // run the coroutine on ML, "from" L, passing no arguments. -// int status = lua_resume(ML, L, 0); - // we expect one return value - int status = lua_pcall(ML, 0, 1, 0); + // error message on stack top + LL_DEBUGS("Lua") << "Error loading module " << desc << ": " + << lua_tostring(ML, -1) << LL_ENDL; + lua_pushliteral(ML, "loadstring: "); + // stack contains error, "loadstring: " + // swap: insert stack top at position -2 + lua_insert(ML, -2); + // stack contains "loadstring: ", error + lua_concat(ML, 2); + // stack contains "loadstring: " + error + } + else // module code on stack top + { + // push debug module + lua_getglobal(ML, "debug"); + // push debug.traceback + lua_getfield(ML, -1, "traceback"); + // stack contains module code, debug, debug.traceback + // ditch debug + lua_replace(ML, -2); + // stack contains module code, debug.traceback + // swap: insert stack top at position -2 + lua_insert(ML, -2); + // stack contains debug.traceback, module code + LL_DEBUGS("Lua") << "Loaded module " << desc << ", running" << LL_ENDL; + // no arguments, one return value + // pass debug.traceback as the error function + int status = lua_pcall(ML, 0, 1, -2); + // lua_pcall() has popped the module code and replaced it with its + // return value. Regardless of status or the type of the stack + // top, get rid of debug.traceback on the stack. + lua_remove(ML, -2); if (status == LUA_OK) { - if (lua_gettop(ML) == 0) - lua_pushfstring(ML, "module %s must return a value", desc.data()); - else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1)) + auto top{ lua_gettop(ML) }; + std::string type{ (top == 0)? "nothing" + : lua_typename(ML, lua_type(ML, -1)) }; + LL_DEBUGS("Lua") << "Module " << desc << " returned " << type << LL_ENDL; + if ((top == 0) || ! (lua_istable(ML, -1) || lua_isfunction(ML, -1))) + { lua_pushfstring(ML, "module %s must return a table or function, not %s", - desc.data(), lua_typename(ML, lua_type(ML, -1))); + desc.data(), type.data()); + } } else if (status == LUA_YIELD) { + LL_DEBUGS("Lua") << "Module " << desc << " yielded" << LL_ENDL; lua_pushfstring(ML, "module %s can not yield", desc.data()); } - else if (!lua_isstring(ML, -1)) + else { - lua_pushfstring(ML, "unknown error while running module %s", desc.data()); + llassert(lua_isstring(ML, -1)); + LL_DEBUGS("Lua") << "Module " << desc << " error: " + << lua_tostring(ML, -1) << LL_ENDL; } } } @@ -502,8 +527,4 @@ void LLRequireResolver::runModule(const std::string& desc, const std::string& co { lua_xmove(ML, L, 1); } - // remove ML from L's stack -// lua_remove(L, -2); -// // DON'T call lua_close(ML)! Since ML is only a thread of L, corrupts L too! -// lua_close(ML); } -- cgit v1.2.3 From 165b3cb04266f96f7fc48f542f915b93a4795aaf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 19 Jun 2024 10:10:53 -0400 Subject: Move popup.lua to require subdir with the rest of the modules. --- indra/newview/scripts/lua/popup.lua | 32 ----------------------------- indra/newview/scripts/lua/require/popup.lua | 32 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 indra/newview/scripts/lua/popup.lua create mode 100644 indra/newview/scripts/lua/require/popup.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/popup.lua b/indra/newview/scripts/lua/popup.lua deleted file mode 100644 index 8a01ab7836..0000000000 --- a/indra/newview/scripts/lua/popup.lua +++ /dev/null @@ -1,32 +0,0 @@ -local leap = require 'leap' - --- notification is any name defined in notifications.xml as --- <notification name=> --- vars is a table providing values for [VAR] substitution keys in the --- notification body. -local popup_meta = { - -- setting this function as getmetatable(popup).__call() means this gets - -- called when a consumer calls popup(notification, vars, payload) - __call = function(self, notification, vars, payload) - return leap.request('LLNotifications', - {op='requestAdd', name=notification, - substitutions=vars, - payload=payload}) - end -} - -local popup = setmetatable({}, popup_meta) - -function popup:alert(message) - return self('GenericAlert', {MESSAGE=message}) -end - -function popup:alertOK(message) - return self('GenericAlertOK', {MESSAGE=message}) -end - -function popup:alertYesCancel(message) - return self('GenericAlertYesCancel', {MESSAGE=message}) -end - -return popup diff --git a/indra/newview/scripts/lua/require/popup.lua b/indra/newview/scripts/lua/require/popup.lua new file mode 100644 index 0000000000..8a01ab7836 --- /dev/null +++ b/indra/newview/scripts/lua/require/popup.lua @@ -0,0 +1,32 @@ +local leap = require 'leap' + +-- notification is any name defined in notifications.xml as +-- <notification name=> +-- vars is a table providing values for [VAR] substitution keys in the +-- notification body. +local popup_meta = { + -- setting this function as getmetatable(popup).__call() means this gets + -- called when a consumer calls popup(notification, vars, payload) + __call = function(self, notification, vars, payload) + return leap.request('LLNotifications', + {op='requestAdd', name=notification, + substitutions=vars, + payload=payload}) + end +} + +local popup = setmetatable({}, popup_meta) + +function popup:alert(message) + return self('GenericAlert', {MESSAGE=message}) +end + +function popup:alertOK(message) + return self('GenericAlertOK', {MESSAGE=message}) +end + +function popup:alertYesCancel(message) + return self('GenericAlertYesCancel', {MESSAGE=message}) +end + +return popup -- cgit v1.2.3 From 09b814a2dc6d3a647d75bcf0a310eba2678a0228 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 20 Jun 2024 00:42:25 +0300 Subject: Use LLLeapListener to listen to LLNearbyChat pump --- indra/newview/llfloaterimnearbychatlistener.cpp | 39 ----------------------- indra/newview/llfloaterimnearbychatlistener.h | 7 ---- indra/newview/scripts/lua/LLChatListener.lua | 12 ++++--- indra/newview/scripts/lua/test_LLChatListener.lua | 3 +- 4 files changed, 10 insertions(+), 51 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index e61bf5ffc2..0618741cc4 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -33,7 +33,6 @@ #include "llagent.h" #include "llchat.h" -#include "llluamanager.h" #include "llviewercontrol.h" #include "stringize.h" @@ -50,34 +49,6 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() "[\"channel\"] chat channel number [default = 0]\n" "[\"type\"] chat type \"whisper\", \"normal\", \"shout\" [default = \"normal\"]", &LLFloaterIMNearbyChatListener::sendChat); - - add("listen", - "Start listening to the Nearby chat, chat messages will be resent to the script event pump", - &LLFloaterIMNearbyChatListener::listenChat, - llsd::map("reply", LLSD())); - - add("stopListening", - "Stop listening to the Nearby chat", - &LLFloaterIMNearbyChatListener::stopListeningChat); - - mOutConnection = LLEventPumps::instance().obtain("LLNearbyChat").listen("LLFloaterIMNearbyChatListener", [this](const LLSD &data) - { - std::map<std::string, std::string> reply_pumps = mReplyPumps; - std::map<std::string, std::string> scripts = LLLUAmanager::getScriptNames(); - for (auto &it : reply_pumps) - { - //check if listener script is still running - if (scripts.find(it.first) != scripts.end()) - { - LLEventPumps::instance().obtain(it.second).post(data); - } - else - { - mReplyPumps.erase(it.first); - } - } - return false; - }); } @@ -132,13 +103,3 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) gSavedSettings.getBOOL("PlayChatAnim")); } - -void LLFloaterIMNearbyChatListener::listenChat(LLSD const &chat_data) -{ - mReplyPumps[LLCoros::getName()] = chat_data["reply"].asString(); -} - -void LLFloaterIMNearbyChatListener::stopListeningChat(LLSD const &chat_data) -{ - mReplyPumps.erase(LLCoros::getName()); -} diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index a466db8e5f..18a8bacfaa 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -43,14 +43,7 @@ public: private: void sendChat(LLSD const & chat_data); - void listenChat(LLSD const &chat_data); - void stopListeningChat(LLSD const &chat_data); - F64 mLastThrottleTime{ 0.0 }; - - LLTempBoundListener mOutConnection; - std::map<std::string, std::string> mReplyPumps; - }; #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H diff --git a/indra/newview/scripts/lua/LLChatListener.lua b/indra/newview/scripts/lua/LLChatListener.lua index d615ae5dbc..b4e90d272c 100644 --- a/indra/newview/scripts/lua/LLChatListener.lua +++ b/indra/newview/scripts/lua/LLChatListener.lua @@ -1,8 +1,10 @@ local fiber = require 'fiber' local inspect = require 'inspect' +local leap = require 'leap' local LLChatListener = {} local waitfor = {} +local listener_name = {} function LLChatListener:new() local obj = setmetatable({}, self) @@ -13,14 +15,16 @@ function LLChatListener:new() end function LLChatListener:handleMessages(event_data) - --print(inspect(event_data)) + print(inspect(event_data)) return true end function LLChatListener:start() waitfor = leap.WaitFor:new(-1, self.name) function waitfor:filter(pump, data) - return data + if pump == "LLNearbyChat" then + return data + end end fiber.launch(self.name, function() @@ -30,11 +34,11 @@ function LLChatListener:start() end end) - leap.send('LLChatBar', {op='listen'}) + listener_name = leap.request(leap.cmdpump(), {op='listen', source='LLNearbyChat', listener="ChatListener", tweak=true}).listener end function LLChatListener:stop() - leap.send('LLChatBar', {op='stopListening'}) + leap.send(leap.cmdpump(), {op='stoplistening', source='LLNearbyChat', listener=listener_name}) waitfor:close() end diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua index 2c7b1dc3e5..b9696e7cfc 100644 --- a/indra/newview/scripts/lua/test_LLChatListener.lua +++ b/indra/newview/scripts/lua/test_LLChatListener.lua @@ -1,5 +1,6 @@ local LLChatListener = require 'LLChatListener' local LLChat = require 'LLChat' +local leap = require 'leap' function openOrEcho(message) local floater_name = string.match(message, "^open%s+(%w+)") @@ -21,7 +22,7 @@ function listener:handleMessages(event_data) else openOrEcho(event_data.message) end - return LLChatListener.handleMessages(self, event_data) + return true end listener:start() -- cgit v1.2.3 From 350225e54ba02a7523e17106936a4ce44af91e55 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 20 Jun 2024 10:55:19 -0400 Subject: Give popup() the ability to not wait; add popup:tip(message). popup:tip() engages 'SystemMessageTip'. --- indra/newview/scripts/lua/require/popup.lua | 33 +++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/popup.lua b/indra/newview/scripts/lua/require/popup.lua index 8a01ab7836..3aaadf85ba 100644 --- a/indra/newview/scripts/lua/require/popup.lua +++ b/indra/newview/scripts/lua/require/popup.lua @@ -1,17 +1,34 @@ local leap = require 'leap' +local mapargs = require 'mapargs' -- notification is any name defined in notifications.xml as -- <notification name=> -- vars is a table providing values for [VAR] substitution keys in the --- notification body. +-- notification body +-- payload prepopulates the response table +-- wait=false means fire and forget, otherwise wait for user response local popup_meta = { -- setting this function as getmetatable(popup).__call() means this gets -- called when a consumer calls popup(notification, vars, payload) - __call = function(self, notification, vars, payload) - return leap.request('LLNotifications', - {op='requestAdd', name=notification, - substitutions=vars, - payload=payload}) + __call = function(self, ...) + local args = mapargs('notification,vars,payload,wait', ...) + -- we use convenience argument names different from 'LLNotifications' + -- listener + args.name = args.notification + args.notification = nil + args.substitutions = args.vars + args.vars = nil + local wait = args.wait + args.wait = nil + args.op = 'requestAdd' + -- Specifically test (wait == false), NOT (not wait), because we treat + -- nil (omitted, default true) differently than false (explicitly + -- DON'T wait). + if wait == false then + leap.send('LLNotifications', args) + else + return leap.request('LLNotifications', args).response + end end } @@ -29,4 +46,8 @@ function popup:alertYesCancel(message) return self('GenericAlertYesCancel', {MESSAGE=message}) end +function popup:tip(message) + self{'SystemMessageTip', {MESSAGE=message}, wait=false} +end + return popup -- cgit v1.2.3 From 3a2018ddda6feb1aaa023106f95de6d8e0a0b507 Mon Sep 17 00:00:00 2001 From: nat-goodspeed <nat@lindenlab.com> Date: Thu, 20 Jun 2024 12:56:35 -0400 Subject: Revert LLLuaFloater "idle" events in favor of Lua timers.Timer(). --- .../newview/scripts/lua/test_luafloater_speedometer.lua | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_speedometer.lua b/indra/newview/scripts/lua/test_luafloater_speedometer.lua index 610401ae44..a9d3a70330 100644 --- a/indra/newview/scripts/lua/test_luafloater_speedometer.lua +++ b/indra/newview/scripts/lua/test_luafloater_speedometer.lua @@ -1,18 +1,23 @@ local Floater = require 'Floater' +local leap = require 'leap' +local LLNotification = require 'LLNotification' local startup = require 'startup' -inspect = require 'inspect' -leap = require 'leap' -LLNotification = require 'LLNotification' +local Timer = (require 'timers').Timer local max_speed = 0 local flt = Floater:new("luafloater_speedometer.xml") startup.wait('STATE_STARTED') +local timer + function flt:floater_close(event_data) + if timer then + timer:cancel() + end msg = "Registered max speed: " .. string.format("%.2f", max_speed) .. " m/s"; LLNotification.add('SystemMessageTip', {MESSAGE = msg}) end -function flt:idle(event_data) +local function idle(event_data) local speed = leap.request('LLVOAvatar', {op='getSpeed'})['value'] flt:post({action="set_value", ctrl_name="speed_lbl", value = string.format("%.2f", speed)}) max_speed=math.max(max_speed, speed) @@ -22,5 +27,6 @@ msg = 'Are you sure you want to run this "speedometer" script?' response = LLNotification.requestAdd('GenericAlertYesCancel', {MESSAGE = msg}) if response.OK_okcancelbuttons then - flt:show() + flt:show() + timer = Timer:new(1, idle, true) -- iterate end -- cgit v1.2.3 From 6d29c1fcf80441cc4619e672ca07469cc3efe100 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 20 Jun 2024 16:21:17 -0400 Subject: Use new popup.lua, which supersedes LLNotification.lua. Use ClassName(ctor args) for classes using util.classctor(). --- indra/newview/scripts/lua/LLNotification.lua | 15 --------------- indra/newview/scripts/lua/test_luafloater_speedometer.lua | 11 +++++------ 2 files changed, 5 insertions(+), 21 deletions(-) delete mode 100644 indra/newview/scripts/lua/LLNotification.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/LLNotification.lua b/indra/newview/scripts/lua/LLNotification.lua deleted file mode 100644 index f47730d1cc..0000000000 --- a/indra/newview/scripts/lua/LLNotification.lua +++ /dev/null @@ -1,15 +0,0 @@ --- Engage the LLNotificationsListener LLEventAPI - -leap = require 'leap' - -local LLNotification = {} - -function LLNotification.add(name, substitutions) - leap.send('LLNotifications', {op='requestAdd', name=name, substitutions=substitutions}) -end - -function LLNotification.requestAdd(name, substitutions) - return leap.request('LLNotifications', {op='requestAdd', name=name, substitutions=substitutions})['response'] -end - -return LLNotification diff --git a/indra/newview/scripts/lua/test_luafloater_speedometer.lua b/indra/newview/scripts/lua/test_luafloater_speedometer.lua index a9d3a70330..af7189a2cb 100644 --- a/indra/newview/scripts/lua/test_luafloater_speedometer.lua +++ b/indra/newview/scripts/lua/test_luafloater_speedometer.lua @@ -1,10 +1,10 @@ local Floater = require 'Floater' local leap = require 'leap' -local LLNotification = require 'LLNotification' +local popup = require 'popup' local startup = require 'startup' local Timer = (require 'timers').Timer local max_speed = 0 -local flt = Floater:new("luafloater_speedometer.xml") +local flt = Floater("luafloater_speedometer.xml") startup.wait('STATE_STARTED') local timer @@ -13,8 +13,7 @@ function flt:floater_close(event_data) if timer then timer:cancel() end - msg = "Registered max speed: " .. string.format("%.2f", max_speed) .. " m/s"; - LLNotification.add('SystemMessageTip', {MESSAGE = msg}) + popup:tip(string.format("Registered max speed: %.2f m/s", max_speed)) end local function idle(event_data) @@ -24,9 +23,9 @@ local function idle(event_data) end msg = 'Are you sure you want to run this "speedometer" script?' -response = LLNotification.requestAdd('GenericAlertYesCancel', {MESSAGE = msg}) +response = popup:alertYesCancel(msg) if response.OK_okcancelbuttons then flt:show() - timer = Timer:new(1, idle, true) -- iterate + timer = Timer(1, idle, true) -- iterate end -- cgit v1.2.3 From 5dbca6bb3ed33cb8f19ea3871ce7ef9f07957088 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 10:06:55 -0400 Subject: Move newer Lua modules to scripts/lua/require subdirectory. --- indra/newview/scripts/lua/LLChatListener.lua | 45 ------------- indra/newview/scripts/lua/login.lua | 19 ------ indra/newview/scripts/lua/mapargs.lua | 73 ---------------------- .../newview/scripts/lua/require/LLChatListener.lua | 45 +++++++++++++ indra/newview/scripts/lua/require/login.lua | 19 ++++++ indra/newview/scripts/lua/require/mapargs.lua | 73 ++++++++++++++++++++++ 6 files changed, 137 insertions(+), 137 deletions(-) delete mode 100644 indra/newview/scripts/lua/LLChatListener.lua delete mode 100644 indra/newview/scripts/lua/login.lua delete mode 100644 indra/newview/scripts/lua/mapargs.lua create mode 100644 indra/newview/scripts/lua/require/LLChatListener.lua create mode 100644 indra/newview/scripts/lua/require/login.lua create mode 100644 indra/newview/scripts/lua/require/mapargs.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/LLChatListener.lua b/indra/newview/scripts/lua/LLChatListener.lua deleted file mode 100644 index b4e90d272c..0000000000 --- a/indra/newview/scripts/lua/LLChatListener.lua +++ /dev/null @@ -1,45 +0,0 @@ -local fiber = require 'fiber' -local inspect = require 'inspect' -local leap = require 'leap' - -local LLChatListener = {} -local waitfor = {} -local listener_name = {} - -function LLChatListener:new() - local obj = setmetatable({}, self) - self.__index = self - obj.name = 'Chat_listener' - - return obj -end - -function LLChatListener:handleMessages(event_data) - print(inspect(event_data)) - return true -end - -function LLChatListener:start() - waitfor = leap.WaitFor:new(-1, self.name) - function waitfor:filter(pump, data) - if pump == "LLNearbyChat" then - return data - end - end - - fiber.launch(self.name, function() - event = waitfor:wait() - while event and self:handleMessages(event) do - event = waitfor:wait() - end - end) - - listener_name = leap.request(leap.cmdpump(), {op='listen', source='LLNearbyChat', listener="ChatListener", tweak=true}).listener -end - -function LLChatListener:stop() - leap.send(leap.cmdpump(), {op='stoplistening', source='LLNearbyChat', listener=listener_name}) - waitfor:close() -end - -return LLChatListener diff --git a/indra/newview/scripts/lua/login.lua b/indra/newview/scripts/lua/login.lua deleted file mode 100644 index 0d8591cace..0000000000 --- a/indra/newview/scripts/lua/login.lua +++ /dev/null @@ -1,19 +0,0 @@ -local UI = require 'UI' -local leap = require 'leap' - -local function login(username, password) - if username and password then - local userpath = '//username_combo/Combo Text Entry' - local passpath = '//password_edit' - -- first clear anything presently in those text fields - for _, path in pairs({userpath, passpath}) do - UI.click(path) - UI.keypress{keysym='Backsp', path=path} - end - UI.type{path=userpath, text=username} - UI.type{path=passpath, text=password} - end - leap.send('LLPanelLogin', {op='onClickConnect'}) -end - -return login diff --git a/indra/newview/scripts/lua/mapargs.lua b/indra/newview/scripts/lua/mapargs.lua deleted file mode 100644 index 45f5a9c556..0000000000 --- a/indra/newview/scripts/lua/mapargs.lua +++ /dev/null @@ -1,73 +0,0 @@ --- Allow a calling function to be passed a mix of positional arguments with --- keyword arguments. Reference them as fields of a table. --- Don't use this for a function that can accept a single table argument. --- mapargs() assumes that a single table argument means its caller was called --- with f{table constructor} syntax, and maps that table to the specified names. --- Usage: --- function f(...) --- local a = mapargs({'a1', 'a2', 'a3'}, ...) --- ... a.a1 ... etc. --- end --- f(10, 20, 30) -- a.a1 == 10, a.a2 == 20, a.a3 == 30 --- f{10, 20, 30} -- a.a1 == 10, a.a2 == 20, a.a3 == 30 --- f{a3=300, a1=100} -- a.a1 == 100, a.a2 == nil, a.a3 == 300 --- f{1, a3=3} -- a.a1 == 1, a.a2 == nil, a.a3 == 3 --- f{a3=3, 1} -- a.a1 == 1, a.a2 == nil, a.a3 == 3 -local function mapargs(names, ...) - local args = table.pack(...) - local posargs = {} - local keyargs = {} - -- For a mixed table, no Lua operation will reliably tell you how many - -- array items it contains, if there are any holes. Track that by hand. - -- We must be able to handle f(1, nil, 3) calls. - local maxpos = 0 - - -- For convenience, allow passing 'names' as a string 'n0,n1,...' - if type(names) == 'string' then - names = string.split(names, ',') - end - - if not (args.n == 1 and type(args[1]) == 'table') then - -- If caller passes more than one argument, or if the first argument - -- is not a table, then it's classic positional function-call syntax: - -- f(first, second, etc.). In that case we need not bother teasing - -- apart positional from keyword arguments. - posargs = args - maxpos = args.n - else - -- Single table argument implies f{mixed} syntax. - -- Tease apart positional arguments from keyword arguments. - for k, v in pairs(args[1]) do - if type(k) == 'number' then - posargs[k] = v - maxpos = math.max(maxpos, k) - else - if table.find(names, k) == nil then - error('unknown keyword argument ' .. tostring(k)) - end - keyargs[k] = v - end - end - end - - -- keyargs already has keyword arguments in place, just fill in positionals - args = keyargs - -- Don't exceed the number of parameter names. Loop explicitly over every - -- index value instead of using ipairs() so we can support holes (nils) in - -- posargs. - for i = 1, math.min(#names, maxpos) do - if posargs[i] ~= nil then - -- As in Python, make it illegal to pass an argument both positionally - -- and by keyword. This implementation permits func(17, first=nil), a - -- corner case about which I don't particularly care. - if args[names[i]] ~= nil then - error(string.format('parameter %s passed both positionally and by keyword', - tostring(names[i]))) - end - args[names[i]] = posargs[i] - end - end - return args -end - -return mapargs diff --git a/indra/newview/scripts/lua/require/LLChatListener.lua b/indra/newview/scripts/lua/require/LLChatListener.lua new file mode 100644 index 0000000000..b4e90d272c --- /dev/null +++ b/indra/newview/scripts/lua/require/LLChatListener.lua @@ -0,0 +1,45 @@ +local fiber = require 'fiber' +local inspect = require 'inspect' +local leap = require 'leap' + +local LLChatListener = {} +local waitfor = {} +local listener_name = {} + +function LLChatListener:new() + local obj = setmetatable({}, self) + self.__index = self + obj.name = 'Chat_listener' + + return obj +end + +function LLChatListener:handleMessages(event_data) + print(inspect(event_data)) + return true +end + +function LLChatListener:start() + waitfor = leap.WaitFor:new(-1, self.name) + function waitfor:filter(pump, data) + if pump == "LLNearbyChat" then + return data + end + end + + fiber.launch(self.name, function() + event = waitfor:wait() + while event and self:handleMessages(event) do + event = waitfor:wait() + end + end) + + listener_name = leap.request(leap.cmdpump(), {op='listen', source='LLNearbyChat', listener="ChatListener", tweak=true}).listener +end + +function LLChatListener:stop() + leap.send(leap.cmdpump(), {op='stoplistening', source='LLNearbyChat', listener=listener_name}) + waitfor:close() +end + +return LLChatListener diff --git a/indra/newview/scripts/lua/require/login.lua b/indra/newview/scripts/lua/require/login.lua new file mode 100644 index 0000000000..0d8591cace --- /dev/null +++ b/indra/newview/scripts/lua/require/login.lua @@ -0,0 +1,19 @@ +local UI = require 'UI' +local leap = require 'leap' + +local function login(username, password) + if username and password then + local userpath = '//username_combo/Combo Text Entry' + local passpath = '//password_edit' + -- first clear anything presently in those text fields + for _, path in pairs({userpath, passpath}) do + UI.click(path) + UI.keypress{keysym='Backsp', path=path} + end + UI.type{path=userpath, text=username} + UI.type{path=passpath, text=password} + end + leap.send('LLPanelLogin', {op='onClickConnect'}) +end + +return login diff --git a/indra/newview/scripts/lua/require/mapargs.lua b/indra/newview/scripts/lua/require/mapargs.lua new file mode 100644 index 0000000000..45f5a9c556 --- /dev/null +++ b/indra/newview/scripts/lua/require/mapargs.lua @@ -0,0 +1,73 @@ +-- Allow a calling function to be passed a mix of positional arguments with +-- keyword arguments. Reference them as fields of a table. +-- Don't use this for a function that can accept a single table argument. +-- mapargs() assumes that a single table argument means its caller was called +-- with f{table constructor} syntax, and maps that table to the specified names. +-- Usage: +-- function f(...) +-- local a = mapargs({'a1', 'a2', 'a3'}, ...) +-- ... a.a1 ... etc. +-- end +-- f(10, 20, 30) -- a.a1 == 10, a.a2 == 20, a.a3 == 30 +-- f{10, 20, 30} -- a.a1 == 10, a.a2 == 20, a.a3 == 30 +-- f{a3=300, a1=100} -- a.a1 == 100, a.a2 == nil, a.a3 == 300 +-- f{1, a3=3} -- a.a1 == 1, a.a2 == nil, a.a3 == 3 +-- f{a3=3, 1} -- a.a1 == 1, a.a2 == nil, a.a3 == 3 +local function mapargs(names, ...) + local args = table.pack(...) + local posargs = {} + local keyargs = {} + -- For a mixed table, no Lua operation will reliably tell you how many + -- array items it contains, if there are any holes. Track that by hand. + -- We must be able to handle f(1, nil, 3) calls. + local maxpos = 0 + + -- For convenience, allow passing 'names' as a string 'n0,n1,...' + if type(names) == 'string' then + names = string.split(names, ',') + end + + if not (args.n == 1 and type(args[1]) == 'table') then + -- If caller passes more than one argument, or if the first argument + -- is not a table, then it's classic positional function-call syntax: + -- f(first, second, etc.). In that case we need not bother teasing + -- apart positional from keyword arguments. + posargs = args + maxpos = args.n + else + -- Single table argument implies f{mixed} syntax. + -- Tease apart positional arguments from keyword arguments. + for k, v in pairs(args[1]) do + if type(k) == 'number' then + posargs[k] = v + maxpos = math.max(maxpos, k) + else + if table.find(names, k) == nil then + error('unknown keyword argument ' .. tostring(k)) + end + keyargs[k] = v + end + end + end + + -- keyargs already has keyword arguments in place, just fill in positionals + args = keyargs + -- Don't exceed the number of parameter names. Loop explicitly over every + -- index value instead of using ipairs() so we can support holes (nils) in + -- posargs. + for i = 1, math.min(#names, maxpos) do + if posargs[i] ~= nil then + -- As in Python, make it illegal to pass an argument both positionally + -- and by keyword. This implementation permits func(17, first=nil), a + -- corner case about which I don't particularly care. + if args[names[i]] ~= nil then + error(string.format('parameter %s passed both positionally and by keyword', + tostring(names[i]))) + end + args[names[i]] = posargs[i] + end + end + return args +end + +return mapargs -- cgit v1.2.3 From 63e7e0b35dff15a2e06b924945dbb09389723686 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 10:10:35 -0400 Subject: Use util.classctor(LLChatListener). --- indra/newview/scripts/lua/require/LLChatListener.lua | 3 +++ indra/newview/scripts/lua/test_LLChatListener.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/LLChatListener.lua b/indra/newview/scripts/lua/require/LLChatListener.lua index b4e90d272c..428dca881e 100644 --- a/indra/newview/scripts/lua/require/LLChatListener.lua +++ b/indra/newview/scripts/lua/require/LLChatListener.lua @@ -1,6 +1,7 @@ local fiber = require 'fiber' local inspect = require 'inspect' local leap = require 'leap' +local util = require 'util' local LLChatListener = {} local waitfor = {} @@ -14,6 +15,8 @@ function LLChatListener:new() return obj end +util.classctor(LLChatListener) + function LLChatListener:handleMessages(event_data) print(inspect(event_data)) return true diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua index b9696e7cfc..18363ed43b 100644 --- a/indra/newview/scripts/lua/test_LLChatListener.lua +++ b/indra/newview/scripts/lua/test_LLChatListener.lua @@ -11,7 +11,7 @@ function openOrEcho(message) end end -local listener = LLChatListener:new() +local listener = LLChatListener() function listener:handleMessages(event_data) if string.find(event_data.message, '[LUA]') then -- cgit v1.2.3 From b8e0c16ab1eb3cdd1d11e869bd3fd6196de51d4b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 21 Jun 2024 17:42:45 +0300 Subject: Add Appearance listener --- indra/newview/CMakeLists.txt | 2 + indra/newview/llappearancelistener.cpp | 110 +++++++++++++++++++++ indra/newview/llappearancelistener.h | 44 +++++++++ indra/newview/llappearancemgr.cpp | 28 +++++- indra/newview/llappearancemgr.h | 2 +- indra/newview/llviewermenu.cpp | 4 +- indra/newview/scripts/lua/LLAppearance.lua | 25 +++++ .../scripts/lua/luafloater_outfits_list.xml | 21 ++++ indra/newview/scripts/lua/test_outfits_list.lua | 27 +++++ 9 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 indra/newview/llappearancelistener.cpp create mode 100644 indra/newview/llappearancelistener.h create mode 100644 indra/newview/scripts/lua/LLAppearance.lua create mode 100644 indra/newview/scripts/lua/luafloater_outfits_list.xml create mode 100644 indra/newview/scripts/lua/test_outfits_list.lua (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ab65d71916..4e7e072289 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -95,6 +95,7 @@ set(viewer_SOURCE_FILES llagentwearables.cpp llanimstatelabels.cpp llappcorehttp.cpp + llappearancelistener.cpp llappearancemgr.cpp llappviewer.cpp llappviewerlistener.cpp @@ -760,6 +761,7 @@ set(viewer_HEADER_FILES llanimstatelabels.h llappcorehttp.h llappearance.h + llappearancelistener.h llappearancemgr.h llappviewer.h llappviewerlistener.h diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp new file mode 100644 index 0000000000..2d5ff6bee4 --- /dev/null +++ b/indra/newview/llappearancelistener.cpp @@ -0,0 +1,110 @@ +/** + * @file llappearancelistener.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llappearancelistener.h" + +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "stringize.h" + +LLAppearanceListener::LLAppearanceListener() + : LLEventAPI("LLAppearance", + "API to wear a specified outfit and wear/remove individual items") +{ + add("wearOutfit", + "Wear outfit by folder id: [folder_id]" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfit, + llsd::map("folder_id", LLSD(), "append", LLSD())); + + add("wearOutfitByName", + "Wear outfit by folder name: [folder_name]" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfitByName, + llsd::map("folder_name", LLSD(), "append", LLSD())); + + add("getOutfitsList", + "Return the table of Outfits(id and name) which are send to the script", + &LLAppearanceListener::getOutfitsList); +} + + +void LLAppearanceListener::wearOutfit(LLSD const &data) +{ + Response response(LLSD(), data); + LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); + if (!cat) + { + response.error(stringize("Couldn't find outfit ", data["folder_id"].asUUID())); + return; + } + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + response.error(stringize("Can't wear system folder ", data["folder_id"].asUUID())); + return; + } + bool append = data["append"].asBoolean(); + bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); + if (!can_wear) + { + std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); + return; + } + LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); +} + +void LLAppearanceListener::wearOutfitByName(LLSD const &data) +{ + Response response(LLSD(), data); + std::string error_msg; + if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), data["append"].asBoolean(), error_msg)) + { + response.error(error_msg); + } +} + +void LLAppearanceListener::getOutfitsList(LLSD const &data) +{ + Response response(LLSD(), data); + const LLUUID outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); + + LLSD outfits_data; + for (const LLPointer<LLViewerInventoryCategory> &cat : cat_array) + { + outfits_data[cat->getUUID().asString()] = cat->getName(); + } + response["outfits"] = outfits_data; +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h new file mode 100644 index 0000000000..8448b2ede9 --- /dev/null +++ b/indra/newview/llappearancelistener.h @@ -0,0 +1,44 @@ +/** + * @file llappearancelistener.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLAPPEARANCELISTENER_H +#define LL_LLAPPEARANCELISTENER_H + +#include "lleventapi.h" + +class LLAppearanceListener : public LLEventAPI +{ +public: + LLAppearanceListener(); + +private: + void wearOutfit(LLSD const &data); + void wearOutfitByName(LLSD const &data); + void getOutfitsList(LLSD const &data); +}; + +#endif // LL_LLAPPEARANCELISTENER_H + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 30f07a873b..19b81f5a79 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llappearancelistener.h" #include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llcommandhandler.h" @@ -71,6 +72,8 @@ #pragma warning (disable:4702) #endif +LLAppearanceListener sAppearanceListener; + namespace { const S32 BAKE_RETRY_MAX_COUNT = 5; @@ -2900,8 +2903,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } -// FIXME do we really want to search entire inventory for matching name? -void LLAppearanceMgr::wearOutfitByName(const std::string& name) +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std::string& error_msg) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2936,13 +2938,29 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name) if(cat) { - LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); + bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); + if (is_system_folder) + { + error_msg = stringize("Can't wear system folder ", std::quoted(name)); + return false; + } + bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); + if (!can_wear) + { + std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + error_msg = stringize(msg, std::quoted(name), " , id: ", cat->getUUID()); + LL_WARNS() << error_msg << LL_ENDL; + return false; + } + LLAppearanceMgr::wearInventoryCategory(cat, copy_items, append); } else { - LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()" - << LL_ENDL; + error_msg = stringize("Couldn't find outfit ", std::quoted(name)); + LL_WARNS() << error_msg << LL_ENDL; + return false; } + return true; } bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index e5de92b653..d7b6cd5a61 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -59,7 +59,7 @@ public: void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); - void wearOutfitByName(const std::string& name); + bool wearOutfitByName(const std::string &name, bool append = false, std::string &error_msg = std::string()); void changeOutfit(bool proceed, const LLUUID& category, bool append); void replaceCurrentOutfit(const LLUUID& new_outfit); void renameOutfit(const LLUUID& outfit_id); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 90b7c43047..cea7180187 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9745,8 +9745,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); - view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); - view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); + view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale", cb_info::UNTRUSTED_THROTTLE); + view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale", cb_info::UNTRUSTED_THROTTLE); // Advanced > Character > Animation Speed view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); diff --git a/indra/newview/scripts/lua/LLAppearance.lua b/indra/newview/scripts/lua/LLAppearance.lua new file mode 100644 index 0000000000..ec7a25197f --- /dev/null +++ b/indra/newview/scripts/lua/LLAppearance.lua @@ -0,0 +1,25 @@ +leap = require 'leap' + +local LLAppearance = {} + +function LLAppearance.addOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +end + +function LLAppearance.replaceOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +end + +function LLAppearance.addOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +end + +function LLAppearance.replaceOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) +end + +function LLAppearance.getOutfitsList() + return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] +end + +return LLAppearance diff --git a/indra/newview/scripts/lua/luafloater_outfits_list.xml b/indra/newview/scripts/lua/luafloater_outfits_list.xml new file mode 100644 index 0000000000..1f6505cb8d --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_outfits_list.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="185" + layout="topleft" + name="lua_outfits" + title="Outfits" + width="320"> + <scroll_list + draw_heading="false" + left="5" + width="310" + height="150" + top_pad ="25" + follows="all" + name="outfits_list"> + <scroll_list.columns + name="outfit_name" + label="Name"/> + </scroll_list> +</floater> diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua new file mode 100644 index 0000000000..5875fd51da --- /dev/null +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -0,0 +1,27 @@ +local Floater = require 'Floater' +local LLAppearance = require 'LLAppearance' +local startup = require 'startup' + +local flt = Floater:new( + "luafloater_outfits_list.xml", + {outfits_list = {"double_click"}}) + +function flt:post_build(event_data) + local outfits_map = LLAppearance.getOutfitsList() + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "outfits_list" + local outfits = {} + for uuid, name in pairs(outfits_map) do + table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) + end + action_data.value = outfits + self:post(action_data) +end + +function flt:double_click_outfits_list(event_data) + LLAppearance.replaceOutfit(event_data.value) +end + +startup.wait('STATE_STARTED') +flt:show() -- cgit v1.2.3 From e05155494cb3a4b24f9e89252e34953e68eb7107 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 14:25:05 -0400 Subject: Multiple LL.atexit(function) calls run functions in reverse order. --- indra/newview/scripts/lua/test_atexit.lua | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 indra/newview/scripts/lua/test_atexit.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_atexit.lua b/indra/newview/scripts/lua/test_atexit.lua new file mode 100644 index 0000000000..6fbc0f3eb1 --- /dev/null +++ b/indra/newview/scripts/lua/test_atexit.lua @@ -0,0 +1,3 @@ +LL.atexit(function() print('Third') end) +LL.atexit(function() print('Second') end) +LL.atexit(function() print('First') end) -- cgit v1.2.3 From 1c19563a76dd227c80693701fdc2d52d65bbf4f4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 14:26:36 -0400 Subject: Introduce require/logout.lua and test_logout.lua. Add "userQuit" operation to LLAppViewerListener to engage LLAppViewer::userQuit(), which pops up "Are you sure?" prompt unless suppressed. --- indra/newview/llappviewerlistener.cpp | 9 +++++++++ indra/newview/llappviewerlistener.h | 5 +++-- indra/newview/scripts/lua/require/logout.lua | 7 +++++++ indra/newview/scripts/lua/test_logout.lua | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 indra/newview/scripts/lua/require/logout.lua create mode 100644 indra/newview/scripts/lua/test_logout.lua (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index 6d519b6fef..d02b1b4a79 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -42,6 +42,9 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): mAppViewerGetter(getter) { // add() every method we want to be able to invoke via this event API. + add("userQuit", + "Ask to quit with user confirmation prompt", + &LLAppViewerListener::userQuit); add("requestQuit", "Ask to quit nicely", &LLAppViewerListener::requestQuit); @@ -50,6 +53,12 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): &LLAppViewerListener::forceQuit); } +void LLAppViewerListener::userQuit(const LLSD& event) +{ + LL_INFOS() << "Listener requested user quit" << LL_ENDL; + mAppViewerGetter()->userQuit(); +} + void LLAppViewerListener::requestQuit(const LLSD& event) { LL_INFOS() << "Listener requested quit" << LL_ENDL; diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h index 5ade3d3e04..e116175eb7 100644 --- a/indra/newview/llappviewerlistener.h +++ b/indra/newview/llappviewerlistener.h @@ -30,7 +30,7 @@ #define LL_LLAPPVIEWERLISTENER_H #include "lleventapi.h" -#include <boost/function.hpp> +#include <functional> class LLAppViewer; class LLSD; @@ -39,11 +39,12 @@ class LLSD; class LLAppViewerListener: public LLEventAPI { public: - typedef boost::function<LLAppViewer*(void)> LLAppViewerGetter; + typedef std::function<LLAppViewer*(void)> LLAppViewerGetter; /// Bind the LLAppViewer instance to use (e.g. LLAppViewer::instance()). LLAppViewerListener(const LLAppViewerGetter& getter); private: + void userQuit(const LLSD& event); void requestQuit(const LLSD& event); void forceQuit(const LLSD& event); diff --git a/indra/newview/scripts/lua/require/logout.lua b/indra/newview/scripts/lua/require/logout.lua new file mode 100644 index 0000000000..63dcd7f01f --- /dev/null +++ b/indra/newview/scripts/lua/require/logout.lua @@ -0,0 +1,7 @@ +local leap = require 'leap' + +local function logout() + leap.send('LLAppViewer', {op='userQuit'}); +end + +return logout diff --git a/indra/newview/scripts/lua/test_logout.lua b/indra/newview/scripts/lua/test_logout.lua new file mode 100644 index 0000000000..b1ac59e38c --- /dev/null +++ b/indra/newview/scripts/lua/test_logout.lua @@ -0,0 +1,3 @@ +logout = require 'logout' + +logout() -- cgit v1.2.3 From a6d860f9f3bd7ce8ed5d42635a730c1ee9714aea Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 14:47:30 -0400 Subject: login.lua works now, update test_login.lua accordingly. --- indra/newview/scripts/lua/test_login.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_login.lua b/indra/newview/scripts/lua/test_login.lua index 6df52b08c2..a8c31807bc 100644 --- a/indra/newview/scripts/lua/test_login.lua +++ b/indra/newview/scripts/lua/test_login.lua @@ -3,5 +3,5 @@ login = require 'login' startup.wait('STATE_LOGIN_WAIT') login() --- WIP: not working as of 2024-06-11 +-- Fill in valid credentials as they would be entered on the login screen -- login('My Username', 'password') -- cgit v1.2.3 From 8fa98f095a89778cd3153f3ee88f5626fc5a0d02 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 14:50:35 -0400 Subject: Remove pre-Floater.lua versions of the floater test scripts. --- indra/newview/scripts/lua/test_luafloater_demo.lua | 77 ---------------------- .../scripts/lua/test_luafloater_gesture_list.lua | 75 --------------------- 2 files changed, 152 deletions(-) delete mode 100644 indra/newview/scripts/lua/test_luafloater_demo.lua delete mode 100644 indra/newview/scripts/lua/test_luafloater_gesture_list.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua deleted file mode 100644 index 65a31670c8..0000000000 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ /dev/null @@ -1,77 +0,0 @@ -XML_FILE_PATH = LL.abspath("luafloater_demo.xml") - -scriptparts = string.split(LL.source_path(), '/') -scriptname = scriptparts[#scriptparts] -print('Running ' .. scriptname) - -leap = require 'leap' -fiber = require 'fiber' -startup = require 'startup' - ---event pump for sending actions to the floater -local COMMAND_PUMP_NAME = "" -local reqid ---table of floater UI events -event_list=leap.request("LLFloaterReg", {op="getFloaterEvents"}).events - -local function _event(event_name) - if not table.find(event_list, event_name) then - LL.print_warning("Incorrect event name: " .. event_name) - end - return event_name -end - -function post(action) - leap.send(COMMAND_PUMP_NAME, action) -end - -function getCurrentTime() - local currentTime = os.date("*t") - return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec) -end - -function handleEvents(event_data) - post({action="add_text", ctrl_name="events_editor", value = event_data}) - if event_data.event == _event("commit") then - if event_data.ctrl_name == "disable_ctrl" then - post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) - elseif event_data.ctrl_name == "title_cmb" then - post({action="set_title", value= event_data.value}) - elseif event_data.ctrl_name == "open_btn" then - floater_name = leap.request(COMMAND_PUMP_NAME, {action="get_value", ctrl_name='openfloater_cmd'})['value'] - leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) - end - elseif event_data.event == _event("double_click") then - if event_data.ctrl_name == "show_time_lbl" then - post({action="set_value", ctrl_name="time_lbl", value= getCurrentTime()}) - end - elseif event_data.event == _event("floater_close") then - LL.print_warning("Floater was closed") - return false - end - return true -end - -startup.wait('STATE_LOGIN_WAIT') -local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} ---sign for additional events for defined control {<control_name>= {action1, action2, ...}} -key.extra_events={show_time_lbl = {_event("right_mouse_down"), _event("double_click")}} -local resp = leap.request("LLFloaterReg", key) -COMMAND_PUMP_NAME = resp.command_name -reqid = resp.reqid - -catch_events = leap.WaitFor(-1, "all_events") -function catch_events:filter(pump, data) - if data.reqid == reqid then - return data - end -end - -function process_events(waitfor) - event_data = waitfor:wait() - while event_data and handleEvents(event_data) do - event_data = waitfor:wait() - end -end - -fiber.launch("catch_events", process_events, catch_events) diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua deleted file mode 100644 index a5fd325430..0000000000 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ /dev/null @@ -1,75 +0,0 @@ -XML_FILE_PATH = LL.abspath("luafloater_gesture_list.xml") - -scriptparts = string.split(LL.source_path(), '/') -scriptname = scriptparts[#scriptparts] -print('Running ' .. scriptname) - -leap = require 'leap' -fiber = require 'fiber' -LLGesture = require 'LLGesture' -startup = require 'startup' - ---event pump for sending actions to the floater -local COMMAND_PUMP_NAME = "" -local reqid ---table of floater UI events -event_list=leap.request("LLFloaterReg", {op="getFloaterEvents"}).events - -local function _event(event_name) - if not table.find(event_list, event_name) then - LL.print_warning("Incorrect event name: " .. event_name) - end - return event_name -end - -function post(action) - leap.send(COMMAND_PUMP_NAME, action) -end - -function handleEvents(event_data) - if event_data.event == _event("floater_close") then - return false - end - - if event_data.event == _event("post_build") then - COMMAND_PUMP_NAME = event_data.command_name - reqid = event_data.reqid - gestures_uuid = LLGesture.getActiveGestures() - local action_data = {} - action_data.action = "add_list_element" - action_data.ctrl_name = "gesture_list" - gestures = {} - for uuid, info in pairs(gestures_uuid) do - table.insert(gestures, {value = uuid, columns ={column = "gesture_name", value = info.name}}) - end - action_data.value = gestures - post(action_data) - elseif event_data.event == _event("double_click") then - if event_data.ctrl_name == "gesture_list" then - LLGesture.startGesture(event_data.value) - end - end - return true -end - -startup.wait('STATE_STARTED') -local key = {xml_path = XML_FILE_PATH, op = "showLuaFloater"} ---receive additional events for defined control {<control_name>= {action1, action2, ...}} -key.extra_events={gesture_list = {_event("double_click")}} -handleEvents(leap.request("LLFloaterReg", key)) - -catch_events = leap.WaitFor(-1, "all_events") -function catch_events:filter(pump, data) - if data.reqid == reqid then - return data - end -end - -function process_events(waitfor) - event_data = waitfor:wait() - while event_data and handleEvents(event_data) do - event_data = waitfor:wait() - end -end - -fiber.launch("catch_events", process_events, catch_events) -- cgit v1.2.3 From 56e4b8c5f637343c8a1a181fd59324e033b4782d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 21 Jun 2024 15:11:57 -0400 Subject: Exercise the simple popup.lua APIs --- indra/newview/scripts/lua/test_popup.lua | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 indra/newview/scripts/lua/test_popup.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_popup.lua b/indra/newview/scripts/lua/test_popup.lua new file mode 100644 index 0000000000..e48f89c3a7 --- /dev/null +++ b/indra/newview/scripts/lua/test_popup.lua @@ -0,0 +1,6 @@ +popup = require 'popup' + +response = popup:alert('This just has a Close button') +response = popup:alertOK(string.format('You said "%s", is that OK?', next(response))) +response = popup:alertYesCancel(string.format('You said "%s"', next(response))) +popup:tip(string.format('You said "%s"', next(response))) -- cgit v1.2.3 From eb6d24e531aa5faa251b7aaf8b13c62f06708696 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 25 Jun 2024 14:51:53 +0300 Subject: Add wear/detach actions to Appearance listener; update example script --- indra/newview/llappearancelistener.cpp | 50 +++++++++++- indra/newview/llappearancelistener.h | 3 + indra/newview/llwearableitemslist.cpp | 13 +-- indra/newview/llwearableitemslist.h | 9 +++ indra/newview/scripts/lua/LLAppearance.lua | 25 ------ .../scripts/lua/luafloater_outfits_list.xml | 36 ++++++++- indra/newview/scripts/lua/require/LLAppearance.lua | 37 +++++++++ indra/newview/scripts/lua/test_outfits_list.lua | 93 ++++++++++++++++++++-- 8 files changed, 220 insertions(+), 46 deletions(-) delete mode 100644 indra/newview/scripts/lua/LLAppearance.lua create mode 100644 indra/newview/scripts/lua/require/LLAppearance.lua (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 2d5ff6bee4..11037a0078 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -30,6 +30,7 @@ #include "llappearancemgr.h" #include "llinventoryfunctions.h" #include "stringize.h" +#include "llwearableitemslist.h" LLAppearanceListener::LLAppearanceListener() : LLEventAPI("LLAppearance", @@ -49,9 +50,23 @@ LLAppearanceListener::LLAppearanceListener() &LLAppearanceListener::wearOutfitByName, llsd::map("folder_name", LLSD(), "append", LLSD())); + add("wearItem", + "Wear item by item id: [item_id]", + &LLAppearanceListener::wearItem, + llsd::map("item_id", LLSD(), "replace", LLSD())); + + add("detachItem", + "Detach item by item id: [item_id]", + &LLAppearanceListener::detachItem, + llsd::map("item_id", LLSD())); + add("getOutfitsList", - "Return the table of Outfits(id and name) which are send to the script", + "Return the table with Outfits info(id and name)", &LLAppearanceListener::getOutfitsList); + + add("getOutfitItems", + "Return the table of items(id and name) inside specified outfit folder", + &LLAppearanceListener::getOutfitItems); } @@ -90,6 +105,16 @@ void LLAppearanceListener::wearOutfitByName(LLSD const &data) } } +void LLAppearanceListener::wearItem(LLSD const &data) +{ + LLAppearanceMgr::instance().wearItemOnAvatar(data["item_id"].asUUID(), true, data["replace"].asBoolean()); +} + +void LLAppearanceListener::detachItem(LLSD const &data) +{ + LLAppearanceMgr::instance().removeItemFromAvatar(data["item_id"].asUUID()); +} + void LLAppearanceListener::getOutfitsList(LLSD const &data) { Response response(LLSD(), data); @@ -108,3 +133,26 @@ void LLAppearanceListener::getOutfitsList(LLSD const &data) } response["outfits"] = outfits_data; } + +void LLAppearanceListener::getOutfitItems(LLSD const &data) +{ + Response response(LLSD(), data); + LLUUID outfit_id(data["outfit_id"].asUUID()); + LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); + if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + response.error(stringize("Can't find outfit folder with id: ", outfit_id.asString())); + } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, LLFindOutfitItems()); + + LLSD items_data; + for (const LLPointer<LLViewerInventoryItem> &it : item_array) + { + items_data[it->getUUID().asString()] = it->getName(); + } + + response["items"] = items_data; +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h index 8448b2ede9..00553c072f 100644 --- a/indra/newview/llappearancelistener.h +++ b/indra/newview/llappearancelistener.h @@ -37,7 +37,10 @@ public: private: void wearOutfit(LLSD const &data); void wearOutfitByName(LLSD const &data); + void wearItem(LLSD const &data); + void detachItem(LLSD const &data); void getOutfitsList(LLSD const &data); + void getOutfitItems(LLSD const &data); }; #endif // LL_LLAPPEARANCELISTENER_H diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 676164fcc6..e122cc0360 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -33,7 +33,6 @@ #include "llagentwearables.h" #include "llappearancemgr.h" -#include "llinventoryfunctions.h" #include "llinventoryicon.h" #include "llgesturemgr.h" #include "lltransutil.h" @@ -41,14 +40,6 @@ #include "llviewermenu.h" #include "llvoavatarself.h" -class LLFindOutfitItems : public LLInventoryCollectFunctor -{ -public: - LLFindOutfitItems() {} - virtual ~LLFindOutfitItems() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -}; bool LLFindOutfitItems::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -60,10 +51,10 @@ bool LLFindOutfitItems::operator()(LLInventoryCategory* cat, || (item->getType() == LLAssetType::AT_OBJECT) || (item->getType() == LLAssetType::AT_GESTURE)) { - return TRUE; + return true; } } - return FALSE; + return false; } ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 80e211ad6b..a24679961f 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -32,6 +32,7 @@ #include "llsingleton.h" // newview +#include "llinventoryfunctions.h" #include "llinventoryitemslist.h" #include "llinventorylistitem.h" #include "lllistcontextmenu.h" @@ -505,4 +506,12 @@ protected: LLWearableType::EType mMenuWearableType; }; +class LLFindOutfitItems : public LLInventoryCollectFunctor +{ + public: + LLFindOutfitItems() {} + virtual ~LLFindOutfitItems() {} + virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); +}; + #endif //LL_LLWEARABLEITEMSLIST_H diff --git a/indra/newview/scripts/lua/LLAppearance.lua b/indra/newview/scripts/lua/LLAppearance.lua deleted file mode 100644 index ec7a25197f..0000000000 --- a/indra/newview/scripts/lua/LLAppearance.lua +++ /dev/null @@ -1,25 +0,0 @@ -leap = require 'leap' - -local LLAppearance = {} - -function LLAppearance.addOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) -end - -function LLAppearance.replaceOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) -end - -function LLAppearance.addOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) -end - -function LLAppearance.replaceOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) -end - -function LLAppearance.getOutfitsList() - return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] -end - -return LLAppearance diff --git a/indra/newview/scripts/lua/luafloater_outfits_list.xml b/indra/newview/scripts/lua/luafloater_outfits_list.xml index 1f6505cb8d..8cab864308 100644 --- a/indra/newview/scripts/lua/luafloater_outfits_list.xml +++ b/indra/newview/scripts/lua/luafloater_outfits_list.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="185" + height="205" layout="topleft" name="lua_outfits" title="Outfits" - width="320"> + width="325"> <scroll_list draw_heading="false" left="5" - width="310" + width="315" height="150" top_pad ="25" follows="all" @@ -18,4 +18,34 @@ name="outfit_name" label="Name"/> </scroll_list> + <button + follows="left|bottom" + height="23" + label="Replace COF" + layout="topleft" + name="replace_btn" + enabled="false" + top_pad="5" + width="95" > + </button> + <button + follows="left|bottom" + height="23" + label="Add to COF" + left_pad="7" + layout="topleft" + name="add_btn" + enabled="false" + width="95" > + </button> + <button + follows="left|bottom" + height="23" + label="Show wearables" + left_pad="7" + layout="topleft" + name="select_btn" + enabled="false" + width="111" > + </button> </floater> diff --git a/indra/newview/scripts/lua/require/LLAppearance.lua b/indra/newview/scripts/lua/require/LLAppearance.lua new file mode 100644 index 0000000000..165bb6d06f --- /dev/null +++ b/indra/newview/scripts/lua/require/LLAppearance.lua @@ -0,0 +1,37 @@ +leap = require 'leap' + +local LLAppearance = {} + +function LLAppearance.addOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +end + +function LLAppearance.replaceOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +end + +function LLAppearance.addOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +end + +function LLAppearance.replaceOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) +end + +function LLAppearance.wearItem(item_id, replace) + leap.send('LLAppearance', {op='wearItem', replace = replace, item_id=item_id}) +end + +function LLAppearance.detachItem(item_id) + leap.send('LLAppearance', {op='detachItem', item_id=item_id}) +end + +function LLAppearance.getOutfitsList() + return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] +end + +function LLAppearance.getOutfitItems(id) + return leap.request('LLAppearance', {op='getOutfitItems', outfit_id = id})['items'] +end + +return LLAppearance diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua index 5875fd51da..dd5f914402 100644 --- a/indra/newview/scripts/lua/test_outfits_list.lua +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -1,26 +1,107 @@ local Floater = require 'Floater' local LLAppearance = require 'LLAppearance' local startup = require 'startup' +local inspect = require 'inspect' + +local SHOW_OUTFITS = true +local SELECTED_OUTFIT_ID = {} +local DATA_MAP = {} + +local wearables_lbl = 'Show wearables' +local outfits_lbl = 'Show outfits' +local replace_cof_lbl = 'Replace COF' +local add_cof_lbl = 'Add to COF' +local outfits_title = 'Outfits' +local wear_lbl = 'Wear item' +local detach_lbl = 'Detach item' local flt = Floater:new( "luafloater_outfits_list.xml", {outfits_list = {"double_click"}}) -function flt:post_build(event_data) - local outfits_map = LLAppearance.getOutfitsList() +function get_selected_id() + return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value +end + +function populate_list() + if SHOW_OUTFITS then + DATA_MAP = LLAppearance.getOutfitsList() + else + DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID) + end + local action_data = {} action_data.action = "add_list_element" action_data.ctrl_name = "outfits_list" local outfits = {} - for uuid, name in pairs(outfits_map) do + for uuid, name in pairs(DATA_MAP) do table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) end action_data.value = outfits - self:post(action_data) + flt:post(action_data) +end + +function set_label(btn_name, value) + flt:post({action="set_label", ctrl_name=btn_name, value=value}) +end + +function set_enabled(btn_name, value) + flt:post({action="set_enabled", ctrl_name=btn_name, value=value}) +end + +function update_labels() + if SHOW_OUTFITS then + set_label('select_btn', wearables_lbl) + set_label('replace_btn', replace_cof_lbl) + set_label('add_btn', add_cof_lbl) + + set_enabled('select_btn', false) + flt:post({action="set_title", value=outfits_title}) + else + set_label('select_btn', outfits_lbl) + set_label('replace_btn', wear_lbl) + set_label('add_btn', detach_lbl) + + set_enabled('select_btn', true) + flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]}) + end + + set_enabled('replace_btn', false) + set_enabled('add_btn', false) +end + +function flt:post_build(event_data) + populate_list() +end + +function flt:commit_replace_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.replaceOutfit(get_selected_id()) + else + LLAppearance.wearItem(get_selected_id(), false) + end +end + +function flt:commit_add_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.addOutfit(get_selected_id()) + else + LLAppearance.detachItem(get_selected_id()) + end +end + +function flt:commit_select_btn(event_data) + SHOW_OUTFITS = not SHOW_OUTFITS + SELECTED_OUTFIT_ID = get_selected_id() + update_labels() + self:post({action="clear_list", ctrl_name='outfits_list'}) + populate_list() end -function flt:double_click_outfits_list(event_data) - LLAppearance.replaceOutfit(event_data.value) +function flt:commit_outfits_list(event_data) + set_enabled('replace_btn', true) + set_enabled('add_btn', true) + set_enabled('select_btn', true) end startup.wait('STATE_STARTED') -- cgit v1.2.3 From 0cc7436be1f57299384c5acad5d32e13f2f4d1cf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 27 Jun 2024 19:47:00 -0400 Subject: Introduce TypeTag<T> template whose int value differs for each T. This replaces type_tag<T>(), which searched and possibly extended the type_tags unordered_map at runtime. If we called lua_emplace<T>() from different threads, that would require locking type_tags. In contrast, the compiler must instantiate a distinct TypeTag<T> for every distinct T passed to lua_emplace<T>(), so each gets a distinct value at static initialization time. No locking is required; no lookup; no allocations. Add a test to llluamanager_test.cpp to verify that each distinct T passed to lua_emplace<T>() gets its own TypeTag<T>::value, and that each gets its own destructor -- but that different lua_emplace<T>() calls with the same T share the same TypeTag<T>::value and the same destructor. --- indra/newview/tests/llluamanager_test.cpp | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 2d525f7913..d3fc70dfd5 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -465,4 +465,39 @@ namespace tut ensure_equals(desc + " count: " + result.asString(), count, -1); ensure_contains(desc + " result", result.asString(), "terminated"); } + + template <typename T> + struct Visible + { + Visible(T name): name(name) + { + LL_INFOS() << "Visible<" << LLError::Log::classname<T>() << ">('" << name << "')" << LL_ENDL; + } + Visible(const Visible&) = delete; + Visible& operator=(const Visible&) = delete; + ~Visible() + { + LL_INFOS() << "~Visible<" << LLError::Log::classname<T>() << ">('" << name << "')" << LL_ENDL; + } + T name; + }; + + template<> template<> + void object::test<9>() + { + set_test_name("track distinct lua_emplace<T>() types"); + LuaState L; + lua_emplace<Visible<std::string>>(L, "std::string 0"); + int st0tag = lua_userdatatag(L, -1); + lua_emplace<Visible<const char*>>(L, "const char* 0"); + int cp0tag = lua_userdatatag(L, -1); + lua_emplace<Visible<std::string>>(L, "std::string 1"); + int st1tag = lua_userdatatag(L, -1); + lua_emplace<Visible<const char*>>(L, "const char* 1"); + int cp1tag = lua_userdatatag(L, -1); + lua_settop(L, 0); + ensure_equals("lua_emplace<std::string>() tags diverge", st0tag, st1tag); + ensure_equals("lua_emplace<const char*>() tags diverge", cp0tag, cp1tag); + ensure_not_equals("lua_emplace<>() tags collide", st0tag, cp0tag); + } } // namespace tut -- cgit v1.2.3 From ac56718929044e101dc2c7bfe3ebc5dff565b76d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 28 Jun 2024 13:21:14 -0400 Subject: Add LuaAutorunPath, LuaCommandPath and LuaRequirePath settings. Remove AutorunLuaScriptFile and the LLLUAmanager::runScriptOnLogin() method that checked it. Instead, iterate over LuaAutorunPath directories at viewer startup, iterate over *.lua files in each and implicitly run those. LuaCommandPath and LuaRequirePath are not yet implemented. --- indra/newview/app_settings/settings.xml | 634 +++++++++++++++++--------------- indra/newview/llappviewer.cpp | 19 + indra/newview/llluamanager.cpp | 21 -- indra/newview/llluamanager.h | 2 - indra/newview/llstartup.cpp | 3 - 5 files changed, 350 insertions(+), 329 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2463d56eae..cdaf9a47dd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -346,7 +346,7 @@ <key>Value</key> <real>0.5</real> </map> - <key>AudioStreamingMedia</key> + <key>AudioStreamingMedia</key> <map> <key>Comment</key> <string>Enable streaming</string> @@ -1291,7 +1291,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>0</integer> </map> <key>CameraPositionSmoothing</key> <map> @@ -1907,17 +1907,17 @@ <key>Value</key> <string /> </map> - <key>DebugAvatarRezTime</key> - <map> - <key>Comment</key> - <string>Display times for avatars to resolve.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> + <key>DebugAvatarRezTime</key> + <map> + <key>Comment</key> + <string>Display times for avatars to resolve.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>DebugAvatarLocalTexLoadedTime</key> <map> <key>Comment</key> @@ -2292,39 +2292,39 @@ <key>Value</key> <integer>0</integer> </map> - <key>DefaultFemaleAvatar</key> - <map> - <key>Comment</key> - <string>Default Female Avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>Female Shape & Outfit</string> - </map> - <key>DefaultLoginLocation</key> - <map> - <key>Comment</key> - <string>Startup destination default (if not specified on command line)</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string/> - </map> - <key>DefaultMaleAvatar</key> - <map> - <key>Comment</key> - <string>Default Male Avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>Male Shape & Outfit</string> - </map> + <key>DefaultFemaleAvatar</key> + <map> + <key>Comment</key> + <string>Default Female Avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Female Shape & Outfit</string> + </map> + <key>DefaultLoginLocation</key> + <map> + <key>Comment</key> + <string>Startup destination default (if not specified on command line)</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string/> + </map> + <key>DefaultMaleAvatar</key> + <map> + <key>Comment</key> + <string>Default Male Avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Male Shape & Outfit</string> + </map> <key>DestinationGuideURL</key> <map> <key>Comment</key> @@ -2699,7 +2699,7 @@ <key>Value</key> <integer>0</integer> </map> - <key>FirstSelectedEnabledPopups</key> + <key>FirstSelectedEnabledPopups</key> <map> <key>Comment</key> <string>Return false if there is not enable popup selected in the list of floater preferences popups</string> @@ -3521,39 +3521,39 @@ <key>Value</key> <integer>0</integer> </map> - <key>InventoryLinking</key> - <map> - <key>Comment</key> - <string>Enable ability to create links to folders and items via "Paste as link".</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>InventoryOutboxLogging</key> - <map> - <key>Comment</key> - <string>Enable debug output associated with the Merchant Outbox.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>InventoryOutboxMakeVisible</key> - <map> - <key>Comment</key> - <string>Enable making the Merchant Outbox and Inbox visible in the inventory for debug purposes.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> + <key>InventoryLinking</key> + <map> + <key>Comment</key> + <string>Enable ability to create links to folders and items via "Paste as link".</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>InventoryOutboxLogging</key> + <map> + <key>Comment</key> + <string>Enable debug output associated with the Merchant Outbox.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>InventoryOutboxMakeVisible</key> + <map> + <key>Comment</key> + <string>Enable making the Merchant Outbox and Inbox visible in the inventory for debug purposes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>InventoryOutboxMaxFolderCount</key> <map> <key>Comment</key> @@ -3807,8 +3807,8 @@ <key>Value</key> <real>0.25</real> </map> - <key>Jpeg2000AdvancedCompression</key> - <map> + <key>Jpeg2000AdvancedCompression</key> + <map> <key>Comment</key> <string>Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers)</string> <key>Persist</key> @@ -3817,9 +3817,9 @@ <string>Boolean</string> <key>Value</key> <integer>0</integer> - </map> - <key>Jpeg2000PrecinctsSize</key> - <map> + </map> + <key>Jpeg2000PrecinctsSize</key> + <map> <key>Comment</key> <string>Size of image precincts. Assumed square and same for all levels. Must be power of 2.</string> <key>Persist</key> @@ -3828,9 +3828,9 @@ <string>S32</string> <key>Value</key> <integer>256</integer> - </map> - <key>Jpeg2000BlocksSize</key> - <map> + </map> + <key>Jpeg2000BlocksSize</key> + <map> <key>Comment</key> <string>Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4.</string> <key>Persist</key> @@ -3839,7 +3839,7 @@ <string>S32</string> <key>Value</key> <integer>64</integer> - </map> + </map> <key>KeepAspectForSnapshot</key> <map> <key>Comment</key> @@ -3917,10 +3917,23 @@ <key>Value</key> <string>Monospace</string> </map> + <key>LuaAutorunPath</key> + <map> + <key>Comment</key> + <string>Directories containing scripts to autorun at viewer startup</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <string>scripts/lua/auto</string> + </array> + </map> <key>LuaChunk</key> <map> <key>Comment</key> - <string>Zero or more Lua chunks to run</string> + <string>Zero or more Lua chunks to run from command line</string> <key>Persist</key> <integer>0</integer> <key>Type</key> @@ -3928,10 +3941,36 @@ <key>Value</key> <array /> </map> + <key>LuaCommandPath</key> + <map> + <key>Comment</key> + <string>Directories containing scripts recognized as chat slash commands</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <string>scripts/lua</string> + </array> + </map> + <key>LuaRequirePath</key> + <map> + <key>Comment</key> + <string>Directories containing Lua modules loadable by require()</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <array> + <string>scripts/lua/require</string> + </array> + </map> <key>LuaScript</key> <map> <key>Comment</key> - <string>Zero or more Lua script files to run</string> + <string>Zero or more Lua script files to run from command line</string> <key>Persist</key> <integer>0</integer> <key>Type</key> @@ -4469,17 +4508,17 @@ <key>Value</key> <string /> </map> - <key>MarketplaceListingsLogging</key> - <map> - <key>Comment</key> - <string>Enable debug output associated with the Marketplace Listings (SLM) API.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> + <key>MarketplaceListingsLogging</key> + <map> + <key>Comment</key> + <string>Enable debug output associated with the Marketplace Listings (SLM) API.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>MarketplaceURL</key> <map> <key>Comment</key> @@ -5365,28 +5404,28 @@ <key>Value</key> <integer>1000</integer> </map> - <key>FakeInitialOutfitName</key> - <map> - <key>Comment</key> - <string>Pretend that this is first time login and specified name was chosen</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> + <key>FakeInitialOutfitName</key> + <map> + <key>Comment</key> + <string>Pretend that this is first time login and specified name was chosen</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> <string>String</string> <key>Value</key> <string /> - </map> - <key>MyOutfitsAutofill</key> - <map> - <key>Comment</key> - <string>Always autofill My Outfits from library when empty (else happens just once).</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> + </map> + <key>MyOutfitsAutofill</key> + <map> + <key>Comment</key> + <string>Always autofill My Outfits from library when empty (else happens just once).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>NearMeRange</key> <map> <key>Comment</key> @@ -5506,7 +5545,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>0</integer> </map> <key>NonvisibleObjectsInMemoryTime</key> <map> @@ -5517,7 +5556,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>64</integer> + <integer>64</integer> </map> <key>NoPreload</key> <map> @@ -6429,7 +6468,7 @@ <key>Value</key> <real>6.0</real> </map> - <key>PreferredMaturity</key> + <key>PreferredMaturity</key> <map> <key>Comment</key> <string>Setting for the user's preferred maturity level (consts in indra_constants.h)</string> @@ -6438,7 +6477,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>13</integer> + <integer>13</integer> </map> <key>PreviewAmbientColor</key> <map> @@ -6608,8 +6647,8 @@ </map> <key>PrimMediaMasterEnabled</key> - <map> - <key>Comment</key> + <map> + <key>Comment</key> <string>Whether or not Media on a Prim is enabled.</string> <key>Persist</key> <integer>1</integer> @@ -6618,9 +6657,9 @@ <key>Value</key> <integer>1</integer> </map> - <key>PrimMediaControlsUseHoverControlSet</key> - <map> - <key>Comment</key> + <key>PrimMediaControlsUseHoverControlSet</key> + <map> + <key>Comment</key> <string>Whether or not hovering over prim media uses minimal "hover" controls or the authored control set.</string> <key>Persist</key> <integer>1</integer> @@ -6629,17 +6668,17 @@ <key>Value</key> <integer>0</integer> </map> - <key>PrimMediaDragNDrop</key> - <map> - <key>Comment</key> - <string>Enable drag and drop of URLs onto prim faces</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> + <key>PrimMediaDragNDrop</key> + <map> + <key>Comment</key> + <string>Enable drag and drop of URLs onto prim faces</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>PrimMediaMaxRetries</key> <map> <key>Comment</key> @@ -6673,7 +6712,7 @@ <key>Value</key> <real>5.0</real> </map> - <key>PrimMediaMaxSortedQueueSize</key> + <key>PrimMediaMaxSortedQueueSize</key> <map> <key>Comment</key> <string>Maximum number of objects the viewer will load media for initially</string> @@ -6684,7 +6723,7 @@ <key>Value</key> <integer>100000</integer> </map> - <key>PrimMediaMaxRoundRobinQueueSize</key> + <key>PrimMediaMaxRoundRobinQueueSize</key> <map> <key>Comment</key> <string>Maximum number of objects the viewer will continuously update media for</string> @@ -8788,17 +8827,17 @@ <key>Value</key> <integer>1024</integer> </map> - <key>RenderHeroProbeDistance</key> - <map> - <key>Comment</key> - <string>Distance in meters for hero probes to render out to.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>8</real> - </map> + <key>RenderHeroProbeDistance</key> + <map> + <key>Comment</key> + <string>Distance in meters for hero probes to render out to.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>8</real> + </map> <key>RenderHeroProbeUpdateRate</key> <map> <key>Comment</key> @@ -9363,17 +9402,17 @@ <key>Value</key> <integer>1</integer> </map> - <key>RenderTransparentWater</key> - <map> - <key>Comment</key> - <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string> + <key>RenderTransparentWater</key> + <map> + <key>Comment</key> + <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> <integer>1</integer> - </map> + </map> <key>RenderTreeLODFactor</key> <map> <key>Comment</key> @@ -9655,18 +9694,18 @@ <key>Value</key> <integer>1</integer> </map> - <key>RenderPreferStreamDraw</key> - <map> - <key>Comment</key> - <string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>RenderVolumeLODFactor</key> + <key>RenderPreferStreamDraw</key> + <map> + <key>Comment</key> + <string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>RenderVolumeLODFactor</key> <map> <key>Comment</key> <string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string> @@ -9765,18 +9804,18 @@ <key>Value</key> <integer>0</integer> </map> - <key>ReportBugURL</key> - <map> - <key>Comment</key> - <string>URL used for filing bugs from viewer</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>https://feedback.secondlife.com/</string> - </map> - <key>RevokePermsOnStopAnimation</key> + <key>ReportBugURL</key> + <map> + <key>Comment</key> + <string>URL used for filing bugs from viewer</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>https://feedback.secondlife.com/</string> + </map> + <key>RevokePermsOnStopAnimation</key> <map> <key>Comment</key> <string>Clear animation permssions when choosing "Stop Animating Me"</string> @@ -10029,39 +10068,39 @@ <key>Value</key> <real>400.0</real> </map> - <key>SceneLoadingMonitorEnabled</key> - <map> - <key>Comment</key> - <string>Enabled scene loading monitor if set</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>SceneLoadingMonitorSampleTime</key> - <map> - <key>Comment</key> - <string>Time between screen samples when monitor scene load (seconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.25</real> - </map> - <key>SceneLoadingMonitorPixelDiffThreshold</key> - <map> - <key>Comment</key> - <string>Amount of pixels changed required to consider the scene as still loading (square root of fraction of pixels on screen)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.02</real> - </map> + <key>SceneLoadingMonitorEnabled</key> + <map> + <key>Comment</key> + <string>Enabled scene loading monitor if set</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>SceneLoadingMonitorSampleTime</key> + <map> + <key>Comment</key> + <string>Time between screen samples when monitor scene load (seconds)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.25</real> + </map> + <key>SceneLoadingMonitorPixelDiffThreshold</key> + <map> + <key>Comment</key> + <string>Amount of pixels changed required to consider the scene as still loading (square root of fraction of pixels on screen)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.02</real> + </map> <key>ScriptHelpFollowsCursor</key> <map> <key>Comment</key> @@ -10238,7 +10277,7 @@ <key>Value</key> <integer>0</integer> </map> - <key>AvatarNameTagMode</key> + <key>AvatarNameTagMode</key> <map> <key>Comment</key> <string>Select Avatar Name Tag Mode</string> @@ -10447,7 +10486,7 @@ <key>Value</key> <integer>1</integer> </map> - <key>ShowScriptErrors</key> + <key>ShowScriptErrors</key> <map> <key>Comment</key> <string>Show script errors</string> @@ -10458,7 +10497,7 @@ <key>Value</key> <integer>1</integer> </map> - <key>ShowScriptErrorsLocation</key> + <key>ShowScriptErrorsLocation</key> <map> <key>Comment</key> <string>Show script error in chat (0) or window (1).</string> @@ -10717,8 +10756,8 @@ <string>Display results of find events that are flagged as moderate</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10730,8 +10769,8 @@ <string>Display results of find events that are flagged as adult</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10743,8 +10782,8 @@ <string>Display results of find land sales that are flagged as general</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10756,8 +10795,8 @@ <string>Display results of find land sales that are flagged as moderate</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10769,8 +10808,8 @@ <string>Display results of find land sales that are flagged as adult</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10782,8 +10821,8 @@ <string>Display results of find places or find popular that are in general sims</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10795,8 +10834,8 @@ <string>Display results of find places or find popular that are in moderate sims</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10808,8 +10847,8 @@ <string>Display results of find places or find popular that are in adult sims</string> <key>Persist</key> <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> @@ -10947,17 +10986,17 @@ <key>Value</key> <integer>0</integer> </map> - <key>ShowTutorial</key> - <map> - <key>Comment</key> - <string>Show tutorial window on login</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> + <key>ShowTutorial</key> + <map> + <key>Comment</key> + <string>Show tutorial window on login</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>ShowVoiceVisualizersInCalls</key> <map> <key>Comment</key> @@ -13529,17 +13568,17 @@ <key>Value</key> <real>0.40000000596</real> </map> - <key>moapbeacon</key> - <map> - <key>Comment</key> - <string>Beacon / Highlight media on a prim sources</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> + <key>moapbeacon</key> + <map> + <key>Comment</key> + <string>Beacon / Highlight media on a prim sources</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>particlesbeacon</key> <map> <key>Comment</key> @@ -13639,17 +13678,17 @@ <key>Value</key> <integer>0</integer> </map> - <key>SLURLDragNDrop</key> - <map> - <key>Comment</key> - <string>Enable drag and drop of SLURLs onto the viewer</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> + <key>SLURLDragNDrop</key> + <map> + <key>Comment</key> + <string>Enable drag and drop of SLURLs onto the viewer</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>SLURLPassToOtherInstance</key> <map> <key>Comment</key> @@ -13837,10 +13876,10 @@ <string>LLSD</string> <key>Value</key> <array> - <string>snapshot</string> - <string>postcard</string> - <string>mini_map</string> - <string>beacons</string> + <string>snapshot</string> + <string>postcard</string> + <string>mini_map</string> + <string>beacons</string> </array> </map> <key>LandmarksSortedByDate</key> @@ -14590,7 +14629,7 @@ <key>Value</key> <integer>0</integer> </map> - <key>LocalTerrainAsset1</key> + <key>LocalTerrainAsset1</key> <map> <key>Comment</key> <string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string> @@ -14601,7 +14640,7 @@ <key>Value</key> <string>00000000-0000-0000-0000-000000000000</string> </map> - <key>LocalTerrainAsset2</key> + <key>LocalTerrainAsset2</key> <map> <key>Comment</key> <string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string> @@ -14612,7 +14651,7 @@ <key>Value</key> <string>00000000-0000-0000-0000-000000000000</string> </map> - <key>LocalTerrainAsset3</key> + <key>LocalTerrainAsset3</key> <map> <key>Comment</key> <string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string> @@ -14623,7 +14662,7 @@ <key>Value</key> <string>00000000-0000-0000-0000-000000000000</string> </map> - <key>LocalTerrainAsset4</key> + <key>LocalTerrainAsset4</key> <map> <key>Comment</key> <string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string> @@ -14634,7 +14673,7 @@ <key>Value</key> <string>00000000-0000-0000-0000-000000000000</string> </map> - <key>PathfindingRetrieveNeighboringRegion</key> + <key>PathfindingRetrieveNeighboringRegion</key> <map> <key>Comment</key> <string>Download a neighboring region when visualizing a pathfinding navmesh (default val 99 means do not download neighbors).</string> @@ -14643,9 +14682,9 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>99</integer> + <integer>99</integer> </map> - <key>PathfindingNavMeshClear</key> + <key>PathfindingNavMeshClear</key> <map> <key>Comment</key> <string>Background color when displaying pathfinding navmesh.</string> @@ -14805,7 +14844,7 @@ <real>1.0</real> </array> </map> - <key>PathfindingTestPathValidEndColor</key> + <key>PathfindingTestPathValidEndColor</key> <map> <key>Comment</key> <string>Color of the pathfinding test-pathing tool end-point when the path is valid.</string> @@ -14837,7 +14876,7 @@ <real>1.0</real> </array> </map> - <key>PathfindingTestPathColor</key> + <key>PathfindingTestPathColor</key> <map> <key>Comment</key> <string>Color of the pathfinding test-path when the path is valid.</string> @@ -15397,17 +15436,6 @@ <key>Value</key> <integer>3</integer> </map> - <key>AutorunLuaScriptName</key> - <map> - <key>Comment</key> - <string>Script name to autorun after login.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>default.lua</string> - </map> <key>ResetUIScaleOnFirstRun</key> <map> <key>Comment</key> @@ -15485,17 +15513,17 @@ <key>Value</key> <real>300</real> </map> - <key>StatsReportFileInterval</key> - <map> - <key>Comment</key> - <string>Interval to save viewer stats file data</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.2</real> - </map> + <key>StatsReportFileInterval</key> + <map> + <key>Comment</key> + <string>Interval to save viewer stats file data</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.2</real> + </map> <key>StatsReportSkipZeroDataSaves</key> <map> <key>Comment</key> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 65e5e4f783..ef12fe0bd3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -117,6 +117,7 @@ #include "lldiriterator.h" #include "llexperiencecache.h" #include "llimagej2c.h" +#include "llluamanager.h" #include "llmemory.h" #include "llprimitive.h" #include "llurlaction.h" @@ -1218,6 +1219,24 @@ bool LLAppViewer::init() // no completion callback: we don't need to know LLLUAmanager::runScriptFile(script); }); + processComposeSwitch( + "LuaAutorunPath", "LuaAutorunPath", + [](const LLSD& directory) + { + // each directory can be relative to the viewer's install + // directory -- if directory is already absolute, operator/() + // preserves it + auto abspath(fsyspath(gDirUtilp->getAppRODataDir()) / directory.asString()); + std::string absdir(abspath.string()); + LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << LL_ENDL; + LLDirIterator scripts(absdir, "*.lua"); + std::string script; + while (scripts.next(script)) + { + LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << ": " << script << LL_ENDL; + LLLUAmanager::runScriptFile((abspath / script).string()); + } + }); if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0) { diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 3ed72c34f3..77f197b2d2 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -265,27 +265,6 @@ void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_r }); } -void LLLUAmanager::runScriptOnLogin() -{ -#ifndef LL_TEST - std::string filename = gSavedSettings.getString("AutorunLuaScriptName"); - if (filename.empty()) - { - LL_INFOS() << "Script name wasn't set." << LL_ENDL; - return; - } - - filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); - if (!gDirUtilp->fileExists(filename)) - { - LL_INFOS() << filename << " was not found." << LL_ENDL; - return; - } - - runScriptFile(filename); -#endif // ! LL_TEST -} - std::string read_file(const std::string &name) { llifstream in_file; diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index af9dcf70c2..dcbb91f799 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -82,8 +82,6 @@ public: // The return value is the (count, result) pair described above. static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& chunk); - static void runScriptOnLogin(); - static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } private: diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 470e512694..3cf0def66e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -208,7 +208,6 @@ #include "llstacktrace.h" #include "threadpool.h" -#include "llluamanager.h" #include "llperfstats.h" @@ -2422,8 +2421,6 @@ bool idle_startup() LLPerfStats::StatsRecorder::setAutotuneInit(); - LLLUAmanager::runScriptOnLogin(); - return TRUE; } -- cgit v1.2.3 From 07f0f12bcbe864177a145b074c2739eaf08f2c5c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 1 Jul 2024 13:02:49 +0300 Subject: Move error strings to strings.xml; pass wearable type and is_worn flag for outfit items --- indra/newview/llappearancelistener.cpp | 20 +++++++++++++------- indra/newview/llappearancemgr.cpp | 9 +++++---- indra/newview/scripts/lua/test_outfits_list.lua | 8 +++++++- indra/newview/skins/default/xui/en/strings.xml | 4 ++++ 4 files changed, 29 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 11037a0078..3db2c64b78 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -29,8 +29,9 @@ #include "llappearancemgr.h" #include "llinventoryfunctions.h" -#include "stringize.h" +#include "lltransutil.h" #include "llwearableitemslist.h" +#include "stringize.h" LLAppearanceListener::LLAppearanceListener() : LLEventAPI("LLAppearance", @@ -65,7 +66,7 @@ LLAppearanceListener::LLAppearanceListener() &LLAppearanceListener::getOutfitsList); add("getOutfitItems", - "Return the table of items(id and name) inside specified outfit folder", + "Return the table of items with info(id : name, wearable_type, is_worn) inside specified outfit folder", &LLAppearanceListener::getOutfitItems); } @@ -76,19 +77,19 @@ void LLAppearanceListener::wearOutfit(LLSD const &data) LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); if (!cat) { - response.error(stringize("Couldn't find outfit ", data["folder_id"].asUUID())); + response.error(stringize(LLTrans::getString("OutfitNotFound"), data["folder_id"].asUUID())); return; } if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { - response.error(stringize("Can't wear system folder ", data["folder_id"].asUUID())); + response.error(stringize(LLTrans::getString("SystemFolderNotWorn"), data["folder_id"].asUUID())); return; } bool append = data["append"].asBoolean(); bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); if (!can_wear) { - std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); return; } @@ -141,7 +142,7 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - response.error(stringize("Can't find outfit folder with id: ", outfit_id.asString())); + response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); } LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; @@ -151,7 +152,12 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLSD items_data; for (const LLPointer<LLViewerInventoryItem> &it : item_array) { - items_data[it->getUUID().asString()] = it->getName(); + LLSD info; + info["name"] = it->getName(); + info["wearable_type"] = LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE); + info["is_worn"] = get_is_item_worn(it); + + items_data[it->getUUID().asString()] = info; } response["items"] = items_data; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 19b81f5a79..3d13f8afc8 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -49,6 +49,7 @@ #include "lloutfitslist.h" #include "llselectmgr.h" #include "llsidepanelappearance.h" +#include "lltransutil.h" #include "llviewerobjectlist.h" #include "llvoavatar.h" #include "llvoavatarself.h" @@ -2941,14 +2942,14 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); if (is_system_folder) { - error_msg = stringize("Can't wear system folder ", std::quoted(name)); + error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(name)); return false; } bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); if (!can_wear) { - std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; - error_msg = stringize(msg, std::quoted(name), " , id: ", cat->getUUID()); + std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); + error_msg = stringize(msg, std::quoted(name), ", id: ", cat->getUUID()); LL_WARNS() << error_msg << LL_ENDL; return false; } @@ -2956,7 +2957,7 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std } else { - error_msg = stringize("Couldn't find outfit ", std::quoted(name)); + error_msg = stringize(LLTrans::getString("OutfitNotFound"), std::quoted(name)); LL_WARNS() << error_msg << LL_ENDL; return false; } diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua index dd5f914402..1011029f34 100644 --- a/indra/newview/scripts/lua/test_outfits_list.lua +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -34,7 +34,13 @@ function populate_list() action_data.action = "add_list_element" action_data.ctrl_name = "outfits_list" local outfits = {} - for uuid, name in pairs(DATA_MAP) do + for uuid, info in pairs(DATA_MAP) do + name = {} + if SHOW_OUTFITS then + name = info + else + name = info.name + end table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) end action_data.value = outfits diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 76a2660dbb..492b29fbc7 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -4028,6 +4028,10 @@ Please check http://status.secondlifegrid.net to see if there is a known problem <string name="DeleteItem">Delete selected item?</string> <string name="EmptyOutfitText">There are no items in this outfit</string> + <string name="OutfitNotFound" value="Couldn't find outfit "/> + <string name="OutfitNotAdded" value="Can't add to COF outfit "/> + <string name="OutfitNotReplaced" value="Can't replace COF with outfit "/> + <string name="SystemFolderNotWorn" value="Can't wear system folder "/> <!-- External editor status codes --> <string name="ExternalEditorNotSet">Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting. -- cgit v1.2.3 From 3961bac0ef705775883a4b37f2b6a84e41b82c05 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Mon, 1 Jul 2024 14:47:52 +0300 Subject: build fix --- indra/newview/llappearancelistener.cpp | 5 +++-- indra/newview/llappearancemgr.cpp | 13 +++++++++++-- indra/newview/llappearancemgr.h | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 3db2c64b78..b29eb48a1b 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -100,7 +100,7 @@ void LLAppearanceListener::wearOutfitByName(LLSD const &data) { Response response(LLSD(), data); std::string error_msg; - if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), data["append"].asBoolean(), error_msg)) + if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, data["append"].asBoolean())) { response.error(error_msg); } @@ -147,7 +147,8 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, LLFindOutfitItems()); + LLFindOutfitItems collector = LLFindOutfitItems(); + gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); LLSD items_data; for (const LLPointer<LLViewerInventoryItem> &it : item_array) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 3d13f8afc8..e4a545a55b 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2904,7 +2904,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } -bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std::string& error_msg) +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& error_msg, bool append) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2950,7 +2950,6 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std { std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); error_msg = stringize(msg, std::quoted(name), ", id: ", cat->getUUID()); - LL_WARNS() << error_msg << LL_ENDL; return false; } LLAppearanceMgr::wearInventoryCategory(cat, copy_items, append); @@ -2958,6 +2957,16 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std else { error_msg = stringize(LLTrans::getString("OutfitNotFound"), std::quoted(name)); + return false; + } + return true; +} + +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append) +{ + std::string error_msg; + if(!wearOutfitByName(name, error_msg, append)) + { LL_WARNS() << error_msg << LL_ENDL; return false; } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index d7b6cd5a61..adc783be5a 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -59,7 +59,8 @@ public: void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); - bool wearOutfitByName(const std::string &name, bool append = false, std::string &error_msg = std::string()); + bool wearOutfitByName(const std::string &name, std::string &error_msg, bool append = false); + bool wearOutfitByName(const std::string &name, bool append = false); void changeOutfit(bool proceed, const LLUUID& category, bool append); void replaceCurrentOutfit(const LLUUID& new_outfit); void renameOutfit(const LLUUID& outfit_id); -- cgit v1.2.3 From 212868a8c3f803b387da602b6440f69c2c617e40 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Jul 2024 10:35:34 -0400 Subject: Promote LuaRemover from llluamanager.cpp to lua_function.h. --- indra/newview/llluamanager.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 77f197b2d2..c95ce9c57b 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -309,31 +309,6 @@ LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : luaL_argerrorL(L, 1, "cannot require a full path"); } -/** - * Remove a particular stack index on exit from enclosing scope. - * If you pass a negative index (meaning relative to the current stack top), - * converts to an absolute index. The point of LuaRemover is to remove the - * entry at the specified index regardless of subsequent pushes to the stack. - */ -class LuaRemover -{ -public: - LuaRemover(lua_State* L, int index): - mState(L), - mIndex(lua_absindex(L, index)) - {} - LuaRemover(const LuaRemover&) = delete; - LuaRemover& operator=(const LuaRemover&) = delete; - ~LuaRemover() - { - lua_remove(mState, mIndex); - } - -private: - lua_State* mState; - int mIndex; -}; - // push the loaded module or throw a Lua error void LLRequireResolver::findModule() { -- cgit v1.2.3 From f8357732a108e579c285a76a53c550b8b5c0a153 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Jul 2024 12:09:59 -0400 Subject: Make require() implementation honor LuaRequirePath setting. Remove LL_TEST special case from require() code (to search in the viewer's source tree). Instead, make llluamanager_test.cpp append to LuaRequirePath to get the same effect. --- indra/newview/llluamanager.cpp | 18 +++++++---------- indra/newview/tests/llluamanager_test.cpp | 33 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c95ce9c57b..ccfa08078e 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -32,6 +32,7 @@ #include "llcoros.h" #include "llerror.h" #include "lleventcoro.h" +#include "llsdutil.h" #include "llviewercontrol.h" #include "lua_function.h" #include "lualistener.h" @@ -338,18 +339,13 @@ void LLRequireResolver::findModule() fail(); } - std::vector<fsyspath> lib_paths + LLSD lib_paths(gSavedSettings.getLLSD("LuaRequirePath")); + LL_DEBUGS("Lua") << "LuaRequirePath = " << lib_paths << LL_ENDL; + for (const auto& path : llsd::inArray(lib_paths)) { - gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua", "require"), -#ifdef LL_TEST - // Build-time tests don't have the app bundle - use source tree. - fsyspath(__FILE__).parent_path() / "scripts" / "lua" / "require", -#endif - }; - - for (const auto& path : lib_paths) - { - std::string absolutePathOpt = (path / mPathToResolve).u8string(); + // if path is already absolute, operator/() preserves it + auto abspath(fsyspath(gDirUtilp->getAppRODataDir()) / path.asString()); + std::string absolutePathOpt = (abspath / mPathToResolve).u8string(); if (absolutePathOpt.empty()) luaL_error(L, "error requiring module '%s'", mPathToResolve.u8string().data()); diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index d3fc70dfd5..55e87acaea 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -21,6 +21,7 @@ #include "../llcommon/tests/StringVec.h" #include "../test/lltut.h" #include "llapp.h" +#include "llcontrol.h" #include "lldate.h" #include "llevents.h" #include "lleventcoro.h" @@ -39,6 +40,8 @@ public: bool frame() override { return true; } }; +LLControlGroup gSavedSettings("Global"); + template <typename CALLABLE> auto listener(CALLABLE&& callable) { @@ -57,6 +60,36 @@ namespace tut { struct llluamanager_data { + llluamanager_data() + { + // Load gSavedSettings from source tree + // indra/newview/tests/llluamanager_test.cpp => + // indra/newview + auto newview{ fsyspath(__FILE__).parent_path().parent_path() }; + auto settings{ newview / "app_settings" / "settings.xml" }; + // true suppresses implicit declare; implicit declare requires + // that every variable in settings.xml has a Comment, which many don't. + gSavedSettings.loadFromFile(settings.u8string().c_str(), true); + // At test time, since we don't have the app bundle available, + // extend LuaRequirePath to include the require directory in the + // source tree. + auto require{ (newview / "scripts" / "lua" / "require").u8string() }; + auto paths{ gSavedSettings.getLLSD("LuaRequirePath") }; + bool found = false; + for (const auto& path : llsd::inArray(paths)) + { + if (path.asString() == require) + { + found = true; + break; + } + } + if (! found) + { + paths.append(require); + gSavedSettings.setLLSD("LuaRequirePath", paths); + } + } // We need an LLApp instance because LLLUAmanager uses coroutines, // which suspend, and when a coroutine suspends it checks LLApp state, // and if it's not APP_STATUS_RUNNING the coroutine terminates. -- cgit v1.2.3 From 9a3c770a3bf430da8878a8691cee9b726a5f026c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 2 Jul 2024 13:12:40 -0400 Subject: Eliminate c_str() calls from LLControlGroup::loadFromFile() calls. Passing std::string::c_str() to a (const std::string&) function parameter is worse than clutter, it's pointless overhead: it forces the compiler to construct a new std::string instance, instead of passing a const reference to the one you already have in hand. --- indra/newview/tests/llluamanager_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 55e87acaea..824ddd445b 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -69,7 +69,7 @@ namespace tut auto settings{ newview / "app_settings" / "settings.xml" }; // true suppresses implicit declare; implicit declare requires // that every variable in settings.xml has a Comment, which many don't. - gSavedSettings.loadFromFile(settings.u8string().c_str(), true); + gSavedSettings.loadFromFile(settings.u8string(), true); // At test time, since we don't have the app bundle available, // extend LuaRequirePath to include the require directory in the // source tree. -- cgit v1.2.3 From a877e3a0994a19d522e77d6781844341197dd6dc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 3 Jul 2024 14:05:25 -0400 Subject: Use llsd::toMap() to return LLSD maps from "LLAppearance" listener. --- indra/newview/llappearancelistener.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index b29eb48a1b..2a3133433a 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -127,12 +127,9 @@ void LLAppearanceListener::getOutfitsList(LLSD const &data) LLIsType is_category(LLAssetType::AT_CATEGORY); gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); - LLSD outfits_data; - for (const LLPointer<LLViewerInventoryCategory> &cat : cat_array) - { - outfits_data[cat->getUUID().asString()] = cat->getName(); - } - response["outfits"] = outfits_data; + response["outfits"] = llsd::toMap(cat_array, + [](const LLPointer<LLViewerInventoryCategory> &cat) + { return std::make_pair(cat->getUUID().asString(), cat->getName()); }); } void LLAppearanceListener::getOutfitItems(LLSD const &data) @@ -150,16 +147,14 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLFindOutfitItems collector = LLFindOutfitItems(); gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); - LLSD items_data; - for (const LLPointer<LLViewerInventoryItem> &it : item_array) - { - LLSD info; - info["name"] = it->getName(); - info["wearable_type"] = LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE); - info["is_worn"] = get_is_item_worn(it); - - items_data[it->getUUID().asString()] = info; - } - - response["items"] = items_data; + response["items"] = llsd::toMap(item_array, + [](const LLPointer<LLViewerInventoryItem> &it) + { + return std::make_pair( + it->getUUID().asString(), + llsd::map( + "name", it->getName(), + "wearable_type", LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE), + "is_worn", get_is_item_worn(it))); + }); } -- cgit v1.2.3 From ece0f4eb566af937d724f60f934beb6dfcb4d493 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 5 Jul 2024 16:03:51 +0300 Subject: clean up and rename demo script --- indra/newview/llappearancelistener.cpp | 93 +++++++++-------- indra/newview/llappearancelistener.h | 5 +- indra/newview/llappearancemgr.cpp | 28 ++++- indra/newview/llappearancemgr.h | 1 + indra/newview/llwearableitemslist.h | 3 +- indra/newview/scripts/lua/require/LLAppearance.lua | 28 ++--- indra/newview/scripts/lua/test_LLAppearance.lua | 114 +++++++++++++++++++++ indra/newview/scripts/lua/test_outfits_list.lua | 114 --------------------- 8 files changed, 205 insertions(+), 181 deletions(-) create mode 100644 indra/newview/scripts/lua/test_LLAppearance.lua delete mode 100644 indra/newview/scripts/lua/test_outfits_list.lua (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 2a3133433a..75eaf29186 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -38,28 +38,20 @@ LLAppearanceListener::LLAppearanceListener() "API to wear a specified outfit and wear/remove individual items") { add("wearOutfit", - "Wear outfit by folder id: [folder_id]" + "Wear outfit by folder id: [folder_id] OR by folder name: [folder_name]\n" "When [\"append\"] is true, outfit will be added to COF\n" "otherwise it will replace current oufit", - &LLAppearanceListener::wearOutfit, - llsd::map("folder_id", LLSD(), "append", LLSD())); + &LLAppearanceListener::wearOutfit); - add("wearOutfitByName", - "Wear outfit by folder name: [folder_name]" - "When [\"append\"] is true, outfit will be added to COF\n" - "otherwise it will replace current oufit", - &LLAppearanceListener::wearOutfitByName, - llsd::map("folder_name", LLSD(), "append", LLSD())); - - add("wearItem", - "Wear item by item id: [item_id]", - &LLAppearanceListener::wearItem, - llsd::map("item_id", LLSD(), "replace", LLSD())); + add("wearItems", + "Wear items by id: [items_id]", + &LLAppearanceListener::wearItems, + llsd::map("items_id", LLSD(), "replace", LLSD())); - add("detachItem", - "Detach item by item id: [item_id]", - &LLAppearanceListener::detachItem, - llsd::map("item_id", LLSD())); + add("detachItems", + "Detach items by id: [items_id]", + &LLAppearanceListener::detachItems, + llsd::map("items_id", LLSD())); add("getOutfitsList", "Return the table with Outfits info(id and name)", @@ -74,46 +66,61 @@ LLAppearanceListener::LLAppearanceListener() void LLAppearanceListener::wearOutfit(LLSD const &data) { Response response(LLSD(), data); - LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); - if (!cat) + if (!data.has("folder_id") && !data.has("folder_name")) { - response.error(stringize(LLTrans::getString("OutfitNotFound"), data["folder_id"].asUUID())); - return; + return response.error("Either [folder_id] or [folder_name] is required"); } - if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + + std::string error_msg; + bool result(false); + bool append = data.has("append") ? data["append"].asBoolean() : false; + if (data.has("folder_id")) { - response.error(stringize(LLTrans::getString("SystemFolderNotWorn"), data["folder_id"].asUUID())); - return; + result = LLAppearanceMgr::instance().wearOutfit(data["folder_id"].asUUID(), error_msg, append); } - bool append = data["append"].asBoolean(); - bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); - if (!can_wear) + else { - std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); - response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); - return; + result = LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, append); } - LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); -} -void LLAppearanceListener::wearOutfitByName(LLSD const &data) -{ - Response response(LLSD(), data); - std::string error_msg; - if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, data["append"].asBoolean())) + if (!result) { response.error(error_msg); } } -void LLAppearanceListener::wearItem(LLSD const &data) +void LLAppearanceListener::wearItems(LLSD const &data) { - LLAppearanceMgr::instance().wearItemOnAvatar(data["item_id"].asUUID(), true, data["replace"].asBoolean()); + if (data["items_id"].isArray()) + { + uuid_vec_t ids; + for (const auto &id : llsd::inArray(data["items_id"])) + { + ids.push_back(id); + } + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); + } + else + { + LLAppearanceMgr::instance().wearItemOnAvatar(data["items_id"].asUUID(), true, data["replace"].asBoolean()); + } } -void LLAppearanceListener::detachItem(LLSD const &data) +void LLAppearanceListener::detachItems(LLSD const &data) { - LLAppearanceMgr::instance().removeItemFromAvatar(data["item_id"].asUUID()); + if (data["items_id"].isArray()) + { + uuid_vec_t ids; + for (const auto &id : llsd::inArray(data["items_id"])) + { + ids.push_back(id); + } + LLAppearanceMgr::instance().removeItemsFromAvatar(ids); + } + else + { + LLAppearanceMgr::instance().removeItemFromAvatar(data["items_id"].asUUID()); + } } void LLAppearanceListener::getOutfitsList(LLSD const &data) @@ -139,7 +146,7 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); + return response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); } LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h index 00553c072f..04c5eac2eb 100644 --- a/indra/newview/llappearancelistener.h +++ b/indra/newview/llappearancelistener.h @@ -36,9 +36,8 @@ public: private: void wearOutfit(LLSD const &data); - void wearOutfitByName(LLSD const &data); - void wearItem(LLSD const &data); - void detachItem(LLSD const &data); + void wearItems(LLSD const &data); + void detachItems(LLSD const &data); void getOutfitsList(LLSD const &data); void getOutfitItems(LLSD const &data); }; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index e4a545a55b..7a34006323 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2939,8 +2939,8 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& err if(cat) { - bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); - if (is_system_folder) + // don't allow wearing a system folder + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(name)); return false; @@ -2962,6 +2962,30 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& err return true; } +bool LLAppearanceMgr::wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append) +{ + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + if (!cat) + { + error_msg = stringize(LLTrans::getString("OutfitNotFound"), cat_id); + return false; + } + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), cat_id); + return false; + } + bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat_id) : LLAppearanceMgr::instance().getCanReplaceCOF(cat_id); + if (!can_wear) + { + std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); + error_msg = stringize(msg, std::quoted(cat->getName()), " , id: ", cat_id); + return false; + } + LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); + return true; +} + bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append) { std::string error_msg; diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index adc783be5a..b795494f94 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -59,6 +59,7 @@ public: void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); + bool wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append = false); bool wearOutfitByName(const std::string &name, std::string &error_msg, bool append = false); bool wearOutfitByName(const std::string &name, bool append = false); void changeOutfit(bool proceed, const LLUUID& category, bool append); diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index a24679961f..15033f5e9a 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -506,9 +506,8 @@ protected: LLWearableType::EType mMenuWearableType; }; -class LLFindOutfitItems : public LLInventoryCollectFunctor +struct LLFindOutfitItems : public LLInventoryCollectFunctor { - public: LLFindOutfitItems() {} virtual ~LLFindOutfitItems() {} virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); diff --git a/indra/newview/scripts/lua/require/LLAppearance.lua b/indra/newview/scripts/lua/require/LLAppearance.lua index 165bb6d06f..f533d22daf 100644 --- a/indra/newview/scripts/lua/require/LLAppearance.lua +++ b/indra/newview/scripts/lua/require/LLAppearance.lua @@ -1,29 +1,23 @@ -leap = require 'leap' +local leap = require 'leap' local LLAppearance = {} -function LLAppearance.addOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +function LLAppearance.wearOutfit(folder, action) + action = action or 'add' + leap.request('LLAppearance', {op='wearOutfit', append = (action == 'add'), folder_id=folder}) end -function LLAppearance.replaceOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +function LLAppearance.wearOutfitByName(folder, action) + action = action or 'add' + leap.request('LLAppearance', {op='wearOutfit', append = (action == 'add'), folder_name=folder}) end -function LLAppearance.addOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +function LLAppearance.wearItems(items_id, replace) + leap.send('LLAppearance', {op='wearItems', replace = replace, items_id=items_id}) end -function LLAppearance.replaceOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) -end - -function LLAppearance.wearItem(item_id, replace) - leap.send('LLAppearance', {op='wearItem', replace = replace, item_id=item_id}) -end - -function LLAppearance.detachItem(item_id) - leap.send('LLAppearance', {op='detachItem', item_id=item_id}) +function LLAppearance.detachItems(items_id) + leap.send('LLAppearance', {op='detachItems', items_id=items_id}) end function LLAppearance.getOutfitsList() diff --git a/indra/newview/scripts/lua/test_LLAppearance.lua b/indra/newview/scripts/lua/test_LLAppearance.lua new file mode 100644 index 0000000000..5ddd9f15ff --- /dev/null +++ b/indra/newview/scripts/lua/test_LLAppearance.lua @@ -0,0 +1,114 @@ +local Floater = require 'Floater' +local LLAppearance = require 'LLAppearance' +local startup = require 'startup' +local inspect = require 'inspect' + +local SHOW_OUTFITS = true +local SELECTED_OUTFIT_ID = {} +local DATA_MAP = {} + +local wearables_lbl = 'Show wearables' +local outfits_lbl = 'Show outfits' +local replace_cof_lbl = 'Replace COF' +local add_cof_lbl = 'Add to COF' +local outfits_title = 'Outfits' +local wear_lbl = 'Wear item' +local detach_lbl = 'Detach item' + +local flt = Floater:new( + "luafloater_outfits_list.xml", + {outfits_list = {"double_click"}}) + +function get_selected_id() + return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value +end + +function populate_list() + if SHOW_OUTFITS then + DATA_MAP = LLAppearance.getOutfitsList() + else + DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID) + end + + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "outfits_list" + local outfits = {} + for uuid, info in pairs(DATA_MAP) do + name = {} + if SHOW_OUTFITS then + name = info + else + name = info.name + end + table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) + end + action_data.value = outfits + flt:post(action_data) +end + +function set_label(btn_name, value) + flt:post({action="set_label", ctrl_name=btn_name, value=value}) +end + +function set_enabled(btn_name, value) + flt:post({action="set_enabled", ctrl_name=btn_name, value=value}) +end + +function update_labels() + if SHOW_OUTFITS then + set_label('select_btn', wearables_lbl) + set_label('replace_btn', replace_cof_lbl) + set_label('add_btn', add_cof_lbl) + + set_enabled('select_btn', false) + flt:post({action="set_title", value=outfits_title}) + else + set_label('select_btn', outfits_lbl) + set_label('replace_btn', wear_lbl) + set_label('add_btn', detach_lbl) + + set_enabled('select_btn', true) + flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]}) + end + + set_enabled('replace_btn', false) + set_enabled('add_btn', false) +end + +function flt:post_build(event_data) + populate_list() +end + +function flt:commit_replace_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.wearOutfit(get_selected_id(), 'replace') + else + LLAppearance.wearItems(get_selected_id(), false) + end +end + +function flt:commit_add_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.wearOutfit(get_selected_id(), 'add') + else + LLAppearance.detachItems(get_selected_id()) + end +end + +function flt:commit_select_btn(event_data) + SHOW_OUTFITS = not SHOW_OUTFITS + SELECTED_OUTFIT_ID = get_selected_id() + update_labels() + self:post({action="clear_list", ctrl_name='outfits_list'}) + populate_list() +end + +function flt:commit_outfits_list(event_data) + set_enabled('replace_btn', true) + set_enabled('add_btn', true) + set_enabled('select_btn', true) +end + +startup.wait('STATE_STARTED') +flt:show() diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua deleted file mode 100644 index 1011029f34..0000000000 --- a/indra/newview/scripts/lua/test_outfits_list.lua +++ /dev/null @@ -1,114 +0,0 @@ -local Floater = require 'Floater' -local LLAppearance = require 'LLAppearance' -local startup = require 'startup' -local inspect = require 'inspect' - -local SHOW_OUTFITS = true -local SELECTED_OUTFIT_ID = {} -local DATA_MAP = {} - -local wearables_lbl = 'Show wearables' -local outfits_lbl = 'Show outfits' -local replace_cof_lbl = 'Replace COF' -local add_cof_lbl = 'Add to COF' -local outfits_title = 'Outfits' -local wear_lbl = 'Wear item' -local detach_lbl = 'Detach item' - -local flt = Floater:new( - "luafloater_outfits_list.xml", - {outfits_list = {"double_click"}}) - -function get_selected_id() - return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value -end - -function populate_list() - if SHOW_OUTFITS then - DATA_MAP = LLAppearance.getOutfitsList() - else - DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID) - end - - local action_data = {} - action_data.action = "add_list_element" - action_data.ctrl_name = "outfits_list" - local outfits = {} - for uuid, info in pairs(DATA_MAP) do - name = {} - if SHOW_OUTFITS then - name = info - else - name = info.name - end - table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) - end - action_data.value = outfits - flt:post(action_data) -end - -function set_label(btn_name, value) - flt:post({action="set_label", ctrl_name=btn_name, value=value}) -end - -function set_enabled(btn_name, value) - flt:post({action="set_enabled", ctrl_name=btn_name, value=value}) -end - -function update_labels() - if SHOW_OUTFITS then - set_label('select_btn', wearables_lbl) - set_label('replace_btn', replace_cof_lbl) - set_label('add_btn', add_cof_lbl) - - set_enabled('select_btn', false) - flt:post({action="set_title", value=outfits_title}) - else - set_label('select_btn', outfits_lbl) - set_label('replace_btn', wear_lbl) - set_label('add_btn', detach_lbl) - - set_enabled('select_btn', true) - flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]}) - end - - set_enabled('replace_btn', false) - set_enabled('add_btn', false) -end - -function flt:post_build(event_data) - populate_list() -end - -function flt:commit_replace_btn(event_data) - if SHOW_OUTFITS then - LLAppearance.replaceOutfit(get_selected_id()) - else - LLAppearance.wearItem(get_selected_id(), false) - end -end - -function flt:commit_add_btn(event_data) - if SHOW_OUTFITS then - LLAppearance.addOutfit(get_selected_id()) - else - LLAppearance.detachItem(get_selected_id()) - end -end - -function flt:commit_select_btn(event_data) - SHOW_OUTFITS = not SHOW_OUTFITS - SELECTED_OUTFIT_ID = get_selected_id() - update_labels() - self:post({action="clear_list", ctrl_name='outfits_list'}) - populate_list() -end - -function flt:commit_outfits_list(event_data) - set_enabled('replace_btn', true) - set_enabled('add_btn', true) - set_enabled('select_btn', true) -end - -startup.wait('STATE_STARTED') -flt:show() -- cgit v1.2.3 From b27606feca00172cdfd7467ff3e216824f1c9518 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 8 Jul 2024 13:56:46 +0300 Subject: Lua api for Snapshot and demo script --- indra/newview/llviewerwindow.cpp | 2 +- indra/newview/llviewerwindowlistener.cpp | 52 +++++++++++++++++++---------- indra/newview/scripts/lua/require/UI.lua | 15 +++++++++ indra/newview/scripts/lua/test_snapshot.lua | 15 +++++++++ 4 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 indra/newview/scripts/lua/test_snapshot.lua (limited to 'indra/newview') diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b637bcbdac..9f60f71d28 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4840,7 +4840,7 @@ BOOL LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL; LLPointer<LLImageRaw> raw = new LLImageRaw; - BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, show_hud, do_rebuild); + BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, show_hud, do_rebuild, 0, type); if (success) { diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp index da7e18af5c..cba4fbc391 100644 --- a/indra/newview/llviewerwindowlistener.cpp +++ b/indra/newview/llviewerwindowlistener.cpp @@ -43,22 +43,13 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow): mViewerWindow(llviewerwindow) { // add() every method we want to be able to invoke via this event API. - LLSD saveSnapshotArgs; - saveSnapshotArgs["filename"] = LLSD::String(); - saveSnapshotArgs["reply"] = LLSD::String(); - // The following are optional, so don't build them into required prototype. -// saveSnapshotArgs["width"] = LLSD::Integer(); -// saveSnapshotArgs["height"] = LLSD::Integer(); -// saveSnapshotArgs["showui"] = LLSD::Boolean(); -// saveSnapshotArgs["showhud"] = LLSD::Boolean(); -// saveSnapshotArgs["rebuild"] = LLSD::Boolean(); -// saveSnapshotArgs["type"] = LLSD::String(); add("saveSnapshot", - "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n" + "Save screenshot: [\"filename\"] (extension may be specified: bmp, jpeg, png)\n" + "[\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n" "type: \"COLOR\", \"DEPTH\"\n" "Post on [\"reply\"] an event containing [\"ok\"]", &LLViewerWindowListener::saveSnapshot, - saveSnapshotArgs); + llsd::map("filename", LLSD(), "reply", LLSD())); add("requestReshape", "Resize the window: [\"w\"], [\"h\"]", &LLViewerWindowListener::requestReshape); @@ -66,12 +57,15 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow): void LLViewerWindowListener::saveSnapshot(const LLSD& event) const { + Response response(LLSD(), event); + typedef std::map<LLSD::String, LLSnapshotModel::ESnapshotLayerType> TypeMap; TypeMap types; #define tp(name) types[#name] = LLSnapshotModel::SNAPSHOT_TYPE_##name tp(COLOR); tp(DEPTH); -#undef tp +#undef tp + // Our add() call should ensure that the incoming LLSD does in fact // contain our required arguments. Deal with the optional ones. S32 width (mViewerWindow->getWindowWidthRaw()); @@ -94,14 +88,36 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const TypeMap::const_iterator found = types.find(event["type"]); if (found == types.end()) { - LL_ERRS("LLViewerWindowListener") << "LLViewerWindowListener::saveSnapshot(): " - << "unrecognized type " << event["type"] << LL_ENDL; - return; + return response.error(stringize("Unrecognized type ", std::quoted(event["type"].asString()), " [\"COLOR\"] or [\"DEPTH\"] is expected.")); } type = found->second; } - bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, type); - sendReply(LLSDMap("ok", ok), event); + + std::string filename(event["filename"]); + if (filename.empty()) + { + return response.error(stringize("File path is empty.")); + } + + LLSnapshotModel::ESnapshotFormat format(LLSnapshotModel::SNAPSHOT_FORMAT_BMP); + std::string ext = gDirUtilp->getExtension(filename); + if (ext.empty()) + { + filename.append(".bmp"); + } + else if (ext == "png") + { + format = LLSnapshotModel::SNAPSHOT_FORMAT_PNG; + } + else if (ext == "jpeg" || ext == "jpg") + { + format = LLSnapshotModel::SNAPSHOT_FORMAT_JPEG; + } + else if (ext != "bmp") + { + return response.error(stringize("Unrecognized format. [\"png\"], [\"jpeg\"] or [\"bmp\"] is expected.")); + } + response["result"] = mViewerWindow->saveSnapshot(filename, width, height, showui, showhud, rebuild, type, format); } void LLViewerWindowListener::requestReshape(LLSD const & event_data) const diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index eb1a4017c7..8fcc446e09 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -122,4 +122,19 @@ function UI.type(...) end end +-- *************************************************************************** +-- Snapshot +-- *************************************************************************** +-- UI.snapshot{filename=filename -- extension may be specified: bmp, jpeg, png +-- [, type='COLOR' | 'DEPTH'] +-- [, width=width][, height=height] -- uses current window size if not specified +-- [, showui=true][, showhud=true] +-- [, rebuild=false]} +function UI.snapshot(...) + local args = mapargs('filename,width,height,showui,showhud,rebuild,type', ...) + leap.request('LLViewerWindow', {op='saveSnapshot', filename = args.filename, + width=args.width, height=args.height, + showui=args.showui, showhud=args.showhud, + rebuild=args.rebuild, type=args.type}) +end return UI diff --git a/indra/newview/scripts/lua/test_snapshot.lua b/indra/newview/scripts/lua/test_snapshot.lua new file mode 100644 index 0000000000..d7c878833b --- /dev/null +++ b/indra/newview/scripts/lua/test_snapshot.lua @@ -0,0 +1,15 @@ +local UI = require 'UI' + +PATH = 'E:\\' +-- 'png', 'jpeg' or 'bmp' +EXT = '.png' + +NAME_SIMPLE = 'Snapshot_simple' .. '_' .. os.date("%Y-%m-%d_%H-%M-%S") +UI.snapshot(PATH .. NAME_SIMPLE .. EXT) + +NAME_ARGS = 'Snapshot_args' .. '_' .. os.date("%Y-%m-%d_%H-%M-%S") + +-- 'COLOR' or 'DEPTH' +TYPE = 'COLOR' +UI.snapshot{PATH .. NAME_ARGS .. EXT, width = 700, height = 400, + type = TYPE, showui = false, showhud = false} -- cgit v1.2.3 From 6f62e8b59191ee622591c91a55d02bb6c808e85a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 8 Jul 2024 16:21:51 -0400 Subject: Quote "LLAppearance" op="wearOutfit" folder_id and folder_name args --- indra/newview/llappearancelistener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 75eaf29186..b8aca96b43 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -38,7 +38,7 @@ LLAppearanceListener::LLAppearanceListener() "API to wear a specified outfit and wear/remove individual items") { add("wearOutfit", - "Wear outfit by folder id: [folder_id] OR by folder name: [folder_name]\n" + "Wear outfit by folder id: [\"folder_id\"] OR by folder name: [\"folder_name\"]\n" "When [\"append\"] is true, outfit will be added to COF\n" "otherwise it will replace current oufit", &LLAppearanceListener::wearOutfit); -- cgit v1.2.3 From 2918ebc081f63bffd5c482375f7fcbbb2faea175 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 8 Jul 2024 16:23:29 -0400 Subject: Combine LLAppearanceMgr::wearOutfit() and wearOutfitByName() into new private wearOutfit(LLInventoryCategory*) method. --- indra/newview/llappearancemgr.cpp | 63 +++++++++++++++------------------------ indra/newview/llappearancemgr.h | 4 +++ 2 files changed, 28 insertions(+), 39 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 7a34006323..a8bc9d8e52 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2904,6 +2904,17 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append) +{ + std::string error_msg; + if(!wearOutfitByName(name, error_msg, append)) + { + LL_WARNS() << error_msg << LL_ENDL; + return false; + } + return true; +} + bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& error_msg, bool append) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2937,63 +2948,37 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& err } } - if(cat) - { - // don't allow wearing a system folder - if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(name)); - return false; - } - bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); - if (!can_wear) - { - std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); - error_msg = stringize(msg, std::quoted(name), ", id: ", cat->getUUID()); - return false; - } - LLAppearanceMgr::wearInventoryCategory(cat, copy_items, append); - } - else - { - error_msg = stringize(LLTrans::getString("OutfitNotFound"), std::quoted(name)); - return false; - } - return true; + return wearOutfit(std::quoted(name), cat, error_msg, copy_items, append); } bool LLAppearanceMgr::wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append) { LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + return wearOutfit(stringize(cat_id), cat, error_msg, false, append); +} + +bool LLAppearanceMgr::wearOutfit(const std::string &desc, LLInventoryCategory* cat, + std::string &error_msg, bool copy_items, bool append) +{ if (!cat) { - error_msg = stringize(LLTrans::getString("OutfitNotFound"), cat_id); + error_msg = stringize(LLTrans::getString("OutfitNotFound"), desc); return false; } + // don't allow wearing a system folder if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { - error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), cat_id); + error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(cat->getName())); return false; } - bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat_id) : LLAppearanceMgr::instance().getCanReplaceCOF(cat_id); + bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); if (!can_wear) { std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); - error_msg = stringize(msg, std::quoted(cat->getName()), " , id: ", cat_id); - return false; - } - LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); - return true; -} - -bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append) -{ - std::string error_msg; - if(!wearOutfitByName(name, error_msg, append)) - { - LL_WARNS() << error_msg << LL_ENDL; + error_msg = stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID()); return false; } + wearInventoryCategory(cat, copy_items, append); return true; } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index b795494f94..11d209e6b5 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -263,6 +263,10 @@ private: static void onOutfitRename(const LLSD& notification, const LLSD& response); + // used by both wearOutfit(LLUUID) and wearOutfitByName(std::string) + bool wearOutfit(const std::string &desc, LLInventoryCategory* cat, + std::string &error_msg, bool copy_items, bool append); + bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. -- cgit v1.2.3 From 0e5cee5d6ddad76ccd37b5ed6bf8d692435bb7dc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 8 Jul 2024 16:40:02 -0400 Subject: Slightly simplify LLAppearanceListener::wearItems(), detachItems(). --- indra/newview/llappearancelistener.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index b8aca96b43..c39799c5e9 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -91,36 +91,38 @@ void LLAppearanceListener::wearOutfit(LLSD const &data) void LLAppearanceListener::wearItems(LLSD const &data) { - if (data["items_id"].isArray()) + const LLSD& items_id{ data["items_id"] }; + uuid_vec_t ids; + if (! items_id.isArray()) { - uuid_vec_t ids; - for (const auto &id : llsd::inArray(data["items_id"])) + ids.push_back(items_id.asUUID()); + } + else // array + { + for (const auto &id : llsd::inArray(items_id)) { ids.push_back(id); } - LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); - } - else - { - LLAppearanceMgr::instance().wearItemOnAvatar(data["items_id"].asUUID(), true, data["replace"].asBoolean()); } + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); } void LLAppearanceListener::detachItems(LLSD const &data) { - if (data["items_id"].isArray()) + const LLSD& items_id{ data["items_id"] }; + uuid_vec_t ids; + if (! items_id.isArray()) { - uuid_vec_t ids; - for (const auto &id : llsd::inArray(data["items_id"])) + ids.push_back(items_id.asUUID()); + } + else // array + { + for (const auto &id : llsd::inArray(items_id)) { ids.push_back(id); } - LLAppearanceMgr::instance().removeItemsFromAvatar(ids); - } - else - { - LLAppearanceMgr::instance().removeItemFromAvatar(data["items_id"].asUUID()); } + LLAppearanceMgr::instance().removeItemsFromAvatar(ids); } void LLAppearanceListener::getOutfitsList(LLSD const &data) -- cgit v1.2.3 From b8c09ed80d076f44b08d6aaa59fffd98abd55811 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 8 Jul 2024 17:18:48 -0400 Subject: The I/O manipulator std::quoted() must be passed to an ostream. --- indra/newview/llappearancemgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index a8bc9d8e52..26c41b19ed 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2948,7 +2948,7 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& err } } - return wearOutfit(std::quoted(name), cat, error_msg, copy_items, append); + return wearOutfit(stringize(std::quoted(name)), cat, error_msg, copy_items, append); } bool LLAppearanceMgr::wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append) -- cgit v1.2.3 From f009f8da6b140f02f6463a43d336ab2644782fa1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 9 Jul 2024 10:24:32 -0400 Subject: Introduce LLSDParam<vector<T>> and LLSDParam<map<string, T>>. Use LLSDParam<uuid_vec_t> in LLAppearanceListener::wearItems() and detachItems() to build the vector of LLUUIDs from the passed LLSD array. --- indra/newview/llappearancelistener.cpp | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index c39799c5e9..0dab352311 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -91,38 +91,15 @@ void LLAppearanceListener::wearOutfit(LLSD const &data) void LLAppearanceListener::wearItems(LLSD const &data) { - const LLSD& items_id{ data["items_id"] }; - uuid_vec_t ids; - if (! items_id.isArray()) - { - ids.push_back(items_id.asUUID()); - } - else // array - { - for (const auto &id : llsd::inArray(items_id)) - { - ids.push_back(id); - } - } - LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); + LLAppearanceMgr::instance().wearItemsOnAvatar( + LLSDParam<uuid_vec_t>(data["items_id"]), + true, data["replace"].asBoolean()); } void LLAppearanceListener::detachItems(LLSD const &data) { - const LLSD& items_id{ data["items_id"] }; - uuid_vec_t ids; - if (! items_id.isArray()) - { - ids.push_back(items_id.asUUID()); - } - else // array - { - for (const auto &id : llsd::inArray(items_id)) - { - ids.push_back(id); - } - } - LLAppearanceMgr::instance().removeItemsFromAvatar(ids); + LLAppearanceMgr::instance().removeItemsFromAvatar( + LLSDParam<uuid_vec_t>(data["items_id"])); } void LLAppearanceListener::getOutfitsList(LLSD const &data) -- cgit v1.2.3 From 98761798b9a118c46e5482b1f36fef1260c9c5f9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 10 Jul 2024 12:03:49 +0300 Subject: Simplify passing keys to leap.request --- indra/newview/llviewerwindowlistener.cpp | 4 ++-- indra/newview/scripts/lua/require/UI.lua | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp index cba4fbc391..52f413792a 100644 --- a/indra/newview/llviewerwindowlistener.cpp +++ b/indra/newview/llviewerwindowlistener.cpp @@ -47,9 +47,9 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow): "Save screenshot: [\"filename\"] (extension may be specified: bmp, jpeg, png)\n" "[\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n" "type: \"COLOR\", \"DEPTH\"\n" - "Post on [\"reply\"] an event containing [\"ok\"]", + "Post on [\"reply\"] an event containing [\"result\"]", &LLViewerWindowListener::saveSnapshot, - llsd::map("filename", LLSD(), "reply", LLSD())); + llsd::map("filename", LLSD::String(), "reply", LLSD())); add("requestReshape", "Resize the window: [\"w\"], [\"h\"]", &LLViewerWindowListener::requestReshape); diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 8fcc446e09..1eee4657f4 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -132,9 +132,7 @@ end -- [, rebuild=false]} function UI.snapshot(...) local args = mapargs('filename,width,height,showui,showhud,rebuild,type', ...) - leap.request('LLViewerWindow', {op='saveSnapshot', filename = args.filename, - width=args.width, height=args.height, - showui=args.showui, showhud=args.showhud, - rebuild=args.rebuild, type=args.type}) + args.op = 'saveSnapshot' + return leap.request('LLViewerWindow', args).result end return UI -- cgit v1.2.3 From 8c94ff566a4f9076607d1b988f3eb7ad7e200bd9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 10 Jul 2024 15:14:13 -0400 Subject: Remove ability to reuse a LuaState between LLLUAmanager functions. Remove LLLUAmanager::mumbleScriptLine() LuaState& parameters. Make startScriptLine(), waitScriptLine() and runScriptLine() exactly parallel to startScriptFile(), waitScriptFile() and runScriptFile(). That means that runScriptLine()'s C++ coroutine instantiates and destroys its own LuaState, which means that LL.atexit() functions will run on the Lua-specific C++ coroutine rather than (say) the viewer's main coroutine. Introduce LLLUAmanager::script_result typedef for std::pair<int, LLSD> and use in method returns. Remove LuaState::initLuaState(); move its logic back into the constructor. Remove initLuaState() calls in the expr() error cases: they're moot now that we won't get subsequent expr() calls on the same LuaState instance. Remove LLFloaterLUADebug "Use clean lua_State" checkbox and the cleanLuaState() method. Remove mState member. Remove explicit LuaState declarations from LLLUAmanager tests. Adapt one test for implicit LuaState: it was directly calling LuaState::obtainListener() to discover the LuaListener's reply-pump name. But since that test also captures two leap.request() calls from the Lua script, it can just look at the "reply" key in either of those requests. --- indra/newview/llfloaterluadebug.cpp | 13 +----- indra/newview/llfloaterluadebug.h | 2 - indra/newview/llluamanager.cpp | 48 +++++++++------------- indra/newview/llluamanager.h | 20 ++++----- .../skins/default/xui/en/floater_lua_debug.xml | 9 ---- indra/newview/tests/llluamanager_test.cpp | 34 ++++++--------- 6 files changed, 43 insertions(+), 83 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index f715327ec8..9981126e4f 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -27,7 +27,6 @@ #include "llfloaterluadebug.h" -#include "llcheckboxctrl.h" #include "lllineeditor.h" #include "lltexteditor.h" #include "llviewermenufile.h" // LLFilePickerReplyThread @@ -92,8 +91,7 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); - cleanLuaState(); - LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) + LLLUAmanager::runScriptLine(cmd, [this](int count, const LLSD& result) { completion(count, result); }); @@ -174,12 +172,3 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) sep = ", "; } } - -void LLFloaterLUADebug::cleanLuaState() -{ - if(getChild<LLCheckBoxCtrl>("clean_lua_state")->get()) - { - //Reinit to clean lua_State - mState.initLuaState(); - } -} diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index ae30b7cf25..e513d9a095 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -58,14 +58,12 @@ class LLFloaterLUADebug : private: void completion(int count, const LLSD& result); - void cleanLuaState(); LLTempBoundListener mOutConnection; LLTextEditor* mResultOutput; LLLineEditor* mLineInput; LLLineEditor* mScriptPath; - LuaState mState; U32 mAck{ 0 }; bool mExecuting{ false }; }; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index ccfa08078e..7014c59e4e 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -162,24 +162,25 @@ lua_function(get_event_next, return 2; } -LLCoros::Future<std::pair<int, LLSD>> +LLCoros::Future<LLLUAmanager::script_result> LLLUAmanager::startScriptFile(const std::string& filename) { // Despite returning from startScriptFile(), we need this Promise to // remain alive until the callback has fired. - auto promise{ std::make_shared<LLCoros::Promise<std::pair<int, LLSD>>>() }; + auto promise{ std::make_shared<LLCoros::Promise<script_result>>() }; runScriptFile(filename, [promise](int count, LLSD result) { promise->set_value({ count, result }); }); return LLCoros::getFuture(*promise); } -std::pair<int, LLSD> LLLUAmanager::waitScriptFile(const std::string& filename) +LLLUAmanager::script_result LLLUAmanager::waitScriptFile(const std::string& filename) { return startScriptFile(filename).get(); } -void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb) +void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, + script_finished_fn finished_cb) { // A script_result_fn will be called when LuaState::expr() completes. LLCoros::instance().launch(filename, [filename, result_cb, finished_cb]() @@ -212,39 +213,25 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r }); } -void LLLUAmanager::runScriptLine(const std::string& chunk, script_finished_fn cb) -{ - // A script_finished_fn is used to initialize the LuaState. - // It will be called when the LuaState is destroyed. - LuaState L(cb); - runScriptLine(L, chunk); -} - -void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn cb) -{ - LuaState L; - // A script_result_fn will be called when LuaState::expr() completes. - runScriptLine(L, chunk, cb); -} - -LLCoros::Future<std::pair<int, LLSD>> -LLLUAmanager::startScriptLine(LuaState& L, const std::string& chunk) +LLCoros::Future<LLLUAmanager::script_result> +LLLUAmanager::startScriptLine(const std::string& chunk) { // Despite returning from startScriptLine(), we need this Promise to // remain alive until the callback has fired. - auto promise{ std::make_shared<LLCoros::Promise<std::pair<int, LLSD>>>() }; - runScriptLine(L, chunk, + auto promise{ std::make_shared<LLCoros::Promise<script_result>>() }; + runScriptLine(chunk, [promise](int count, LLSD result) { promise->set_value({ count, result }); }); return LLCoros::getFuture(*promise); } -std::pair<int, LLSD> LLLUAmanager::waitScriptLine(LuaState& L, const std::string& chunk) +LLLUAmanager::script_result LLLUAmanager::waitScriptLine(const std::string& chunk) { - return startScriptLine(L, chunk).get(); + return startScriptLine(chunk).get(); } -void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_result_fn cb) +void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn result_cb, + script_finished_fn finished_cb) { // find a suitable abbreviation for the chunk string std::string shortchunk{ chunk }; @@ -256,12 +243,15 @@ void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_r shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); std::string desc{ "lua: " + shortchunk }; - LLCoros::instance().launch(desc, [&L, desc, chunk, cb]() + LLCoros::instance().launch(desc, [desc, chunk, result_cb, finished_cb]() { + // A script_finished_fn is used to initialize the LuaState. + // It will be called when the LuaState is destroyed. + LuaState L(finished_cb); auto [count, result] = L.expr(desc, chunk); - if (cb) + if (result_cb) { - cb(count, result); + result_cb(count, result); } }); } diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index dcbb91f799..50f922a80f 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -55,32 +55,32 @@ public: // count > 1 with result.isArray() means the script returned multiple // results, represented as the entries of the result array. typedef std::function<void(int count, const LLSD& result)> script_result_fn; + // same semantics as script_result_fn parameters + typedef std::pair<int, LLSD> script_result; - static void runScriptFile(const std::string &filename, script_result_fn result_cb = {}, script_finished_fn finished_cb = {}); + static void runScriptFile(const std::string &filename, script_result_fn result_cb = {}, + script_finished_fn finished_cb = {}); // Start running a Lua script file, returning an LLCoros::Future whose // get() method will pause the calling coroutine until it can deliver the // (count, result) pair described above. Between startScriptFile() and // Future::get(), the caller and the Lua script coroutine will run // concurrently. - static LLCoros::Future<std::pair<int, LLSD>> - startScriptFile(const std::string& filename); + static LLCoros::Future<script_result> startScriptFile(const std::string& filename); // Run a Lua script file, and pause the calling coroutine until it completes. // The return value is the (count, result) pair described above. - static std::pair<int, LLSD> waitScriptFile(const std::string& filename); + static script_result waitScriptFile(const std::string& filename); - static void runScriptLine(const std::string &chunk, script_finished_fn cb = {}); - static void runScriptLine(const std::string &chunk, script_result_fn cb); - static void runScriptLine(LuaState& L, const std::string &chunk, script_result_fn cb = {}); + static void runScriptLine(const std::string &chunk, script_result_fn result_cb = {}, + script_finished_fn finished_cb = {}); // Start running a Lua chunk, returning an LLCoros::Future whose // get() method will pause the calling coroutine until it can deliver the // (count, result) pair described above. Between startScriptLine() and // Future::get(), the caller and the Lua script coroutine will run // concurrently. - static LLCoros::Future<std::pair<int, LLSD>> - startScriptLine(LuaState& L, const std::string& chunk); + static LLCoros::Future<script_result> startScriptLine(const std::string& chunk); // Run a Lua chunk, and pause the calling coroutine until it completes. // The return value is the (count, result) pair described above. - static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& chunk); + static script_result waitScriptLine(const std::string& chunk); static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml index 012ea6f254..15027f1647 100644 --- a/indra/newview/skins/default/xui/en/floater_lua_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -25,15 +25,6 @@ width="100"> LUA string: </text> - <check_box - follows="right|top" - height="15" - label="Use clean lua_State" - layout="topleft" - top="10" - right ="-70" - name="clean_lua_state" - width="70"/> <line_editor border_style="line" border_thickness="1" diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 824ddd445b..79ec9b9d3a 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -123,11 +123,10 @@ namespace tut void object::test<1>() { set_test_name("test Lua results"); - LuaState L; for (auto& luax : lua_expressions) { auto [count, result] = - LLLUAmanager::waitScriptLine(L, "return " + luax.expr); + LLLUAmanager::waitScriptLine("return " + luax.expr); auto desc{ stringize("waitScriptLine(", luax.desc, "): ") }; // if count < 0, report Lua error message ensure_equals(desc + result.asString(), count, 1); @@ -144,8 +143,7 @@ namespace tut "data = ", construct, "\n" "LL.post_on('testpump', data)\n" )); - LuaState L; - auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + auto [count, result] = LLLUAmanager::waitScriptLine(lua); // We woke up again ourselves because the coroutine running Lua has // finished. But our Lua chunk didn't actually return anything, so we // expect count to be 0 and result to be undefined. @@ -182,11 +180,10 @@ namespace tut "LL.post_on('testpump', data)\n" "LL.post_on('testpump', 'exit')\n" ); - LuaState L; // It's important to let the startScriptLine() coroutine run // concurrently with ours until we've had a chance to post() our // reply. - auto future = LLLUAmanager::startScriptLine(L, lua); + auto future = LLLUAmanager::startScriptLine(lua); StringVec expected{ "entry", "get_event_pumps()", @@ -217,8 +214,7 @@ namespace tut "pump, data = LL.get_event_next()\n" "return data\n" ); - LuaState L; - auto future = LLLUAmanager::startScriptLine(L, lua); + auto future = LLLUAmanager::startScriptLine(lua); // We woke up again ourselves because the coroutine running Lua has // reached the get_event_next() call, which suspends the calling C++ // coroutine (including the Lua code running on it) until we post @@ -356,8 +352,7 @@ namespace tut sendReply(data, data); })); - LuaState L; - auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + auto [count, result] = LLLUAmanager::waitScriptLine(lua); ensure_equals("Lua script didn't return item", count, 1); ensure_equals("echo failed", result, llsd::map("a", "a", "b", "b")); } @@ -371,18 +366,18 @@ namespace tut "\n" "fiber = require('fiber')\n" "leap = require('leap')\n" - "-- debug = require('printf')\n" "local function debug(...) end\n" + "-- debug = require('printf')\n" "\n" "-- negative priority ensures catchall is always last\n" - "catchall = leap.WaitFor:new(-1, 'catchall')\n" + "catchall = leap.WaitFor(-1, 'catchall')\n" "function catchall:filter(pump, data)\n" " debug('catchall:filter(%s, %s)', pump, data)\n" " return data\n" "end\n" "\n" "-- but first, catch events with 'special' key\n" - "catch_special = leap.WaitFor:new(2, 'catch_special')\n" + "catch_special = leap.WaitFor(2, 'catch_special')\n" "function catch_special:filter(pump, data)\n" " debug('catch_special:filter(%s, %s)', pump, data)\n" " return if data['special'] ~= nil then data else nil\n" @@ -429,10 +424,7 @@ namespace tut requests.append(data); })); - LuaState L; - auto future = LLLUAmanager::startScriptLine(L, lua); - auto replyname{ L.obtainListener().getReplyName() }; - auto& replypump{ LLEventPumps::instance().obtain(replyname) }; + auto future = LLLUAmanager::startScriptLine(lua); // LuaState::expr() periodically interrupts a running chunk to ensure // the rest of our coroutines get cycles. Nonetheless, for this test // we have to wait until both requester() coroutines have posted and @@ -444,6 +436,8 @@ namespace tut llcoro::suspend(); } ensure_equals("didn't get both requests", requests.size(), 2); + auto replyname{ requests[0]["reply"].asString() }; + auto& replypump{ LLEventPumps::instance().obtain(replyname) }; // moreover, we expect they arrived in the order they were created ensure_equals("a wasn't first", requests[0]["name"].asString(), "a"); ensure_equals("b wasn't second", requests[1]["name"].asString(), "b"); @@ -468,8 +462,7 @@ namespace tut "\n" "LL.get_event_next()\n" ); - LuaState L; - auto future = LLLUAmanager::startScriptLine(L, lua); + auto future = LLLUAmanager::startScriptLine(lua); // Poke LLTestApp to send its preliminary shutdown message. mApp.setQuitting(); // but now we have to give the startScriptLine() coroutine a chance to run @@ -491,8 +484,7 @@ namespace tut " x = 1\n" "end\n" ); - LuaState L; - auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + auto [count, result] = LLLUAmanager::waitScriptLine(lua); // We expect the above erroneous script has been forcibly terminated // because it ran too long without doing any actual work. ensure_equals(desc + " count: " + result.asString(), count, -1); -- cgit v1.2.3 From e84e65e88f9953fbc7f88408c9c2821f97f4dee6 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 12 Jul 2024 15:23:57 +0300 Subject: Show description and actual value of LLSD type setting --- indra/newview/llfloatersettingsdebug.cpp | 14 ++++++++++++++ indra/newview/llfloatersettingsdebug.h | 1 + .../skins/default/xui/en/floater_settings_debug.xml | 13 ++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 1c10db4e0d..a494b715a2 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -35,6 +35,7 @@ #include "llviewercontrol.h" #include "lltexteditor.h" #include "llclipboard.h" +#include "llsdutil.h" LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) @@ -54,6 +55,7 @@ BOOL LLFloaterSettingsDebug::postBuild() mComment = getChild<LLTextEditor>("comment_text"); mSettingName = getChild<LLTextBox>("setting_name_txt"); + mLLSDVal = getChild<LLTextEditor>("llsd_text"); mCopyBtn = getChild<LLButton>("copy_btn"); getChild<LLFilterEditor>("filter_input")->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::setSearchFilter, this, _2)); @@ -472,6 +474,17 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) color_swatch->setValue(sd); break; } + case TYPE_LLSD: + { + mLLSDVal->setVisible(true); + std::string new_text = ll_pretty_print_sd(sd); + // Don't setText if not nessesary, it will reset scroll + if (mLLSDVal->getText() != new_text) + { + mLLSDVal->setText(new_text); + } + break; + } default: mComment->setText(std::string("unknown")); break; @@ -638,6 +651,7 @@ void LLFloaterSettingsDebug::hideUIControls() getChildView("val_text")->setVisible(false); getChildView("default_btn")->setVisible(false); getChildView("boolean_combo")->setVisible(false); + mLLSDVal->setVisible(false); mSettingName->setVisible(false); mCopyBtn->setVisible(false); mComment->setVisible(false); diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index e52d5ac863..20aa9bb159 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -69,6 +69,7 @@ private: protected: class LLTextEditor* mComment; + LLTextEditor* mLLSDVal; LLTextBox* mSettingName; LLButton* mCopyBtn; diff --git a/indra/newview/skins/default/xui/en/floater_settings_debug.xml b/indra/newview/skins/default/xui/en/floater_settings_debug.xml index 6fd8f2b255..0b8190df7e 100644 --- a/indra/newview/skins/default/xui/en/floater_settings_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_settings_debug.xml @@ -69,7 +69,7 @@ visible="false" use_ellipses="true" text_color="White" - width="240"> + width="225"> Debug setting name </text> <text_editor @@ -212,4 +212,15 @@ name="hide_default" width="330"> </check_box> + <text_editor + read_only="true" + visible="false" + height="115" + layout="topleft" + name="llsd_text" + follows="left|top" + width="240" + left="320" + top="180" + word_wrap="true" /> </floater> -- cgit v1.2.3 From c9a8de49df04c55b94eee0fe5fb1eb628701cdcb Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 12 Jul 2024 15:38:19 +0300 Subject: fix for 'Run' button --- indra/newview/llfloaterluadebug.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 9981126e4f..ef24481464 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -104,12 +104,6 @@ void LLFloaterLUADebug::onBtnBrowse() void LLFloaterLUADebug::onBtnRun() { - if (mExecuting) - { - LL_DEBUGS("Lua") << "recursive call to onBtnRun()" << LL_ENDL; - return; - } - TempSet executing(mExecuting, true); std::vector<std::string> filenames; std::string filepath = mScriptPath->getText(); if (!filepath.empty()) -- cgit v1.2.3 From 50d60c2518710e92cff05b806624b11ac714369f Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Wed, 17 Jul 2024 16:46:00 +0300 Subject: Lua api for adding new menu items to the Top menu --- indra/newview/lluilistener.cpp | 104 ++++++++++++++++++++++++++++ indra/newview/lluilistener.h | 9 ++- indra/newview/scripts/lua/require/UI.lua | 28 ++++++++ indra/newview/scripts/lua/test_top_menu.lua | 34 +++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 indra/newview/scripts/lua/test_top_menu.lua (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 4afd7f1766..c73c93859a 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -34,10 +34,13 @@ // std headers // external library headers // other Linden headers +#include "llmenugl.h" #include "llui.h" // getRootView(), resolvePath() #include "lluictrl.h" #include "llerror.h" +extern LLMenuBarGL* gMenuBarView; + #define THROTTLE_PERIOD 1.5 // required seconds between throttled functions #define MIN_THROTTLE 0.5 @@ -57,6 +60,31 @@ LLUIListener::LLUIListener(): "current value as [\"value\"] reply.", &LLUIListener::getValue, llsd::map("path", LLSD(), "reply", LLSD())); + + LLSD required_args = llsd::map("name", LLSD(), "label", LLSD(), "reply", LLSD()); + add("addMenu", + "Add new drop-down menu [\"name\"] with displayed [\"label\"] to the Top menu.", + &LLUIListener::addMenu, + required_args); + + required_args.insert("parent_menu", LLSD()); + add("addMenuBranch", + "Add new menu branch [\"name\"] with displayed [\"label\"]\n" + "to the [\"parent_menu\"] within the Top menu.", + &LLUIListener::addMenuBranch, + required_args); + + add("addMenuItem", + "Add new menu item [\"name\"] with displayed [\"label\"]\n" + "and call-on-click UI function [\"func\"] with optional [\"param\"]\n" + "to the [\"parent_menu\"] within the Top menu.", + &LLUIListener::addMenuItem, + required_args.with("func", LLSD())); + + add("addMenuSeparator", + "Add menu separator to the [\"parent_menu\"] within the Top menu.", + &LLUIListener::addMenuSeparator, + llsd::map("parent_menu", LLSD(), "reply", LLSD())); } typedef LLUICtrl::CommitCallbackInfo cb_info; @@ -120,3 +148,79 @@ void LLUIListener::getValue(const LLSD&event) const response.error(stringize("UI control ", std::quoted(event["path"].asString()), " was not found")); } } + +LLMenuGL::Params get_params(const LLSD&event) +{ + LLMenuGL::Params item_params; + item_params.name = event["name"]; + item_params.label = event["label"]; + item_params.can_tear_off = true; + return item_params; +} + +LLMenuGL* get_parent_menu(LLEventAPI::Response& response, const LLSD&event) +{ + LLMenuGL* parent_menu = gMenuBarView->findChildMenuByName(event["parent_menu"], true); + if(!parent_menu) + { + response.error(stringize("Parent menu ", std::quoted(event["parent_menu"].asString()), " was not found")); + } + return parent_menu; +} + +void LLUIListener::addMenu(const LLSD&event) const +{ + Response response(LLSD(), event); + LLMenuGL::Params item_params = get_params(event); + if(!gMenuBarView->appendMenu(LLUICtrlFactory::create<LLMenuGL>(item_params))) + { + response.error(stringize("Menu ", std::quoted(event["name"].asString()), " was not added")); + } +} + +void LLUIListener::addMenuBranch(const LLSD&event) const +{ + Response response(LLSD(), event); + if(LLMenuGL* parent_menu = get_parent_menu(response, event)) + { + LLMenuGL::Params item_params = get_params(event); + if(!parent_menu->appendMenu(LLUICtrlFactory::create<LLMenuGL>(item_params))) + { + response.error(stringize("Menu branch ", std::quoted(event["name"].asString()), " was not added")); + } + } +} + +void LLUIListener::addMenuItem(const LLSD&event) const +{ + Response response(LLSD(), event); + LLMenuItemCallGL::Params item_params; + item_params.name = event["name"]; + item_params.label = event["label"]; + LLUICtrl::CommitCallbackParam item_func; + item_func.function_name = event["func"]; + if (event.has("param")) + { + item_func.parameter = event["param"]; + } + item_params.on_click = item_func; + if(LLMenuGL* parent_menu = get_parent_menu(response, event)) + { + if(!parent_menu->append(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params))) + { + response.error(stringize("Menu item ", std::quoted(event["name"].asString()), " was not added")); + } + } +} + +void LLUIListener::addMenuSeparator(const LLSD&event) const +{ + Response response(LLSD(), event); + if(LLMenuGL* parent_menu = get_parent_menu(response, event)) + { + if(!parent_menu->addSeparator()) + { + response.error("Separator was not added"); + } + } +} diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index 0df2afb3fe..cbb5014300 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -39,12 +39,15 @@ class LLUIListener: public LLEventAPI public: LLUIListener(); -// FIXME These fields are intended to be private, changed here to support very hacky code in llluamanager.cpp -public: +private: void call(const LLSD& event); void getValue(const LLSD&event) const; - private: + void addMenu(const LLSD&event) const; + void addMenuBranch(const LLSD&event) const; + void addMenuItem(const LLSD&event) const; + void addMenuSeparator(const LLSD&event) const; + F64 mLastUntrustedThrottle {0}; F64 mLastMinThrottle {0}; }; diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 1eee4657f4..28488ff3e1 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -135,4 +135,32 @@ function UI.snapshot(...) args.op = 'saveSnapshot' return leap.request('LLViewerWindow', args).result end + +-- *************************************************************************** +-- Top menu +-- *************************************************************************** + +function UI.addMenu(...) + local args = mapargs('name,label', ...) + args.op = 'addMenu' + return leap.request('UI', args) +end + +function UI.addMenuBranch(...) + local args = mapargs('name,label,parent_menu', ...) + args.op = 'addMenuBranch' + return leap.request('UI', args) +end + +function UI.addMenuItem(...) + local args = mapargs('name,label,parent_menu,func,param', ...) + args.op = 'addMenuItem' + return leap.request('UI', args) +end + +function UI.addMenuSeparator(...) + local args = mapargs('parent_menu', ...) + args.op = 'addMenuSeparator' + return leap.request('UI', args) +end return UI diff --git a/indra/newview/scripts/lua/test_top_menu.lua b/indra/newview/scripts/lua/test_top_menu.lua new file mode 100644 index 0000000000..780a384c92 --- /dev/null +++ b/indra/newview/scripts/lua/test_top_menu.lua @@ -0,0 +1,34 @@ +UI = require 'UI' + +--Add new drop-down 'LUA Menu' to the Top menu. +local MENU_NAME = "lua_menu" +UI.addMenu{name=MENU_NAME,label="LUA Menu"} + +--Add two new menu items to the 'LUA Menu': 'Debug console' and 'Scripts' +UI.addMenuItem{name="lua_debug",label="Debug console", + param="lua_debug", + func="Floater.ToggleOrBringToFront", + parent_menu=MENU_NAME} + +UI.addMenuItem{name="lua_scripts",label="Scripts", + param="lua_scripts", + func="Floater.ToggleOrBringToFront", + parent_menu=MENU_NAME} + +--Add menu separator to the 'LUA Menu' under added menu items +UI.addMenuSeparator{parent_menu=MENU_NAME} + +--Add two new menu branch 'About...' to the 'LUA Menu' +local BRANCH_NAME = "about_branch" +UI.addMenuBranch{name="about_branch",label="About...",parent_menu=MENU_NAME} + +--Add two new menu items to the 'About...' branch +UI.addMenuItem{name="lua_info",label="Lua...", + param="https://www.lua.org/about.html", + func="Advanced.ShowURL", + parent_menu=BRANCH_NAME} + +UI.addMenuItem{name="lua_info",label="Luau...", + param="https://luau-lang.org/", + func="Advanced.ShowURL", + parent_menu=BRANCH_NAME} -- cgit v1.2.3 From 1745701280d8a18f51ef09aacba4f76a4c543681 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Thu, 18 Jul 2024 08:01:24 +0300 Subject: Remove trailing whitespaces to make pre-commit happy --- .../app_settings/shaders/class2/deferred/reflectionProbeF.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl index 35848ff4cd..4fb24ca0b1 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl @@ -37,7 +37,7 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear) { ambenv = vec3(reflection_probe_ambiance * 0.25); - + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); vec3 env_vec = env_mat * refnormpersp; glossenv = srgb_to_linear(texture(environmentMap, env_vec).rgb); @@ -59,7 +59,7 @@ void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 l vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear) { ambenv = vec3(reflection_probe_ambiance * 0.25); - + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); vec3 env_vec = env_mat * refnormpersp; @@ -70,7 +70,7 @@ void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 l void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm) { - + } void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity) -- cgit v1.2.3 From 35ee96709ef2704a2636a11c67d61190dd6bdd50 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 18 Jul 2024 12:55:38 -0400 Subject: Make `LLEventPump::listen()` also accept new `LLAwareListener`. `listen()` still takes `LLEventListener`, a `callable(const LLSD&)`, but now also accepts `LLAwareListener`, a `callable(const LLBoundListener&, const LLSD&)`. This uses `boost::signals2::signal::connect_extended()`, which, when the signal is called, passes to a connected listener the `LLBoundListener` (aka `boost::signals2::connection`) representing its own connection. This allows a listener to disconnect itself when done. Internally, `listen_impl()` now always uses `connect_extended()`. When passed a classic `LLEventListener`, `listen()` wraps it in a lambda that ignores the passed `LLBoundListener`. `listen()` also now accepts `LLVoidListener`, and internally wraps it in a lambda that returns `false` on its behalf. --- indra/newview/tests/llluamanager_test.cpp | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 26a4ac95e3..3209d93d39 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -42,17 +42,6 @@ public: LLControlGroup gSavedSettings("Global"); -template <typename CALLABLE> -auto listener(CALLABLE&& callable) -{ - return [callable=std::forward<CALLABLE>(callable)] - (const LLSD& data) - { - callable(data); - return false; - }; -} - /***************************************************************************** * TUT *****************************************************************************/ @@ -138,7 +127,7 @@ namespace tut { LLSD fromlua; LLStreamListener pump("testpump", - listener([&fromlua](const LLSD& data){ fromlua = data; })); + [&fromlua](const LLSD& data){ fromlua = data; }); const std::string lua(stringize( "data = ", construct, "\n" "LL.post_on('testpump', data)\n" @@ -167,8 +156,8 @@ namespace tut set_test_name("test post_on(), get_event_pumps(), get_event_next()"); StringVec posts; LLStreamListener pump("testpump", - listener([&posts](const LLSD& data) - { posts.push_back(data.asString()); })); + [&posts](const LLSD& data) + { posts.push_back(data.asString()); }); const std::string lua( "-- test post_on,get_event_pumps,get_event_next\n" "LL.post_on('testpump', 'entry')\n" @@ -346,11 +335,11 @@ namespace tut LLStreamListener pump( "echo", - listener([](const LLSD& data) + [](const LLSD& data) { LL_DEBUGS("Lua") << "echo pump got: " << data << LL_ENDL; sendReply(data, data); - })); + }); auto [count, result] = LLLUAmanager::waitScriptLine(lua); ensure_equals("Lua script didn't return item", count, 1); @@ -424,11 +413,11 @@ namespace tut LLSD requests; LLStreamListener pump( "testpump", - listener([&requests](const LLSD& data) + [&requests](const LLSD& data) { LL_DEBUGS("Lua") << "testpump got: " << data << LL_ENDL; requests.append(data); - })); + }); auto future = LLLUAmanager::startScriptLine(lua); // LuaState::expr() periodically interrupts a running chunk to ensure -- cgit v1.2.3 From f2f0fa7fd0efc221f1358dd4e440b5d51a5fb8b4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 18 Jul 2024 13:29:34 -0400 Subject: Ditch `LLEventTrackable` aka `boost::signals2::trackable`. Remove documented `LLEventPump` support for `LLEventTrackable`. That claimed support was always a little bit magical/fragile. IF: * a class included `LLEventTrackable` as a base class AND * an instance of that class was managed by `boost::shared_ptr` AND * you passed one of that class's methods and the `boost::shared_ptr` specifically to `boost::bind()` AND * the resulting `boost::bind()` object was passed into `LLEventPump::listen()` THEN the promise was that on destruction of that object, that listener would automatically be disconnected -- instead of leaving a dangling pointer bound into the `LLEventPump`, causing a crash on the next `LLEventPump::post()` call. The only existing code in the viewer code base that exercised `LLEventTrackable` functionality was in test programs. When the viewer calls `LLEventPump::listen()`, it typically stores the resulting connection object in an `LLTempBoundListener` variable, which guarantees disconnection on destruction of that variable. The fact that `LLEventTrackable` support is specific to `boost::bind()`, that it silently fails to keep its promise with `std::bind()` or a lambda or any other form of C++ callable, makes it untrustworthy for new code. Note that the code base still uses `boost::signals2::trackable` for other `boost::signals2::signal` instances not associated with `LLEventPump`. We are not changing those at this time. --- indra/newview/llspeakers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 234de42953..d3304dba59 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -37,7 +37,7 @@ class LLSpeakerMgr; class LLAvatarName; // data for a given participant in a voice channel -class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable +class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker> { public: typedef enum e_speaker_type -- cgit v1.2.3 From decc2d3aa5ba8dc583dae5396a5ae8ca738412dd Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 25 Jul 2024 18:15:24 +0300 Subject: Lua api for Follow Camera control --- indra/newview/llagentlistener.cpp | 74 +++++-- indra/newview/llagentlistener.h | 5 +- .../scripts/lua/luafloater_camera_control.xml | 244 +++++++++++++++++++++ indra/newview/scripts/lua/require/LLAgent.lua | 28 +++ indra/newview/scripts/lua/test_camera_control.lua | 52 +++++ 5 files changed, 379 insertions(+), 24 deletions(-) create mode 100644 indra/newview/scripts/lua/luafloater_camera_control.xml create mode 100644 indra/newview/scripts/lua/require/LLAgent.lua create mode 100644 indra/newview/scripts/lua/test_camera_control.lua (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 54998f3945..38a9d58c1f 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -31,6 +31,7 @@ #include "llagentlistener.h" #include "llagent.h" +#include "llagentcamera.h" #include "llvoavatar.h" #include "llcommandhandler.h" #include "llslurl.h" @@ -69,13 +70,6 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("resetAxes", "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])", &LLAgentListener::resetAxes); - add("getAxes", - "Obsolete - use getPosition instead\n" - "Send information about the agent's orientation on [\"reply\"]:\n" - "[\"euler\"]: map of {roll, pitch, yaw}\n" - "[\"quat\"]: array of [x, y, z, w] quaternion values", - &LLAgentListener::getAxes, - LLSDMap("reply", LLSD())); add("getPosition", "Send information about the agent's position and orientation on [\"reply\"]:\n" "[\"region\"]: array of region {x, y, z} position\n" @@ -138,6 +132,21 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"contrib\"]: user's land contribution to this group\n", &LLAgentListener::getGroups, LLSDMap("reply", LLSD())); + add("setCameraParams", + "Set Follow camera params, and then activate it:\n" + "[\"camera_pos\"]: vector3\n" + "[\"focus_pos\"]: vector3\n" + "[\"focus_offset\"]: vector3\n" + "[\"camera_locked\"]: boolean\n" + "[\"focus_locked\"]: boolean", + &LLAgentListener::setFollowCamParams); + add("setFollowCamActive", + "Set Follow camera active or deactivate it using boolean [\"active\"]", + &LLAgentListener::setFollowCamActive, + llsd::map("active", LLSD())); + add("removeCameraParams", + "Reset Follow camera params", + &LLAgentListener::removeFollowCamParams); } void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -296,22 +305,6 @@ void LLAgentListener::resetAxes(const LLSD& event_data) const } } -void LLAgentListener::getAxes(const LLSD& event_data) const -{ - LLQuaternion quat(mAgent.getQuat()); - F32 roll, pitch, yaw; - quat.getEulerAngles(&roll, &pitch, &yaw); - // The official query API for LLQuaternion's [x, y, z, w] values is its - // public member mQ... - LLSD reply = LLSD::emptyMap(); - reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ)); - reply["euler"] = LLSD::emptyMap(); - reply["euler"]["roll"] = roll; - reply["euler"]["pitch"] = pitch; - reply["euler"]["yaw"] = yaw; - sendReply(reply, event_data); -} - void LLAgentListener::getPosition(const LLSD& event_data) const { F32 roll, pitch, yaw; @@ -519,3 +512,38 @@ void LLAgentListener::getGroups(const LLSD& event) const } sendReply(LLSDMap("groups", reply), event); } + +void LLAgentListener::setFollowCamParams(const LLSD& event) const +{ + if (event.has("camera_pos")) + { + LLFollowCamMgr::getInstance()->setPosition(gAgentID, LLVector3(event["camera_pos"])); + } + if (event.has("focus_pos")) + { + LLFollowCamMgr::getInstance()->setFocus(gAgentID, LLVector3(event["focus_pos"])); + } + if (event.has("focus_offset")) + { + LLFollowCamMgr::getInstance()->setFocusOffset(gAgentID, LLVector3(event["focus_offset"])); + } + if (event.has("camera_locked")) + { + LLFollowCamMgr::getInstance()->setPositionLocked(gAgentID, event["camera_locked"]); + } + if (event.has("focus_locked")) + { + LLFollowCamMgr::getInstance()->setFocusLocked(gAgentID, event["focus_locked"]); + } + LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, true); +} + +void LLAgentListener::setFollowCamActive(LLSD const & event) const +{ + LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, event["active"]); +} + +void LLAgentListener::removeFollowCamParams(LLSD const & event) const +{ + LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID); +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index c544d089ce..2a24de3f52 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -48,7 +48,6 @@ private: void requestStand(LLSD const & event_data) const; void requestTouch(LLSD const & event_data) const; void resetAxes(const LLSD& event_data) const; - void getAxes(const LLSD& event_data) const; void getGroups(const LLSD& event) const; void getPosition(const LLSD& event_data) const; void startAutoPilot(const LLSD& event_data); @@ -58,6 +57,10 @@ private: void stopAutoPilot(const LLSD& event_data) const; void lookAt(LLSD const & event_data) const; + void setFollowCamParams(LLSD const & event_data) const; + void setFollowCamActive(LLSD const & event_data) const; + void removeFollowCamParams(LLSD const & event_data) const; + LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; private: diff --git a/indra/newview/scripts/lua/luafloater_camera_control.xml b/indra/newview/scripts/lua/luafloater_camera_control.xml new file mode 100644 index 0000000000..0601a363e5 --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_camera_control.xml @@ -0,0 +1,244 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="350" + layout="topleft" + name="camera_demo" + title="Follow camera control" + width="360"> + <text + type="string" + follows="left|top" + height="10" + width="100" + layout="topleft" + top="30" + left="10" + name="camera_lbl"> + Camera position: + </text> + <text + type="string" + follows="left|top" + height="10" + width="10" + layout="topleft" + top_pad="12" + left="10" + value="X" + name="cam_x_lbl"/> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="cam_x" + top_delta="-2" + left_pad="5" + width="65" /> + <button + follows="left|bottom" + height="20" + image_overlay="Icon_Copy" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + layout="topleft" + tool_tip="Use Agent position" + name="agent_cam_btn" + left_pad="10" + width="20" > + </button> + <text + type="string" + follows="left|top" + height="10" + width="10" + layout="topleft" + top_pad="7" + left="10" + value="Y" + name="cam_y_lbl"/> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="cam_y" + top_delta="-2" + left_pad="5" + width="65" /> + <text + type="string" + follows="left|top" + height="10" + width="10" + layout="topleft" + top_pad="7" + left="10" + value="Z" + name="cam_z_lbl"/> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="cam_z" + top_delta="-2" + left_pad="5" + width="65" /> + <text + type="string" + follows="left|top" + height="10" + width="100" + layout="topleft" + top="30" + left="145" + name="focus_lbl"> + Focus position: + </text> + <text + type="string" + follows="left|top" + height="10" + width="10" + layout="topleft" + top_pad="12" + left="145" + value="X" + name="cam_x_lbl"/> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="focus_x" + top_delta="-2" + left_pad="5" + width="60" /> + <button + follows="left|bottom" + height="20" + image_overlay="Icon_Copy" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + layout="topleft" + tool_tip="Use Agent position" + name="agent_focus_btn" + left_pad="10" + width="20" > + </button> + <text + type="string" + follows="left|top" + height="10" + width="10" + layout="topleft" + top_pad="7" + left="145" + value="Y" + name="cam_y_lbl"/> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="focus_y" + top_delta="-2" + left_pad="5" + width="60" /> + <text + type="string" + follows="left|top" + height="10" + width="10" + layout="topleft" + top_pad="7" + left="145" + value="Z" + name="cam_z_lbl"/> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + font="SansSerif" + height="20" + layout="topleft" + max_length_bytes="50" + name="focus_z" + top_delta="-2" + left_pad="5" + width="60" /> + <text + type="string" + follows="left|top" + height="10" + width="100" + layout="topleft" + top="30" + left="270" + name="focus_lbl"> + Lock: + </text> + <check_box + width="80" + height="21" + layout="topleft" + follows="top|left" + top_pad="12" + label="Camera" + name="lock_camera_ctrl"/> + <check_box + width="80" + height="21" + layout="topleft" + follows="top|left" + top_pad="2" + label="Focus" + name="lock_focus_ctrl"/> + <button + follows="left|bottom" + height="25" + label="Update params" + layout="topleft" + name="update_btn" + left="10" + top="140" + width="120" > + </button> + <button + follows="left|bottom" + height="25" + label="Reset" + layout="topleft" + name="reset_btn" + left_pad="15" + width="90" > + </button> + <text_editor + follows="top|left" + font="SansSerif" + height="160" + left="5" + enabled="false" + name="events_editor" + top_pad="15" + word_wrap="true" + max_length="65536" + width="350"/> +</floater> diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua new file mode 100644 index 0000000000..7c6a842555 --- /dev/null +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -0,0 +1,28 @@ +local leap = require 'leap' +local mapargs = require 'mapargs' + +local LLAgent = {} + +function LLAgent.getRegionPosition() + return leap.request('LLAgent', {op = 'getPosition'}).region +end + +function LLAgent.getGlobalPosition() + return leap.request('LLAgent', {op = 'getPosition'}).global +end + +function LLAgent.setCamera(...) + local args = mapargs('camera_pos,focus_pos,focus_offset,camera_locked,focus_locked', ...) + args.op = 'setCameraParams' + leap.send('LLAgent', args) +end + +function LLAgent.setFollowCamActive(active) + leap.send('LLAgent', {op = 'setFollowCamActive', active = active}) +end + +function LLAgent.removeCamParams() + leap.send('LLAgent', {op = 'removeCameraParams'}) +end + +return LLAgent diff --git a/indra/newview/scripts/lua/test_camera_control.lua b/indra/newview/scripts/lua/test_camera_control.lua new file mode 100644 index 0000000000..db76201932 --- /dev/null +++ b/indra/newview/scripts/lua/test_camera_control.lua @@ -0,0 +1,52 @@ +local Floater = require 'Floater' +local LLAgent = require 'LLAgent' +local leap = require 'leap' +local startup = require 'startup' +local inspect = require 'inspect' + +local flt = Floater('luafloater_camera_control.xml') + +function getValue(ctrl_name) + return flt:request({action="get_value", ctrl_name=ctrl_name}).value +end + +function setValue(ctrl_name, value) + flt:post({action="set_value", ctrl_name=ctrl_name, value=value}) +end + +function flt:commit_update_btn(event_data) + lock_focus = getValue('lock_focus_ctrl') + lock_camera = self:request({action="get_value", ctrl_name='lock_camera_ctrl'}).value + + local camera_pos = {getValue('cam_x'),getValue('cam_y'),getValue('cam_z')} + local focus_pos = {getValue('focus_x'),getValue('focus_y'),getValue('focus_z')} + + + LLAgent.setCamera{camera_pos=camera_pos,focus_pos=focus_pos, + focus_locked = lock_focus,camera_locked = lock_camera} + + self:post({action="add_text", ctrl_name="events_editor", + value = {'Updating FollowCam params', 'camera_pos:', camera_pos, 'focus_pos:', focus_pos, 'lock_focus:', lock_focus, 'lock_camera:', lock_camera}}) +end + +function flt:commit_agent_cam_btn(event_data) + agent_pos = LLAgent.getRegionPosition() + setValue('cam_x', math.floor(agent_pos[1])) + setValue('cam_y', math.floor(agent_pos[2])) + setValue('cam_z', math.floor(agent_pos[3])) +end + +function flt:commit_agent_focus_btn(event_data) + agent_pos = LLAgent.getRegionPosition() + setValue('focus_x', math.floor(agent_pos[1])) + setValue('focus_y', math.floor(agent_pos[2])) + setValue('focus_z', math.floor(agent_pos[3])) +end + +function flt:commit_reset_btn(event_data) + LLAgent.removeCamParams() + LLAgent.setFollowCamActive(false) +end + +startup.wait('STATE_LOGIN_WAIT') +flt:show() -- cgit v1.2.3 From 4edcebdb31b7d49faf94b60a66c9921e90e23899 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 25 Jul 2024 18:29:06 +0300 Subject: Script clean up --- indra/newview/scripts/lua/test_camera_control.lua | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_camera_control.lua b/indra/newview/scripts/lua/test_camera_control.lua index db76201932..e7ad69b473 100644 --- a/indra/newview/scripts/lua/test_camera_control.lua +++ b/indra/newview/scripts/lua/test_camera_control.lua @@ -1,8 +1,6 @@ local Floater = require 'Floater' local LLAgent = require 'LLAgent' -local leap = require 'leap' local startup = require 'startup' -local inspect = require 'inspect' local flt = Floater('luafloater_camera_control.xml') @@ -16,17 +14,16 @@ end function flt:commit_update_btn(event_data) lock_focus = getValue('lock_focus_ctrl') - lock_camera = self:request({action="get_value", ctrl_name='lock_camera_ctrl'}).value + lock_camera = getValue('lock_camera_ctrl') + local camera_pos = {getValue('cam_x'), getValue('cam_y'), getValue('cam_z')} + local focus_pos = {getValue('focus_x'), getValue('focus_y'), getValue('focus_z')} - local camera_pos = {getValue('cam_x'),getValue('cam_y'),getValue('cam_z')} - local focus_pos = {getValue('focus_x'),getValue('focus_y'),getValue('focus_z')} - - - LLAgent.setCamera{camera_pos=camera_pos,focus_pos=focus_pos, - focus_locked = lock_focus,camera_locked = lock_camera} + LLAgent.setCamera{camera_pos=camera_pos, focus_pos=focus_pos, + focus_locked=lock_focus, camera_locked=lock_camera} self:post({action="add_text", ctrl_name="events_editor", - value = {'Updating FollowCam params', 'camera_pos:', camera_pos, 'focus_pos:', focus_pos, 'lock_focus:', lock_focus, 'lock_camera:', lock_camera}}) + value = {'Updating FollowCam params', 'camera_pos:', camera_pos, 'focus_pos:', focus_pos, + 'lock_focus:', lock_focus, 'lock_camera:', lock_camera}}) end function flt:commit_agent_cam_btn(event_data) -- cgit v1.2.3 From 41ea8a61c247d915ebe53436e9cfc999a712b692 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 26 Jul 2024 15:55:17 +0300 Subject: Add api for more script camera params --- indra/newview/llagentlistener.cpp | 54 ++++++++++++++++++++++++--- indra/newview/scripts/lua/require/LLAgent.lua | 19 +++++++++- 2 files changed, 66 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 38a9d58c1f..045367dbdd 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -132,16 +132,25 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"contrib\"]: user's land contribution to this group\n", &LLAgentListener::getGroups, LLSDMap("reply", LLSD())); + //camera params are similar to LSL, see https://wiki.secondlife.com/wiki/LlSetCameraParams add("setCameraParams", "Set Follow camera params, and then activate it:\n" - "[\"camera_pos\"]: vector3\n" - "[\"focus_pos\"]: vector3\n" - "[\"focus_offset\"]: vector3\n" - "[\"camera_locked\"]: boolean\n" - "[\"focus_locked\"]: boolean", + "[\"camera_pos\"]: vector3, camera position in region coordinates\n" + "[\"focus_pos\"]: vector3, what the camera is aimed at (in region coordinates)\n" + "[\"focus_offset\"]: vector3, adjusts the camera focus position relative to the target, default is (1, 0, 0)\n" + "[\"distance\"]: float (meters), distance the camera wants to be from its target, default is 3\n" + "[\"focus_threshold\"]: float (meters), sets the radius of a sphere around the camera's target position within which its focus is not affected by target motion, default is 1\n" + "[\"camera_threshold\"]: float (meters), sets the radius of a sphere around the camera's ideal position within which it is not affected by target motion, default is 1\n" + "[\"focus_lag\"]: float (seconds), how much the camera lags as it tries to aim towards the target, default is 0.1\n" + "[\"camera_lag\"]: float (seconds), how much the camera lags as it tries to move towards its 'ideal' position, default is 0.1\n" + "[\"camera_pitch\"]: float (degrees), adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance, default is 0\n" + "[\"behindness_angle\"]: float (degrees), sets the angle in degrees within which the camera is not constrained by changes in target rotation, default is 10\n" + "[\"behindness_lag\"]: float (seconds), sets how strongly the camera is forced to stay behind the target if outside of behindness angle, default is 0\n" + "[\"camera_locked\"]: bool, locks the camera position so it will not move\n" + "[\"focus_locked\"]: bool, locks the camera focus so it will not move", &LLAgentListener::setFollowCamParams); add("setFollowCamActive", - "Set Follow camera active or deactivate it using boolean [\"active\"]", + "Turns on or off scripted control of the camera using boolean [\"active\"]", &LLAgentListener::setFollowCamActive, llsd::map("active", LLSD())); add("removeCameraParams", @@ -535,6 +544,39 @@ void LLAgentListener::setFollowCamParams(const LLSD& event) const { LLFollowCamMgr::getInstance()->setFocusLocked(gAgentID, event["focus_locked"]); } + if (event.has("distance")) + { + LLFollowCamMgr::getInstance()->setDistance(gAgentID, event["distance"].asReal()); + } + if (event.has("focus_threshold")) + { + LLFollowCamMgr::getInstance()->setFocusThreshold(gAgentID, event["focus_threshold"].asReal()); + } + if (event.has("camera_threshold")) + { + LLFollowCamMgr::getInstance()->setPositionThreshold(gAgentID, event["camera_threshold"].asReal()); + } + if (event.has("focus_lag")) + { + LLFollowCamMgr::getInstance()->setFocusLag(gAgentID, event["focus_lag"].asReal()); + } + if (event.has("camera_lag")) + { + LLFollowCamMgr::getInstance()->setPositionLag(gAgentID, event["camera_lag"].asReal()); + } + if (event.has("camera_pitch")) + { + LLFollowCamMgr::getInstance()->setPitch(gAgentID, event["camera_pitch"].asReal()); + } + if (event.has("behindness_lag")) + { + LLFollowCamMgr::getInstance()->setBehindnessLag(gAgentID, event["behindness_lag"].asReal()); + } + if (event.has("behindness_angle")) + { + LLFollowCamMgr::getInstance()->setBehindnessAngle(gAgentID, event["behindness_angle"].asReal()); + } + LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, true); } diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 7c6a842555..bc9a6b23a0 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -11,8 +11,25 @@ function LLAgent.getGlobalPosition() return leap.request('LLAgent', {op = 'getPosition'}).global end +-- Use LL.leaphelp('LLAgent') and see 'setCameraParams' to get more info about params +-- -- TYPE -- DEFAULT -- RANGE +-- LLAgent.setCamera{ [, camera_pos] -- vector3 +-- [, focus_pos] -- vector3 +-- [, focus_offset] -- vector3 -- {1,0,0} -- {-10,-10,-10} to {10,10,10} +-- [, distance] -- float (meters) -- 3 -- 0.5 to 50 +-- [, focus_threshold] -- float (meters) -- 1 -- 0 to 4 +-- [, camera_threshold] -- float (meters) -- 1 -- 0 to 4 +-- [, focus_lag] -- float (seconds) -- 0.1 -- 0 to 3 +-- [, camera_lag] -- float (seconds) -- 0.1 -- 0 to 3 +-- [, camera_pitch] -- float (degrees) -- 0 -- -45 to 80 +-- [, behindness_angle] -- float (degrees) -- 10 -- 0 to 180 +-- [, behindness_lag] -- float (seconds) -- 0 -- 0 to 3 +-- [, camera_locked] -- bool -- false +-- [, focus_locked]} -- bool -- false function LLAgent.setCamera(...) - local args = mapargs('camera_pos,focus_pos,focus_offset,camera_locked,focus_locked', ...) + local args = mapargs('camera_pos,focus_pos,focus_offset,focus_lag,camera_lag,' .. + 'distance,focus_threshold,camera_threshold,camera_pitch,' .. + 'camera_locked,focus_locked,behindness_angle,behindness_lag', ...) args.op = 'setCameraParams' leap.send('LLAgent', args) end -- cgit v1.2.3 From c363e5bcf3e0cc60ee782d2ad82a8687e8a85cad Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Fri, 26 Jul 2024 16:23:54 +0200 Subject: Post merge cleanup of Linux code --- indra/newview/lldirpicker.cpp | 17 ----------------- indra/newview/viewer_manifest.py | 37 ------------------------------------- 2 files changed, 54 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 5df3ed1ba4..1d996b8c93 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -272,23 +272,6 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking) } return !mDir.empty(); #endif -#if !LL_MESA_HEADLESS - - if (mFilePicker) - { - GtkWindow* picker = mFilePicker->buildFilePicker(false, true, - "dirpicker"); - - if (picker) - { - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - return (!mFilePicker->getFirstFile().empty()); - } - } -#endif // !LL_MESA_HEADLESS - return false; } diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 5a4167a9e1..6be43f0021 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1438,43 +1438,6 @@ class Linux_x86_64_Manifest(LinuxManifest): self.path("libalut.so*") self.path("libopenal.so*") self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname - if self.args['fmodstudio'] == 'ON': - try: - self.path("libfmod.so.11.7") - self.path("libfmod.so.11") - self.path("libfmod.so") - pass - except: - print("Skipping libfmod.so - not found") - - # KLUDGE: As of 2012-04-11, the 'fontconfig' package installs - # libfontconfig.so.1.4.4, along with symlinks libfontconfig.so.1 - # and libfontconfig.so. Before we added support for library-file - # wildcards, though, this self.path() call specifically named - # libfontconfig.so.1.4.4 WITHOUT also copying the symlinks. When I - # (nat) changed the call to self.path("libfontconfig.so.*"), we - # ended up with the libfontconfig.so.1 symlink in the target - # directory as well. But guess what! At least on Ubuntu 10.04, - # certain viewer fonts look terrible with libfontconfig.so.1 - # present in the target directory. Removing that symlink suffices - # to improve them. I suspect that means we actually do better when - # the viewer fails to find our packaged libfontconfig.so*, falling - # back on the system one instead -- but diagnosing and fixing that - # is a bit out of scope for the present project. Meanwhile, this - # particular wildcard specification gets us exactly what the - # previous call did, without having to explicitly state the - # version number. - self.path("libfontconfig.so.*.*") - - # Include libfreetype.so. but have it work as libfontconfig does. - self.path("libfreetype.so.*.*") - - try: - self.path("libtcmalloc.so*") #formerly called google perf tools - pass - except: - print("tcmalloc files not found, skipping") - pass # Vivox runtimes with self.prefix(src=relpkgdir, dst="bin"): -- cgit v1.2.3 From e008b44fd88be83426812e67707896e970947c49 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Sat, 27 Jul 2024 18:26:31 +0300 Subject: Fix implicit conversion errors from int to float in llvoicewebrtc.cpp --- indra/newview/llvoicewebrtc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index d18a32cb05..123bd5e6ec 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2096,7 +2096,7 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s { // retries wait a short period...randomize it so // all clients don't try to reconnect at once. - mRetryWaitSecs = (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs = static_cast<F32>(rand()) / static_cast<F32>(RAND_MAX) + 0.5f; mWebRTCPeerConnectionInterface = llwebrtc::newPeerConnection(); mWebRTCPeerConnectionInterface->setSignalingObserver(this); @@ -2678,7 +2678,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() case VOICE_STATE_SESSION_UP: { mRetryWaitPeriod = 0; - mRetryWaitSecs = (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs = static_cast<F32>(rand()) / static_cast<F32>(RAND_MAX) + 0.5f; // we'll stay here as long as the session remains up. if (mShutDown) @@ -2700,7 +2700,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { // back off the retry period, and do it by a small random // bit so all clients don't reconnect at once. - mRetryWaitSecs += (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs += static_cast<F32>(rand()) / static_cast<F32>(RAND_MAX) + 0.5f; mRetryWaitPeriod = 0; } } -- cgit v1.2.3 From a9e1d0c781ffdddd5e04d48af604fcb014325b4c Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn <nicky.dasmijn@posteo.nl> Date: Mon, 29 Jul 2024 11:02:30 +0200 Subject: Linux; Package lllibwebrtc.so (#2134) --- indra/newview/viewer_manifest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6be43f0021..876fbb3734 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1253,11 +1253,13 @@ class LinuxManifest(ViewerManifest): with self.prefix(dst="res-sdl") : self.path("secondlife_256.BMP","ll_icon.BMP") + with self.prefix(src=os.path.join(self.args['build'], os.pardir, "llwebrtc" ), dst="lib"): + self.path("libllwebrtc.so") + # plugins with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): self.path("gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer.so") - with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): self.path("cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" ) with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"): -- cgit v1.2.3 From ed388f61bad7f6873ee3a2e4d673c9b991b4ef88 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Mon, 29 Jul 2024 16:51:37 +0300 Subject: Update expired cert in integration test (#2140) see fe8c976 for more info Co-authored-by: Andrey Lihatskiy <alihatskiy@productengine.com> --- indra/newview/tests/llsechandler_basic_test.cpp | 670 ++++++++++++------------ 1 file changed, 345 insertions(+), 325 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index bfe32406cb..cf37a4713c 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -232,381 +232,402 @@ namespace tut "Certificate:\n" " Data:\n" " Version: 3 (0x2)\n" - " Serial Number:\n" - " 82:2f:8f:eb:8d:06:24:b0\n" + " Serial Number: ef:54:d8:f7:da:18:e8:19\n" " Signature Algorithm: sha256WithRSAEncryption\n" " Issuer: C=US, ST=California, L=San Francisco, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Root CA/emailAddress=noreply@lindenlab.com\n" " Validity\n" - " Not Before: May 22 22:19:45 2018 GMT\n" - " Not After : May 17 22:19:45 2038 GMT\n" + " Not Before: Jul 23 11:46:26 2024 GMT\n" + " Not After : Jul 21 11:46:26 2034 GMT\n" " Subject: C=US, ST=California, L=San Francisco, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Root CA/emailAddress=noreply@lindenlab.com\n" " Subject Public Key Info:\n" " Public Key Algorithm: rsaEncryption\n" " Public-Key: (4096 bit)\n" " Modulus:\n" - " 00:bd:e0:79:dd:3b:a6:ac:87:d0:39:f0:58:c7:a4:\n" - " 42:42:f6:5f:93:b0:36:04:b5:e2:d5:f7:2a:c0:6c:\n" - " a0:13:d2:1e:02:81:57:02:50:4c:57:b7:ef:27:9e:\n" - " f6:f1:f1:30:30:72:1e:57:34:e5:3f:82:3c:21:c4:\n" - " 66:d2:73:63:6c:91:e6:dd:49:9e:9c:b1:34:6a:81:\n" - " 45:a1:6e:c4:50:28:f2:d8:e3:fe:80:2f:83:aa:28:\n" - " 91:b4:8c:57:c9:f1:16:d9:0c:87:3c:25:80:a0:81:\n" - " 8d:71:f2:96:e2:16:f1:97:c4:b0:d8:53:bb:13:6c:\n" - " 73:54:2f:29:94:85:cf:86:6e:75:71:ad:39:e3:fc:\n" - " 39:12:53:93:1c:ce:39:e0:33:da:49:b7:3d:af:b0:\n" - " 37:ce:77:09:03:27:32:70:c0:9c:7f:9c:89:ce:90:\n" - " 45:b0:7d:94:8b:ff:13:27:ba:88:7f:ae:c4:aa:73:\n" - " d5:47:b8:87:69:89:80:0c:c1:22:18:78:c2:0d:47:\n" - " d9:10:ff:80:79:0d:46:71:ec:d9:ba:c9:f3:77:fd:\n" - " 92:6d:1f:0f:d9:54:18:6d:f6:72:24:5c:5c:3d:43:\n" - " 49:35:3e:1c:28:de:7e:44:dc:29:c3:9f:62:04:46:\n" - " aa:c4:e6:69:6a:15:f8:e3:74:1c:14:e9:f4:97:7c:\n" - " 30:6c:d4:28:fc:2a:0e:1d:6d:39:2e:1d:f9:17:43:\n" - " 35:5d:23:e7:ba:e3:a8:e9:97:6b:3c:3e:23:ef:d8:\n" - " bc:fb:7a:57:37:39:93:59:03:fc:78:ca:b1:31:ef:\n" - " 26:19:ed:56:e1:63:c3:ad:99:80:5b:47:b5:03:35:\n" - " 5f:fe:6a:a6:21:63:ec:50:fb:4e:c9:f9:ae:a5:66:\n" - " d0:55:33:8d:e6:c5:50:5a:c6:8f:5c:34:45:a7:72:\n" - " da:50:f6:66:4c:19:f5:d1:e4:fb:11:8b:a1:b5:4e:\n" - " 09:43:81:3d:39:28:86:3b:fe:07:28:97:02:b5:3a:\n" - " 07:5f:4a:20:80:1a:7d:a4:8c:f7:6c:f6:c5:9b:f6:\n" - " 61:e5:c7:b0:c3:d5:58:38:7b:bb:47:1e:34:d6:16:\n" - " 55:c5:d2:6c:b0:93:77:b1:90:69:06:b1:53:cb:1b:\n" - " 84:71:cf:b8:87:1b:1e:44:35:b4:2b:bb:04:59:58:\n" - " 0b:e8:93:d8:ae:21:9b:b1:1c:89:30:ae:11:80:77:\n" - " cc:16:f3:d6:35:ed:a1:b3:70:b3:4f:cd:a1:56:99:\n" - " ee:0e:c0:00:a4:09:70:c3:5b:0b:be:a1:07:18:dd:\n" - " c6:f4:6d:8b:58:bc:f9:bb:4b:01:2c:f6:cc:2c:9b:\n" - " 87:0e:b1:4f:9c:10:be:fc:45:e2:a4:ec:7e:fc:ff:\n" - " 45:b8:53\n" + " 00:c6:cc:07:f4:0b:17:06:4d:a6:30:b4:c7:02:6b:\n" + " 9d:a4:47:a6:09:0e:60:1a:32:d4:6b:42:88:ee:c5:\n" + " b9:e9:fb:b5:0b:60:dc:a2:45:92:a5:bb:88:12:fc:\n" + " 42:1a:80:32:79:16:62:7a:97:af:84:28:53:3c:c1:\n" + " f2:68:c0:4e:45:e4:0a:63:f9:34:1d:a2:8b:cc:70:\n" + " df:c6:65:c0:ba:31:32:d2:9d:0c:c8:ce:dc:11:12:\n" + " a4:11:fa:d3:c8:56:e2:31:8a:e3:fb:91:40:da:25:\n" + " 55:d1:f2:75:9b:4d:fa:b8:1f:b5:6d:9b:e1:fe:5d:\n" + " e8:c4:02:79:14:ef:7d:5a:b3:3a:1e:b6:d0:60:2c:\n" + " 90:dc:22:e2:c5:ae:85:1f:b4:9d:7a:20:f8:af:63:\n" + " 56:25:1a:64:f3:9c:3f:9a:cf:68:08:0a:37:db:d0:\n" + " a3:65:26:db:80:82:ff:e0:1b:51:c8:ee:f6:ad:c2:\n" + " b4:f2:ab:d2:e8:85:86:77:28:d0:63:4a:71:78:41:\n" + " e3:8c:7f:71:51:31:af:24:3f:fa:8d:d0:d8:0b:e2:\n" + " 7e:79:33:8a:bb:d2:00:9e:2e:c8:cd:d5:50:92:b8:\n" + " 5c:5a:0b:99:ef:05:39:67:da:be:70:36:51:37:37:\n" + " 20:6f:84:ab:29:11:00:7b:38:32:ba:0b:bc:34:a6:\n" + " b5:c6:a7:f0:c0:25:2d:38:0b:72:40:ab:cf:e6:ff:\n" + " 97:75:ff:e2:a9:3c:2a:57:ce:e4:52:20:8c:de:fe:\n" + " 68:ce:54:85:37:ba:b3:7f:2e:53:58:ea:9b:ac:79:\n" + " 6b:16:65:b8:11:88:5a:46:eb:9e:9e:80:3c:89:91:\n" + " 35:e0:c5:33:45:c8:86:4d:25:51:39:b1:72:97:2b:\n" + " b3:c8:c9:e8:11:cd:32:41:c8:c1:56:22:7e:33:81:\n" + " 85:61:ab:da:9e:6e:5f:24:1c:0f:9b:fa:da:9d:86:\n" + " 1a:66:f6:32:2a:10:80:ea:72:7a:4a:ef:c0:f2:7c:\n" + " 43:02:e6:70:19:6a:e1:02:0a:00:80:51:1c:a3:03:\n" + " 8b:6d:89:9f:91:37:90:d6:d8:9c:73:77:06:9e:bc:\n" + " 95:89:66:ee:43:40:a3:ee:43:a3:f6:2d:43:dd:7b:\n" + " f0:2f:0b:12:37:49:b7:81:5a:e2:54:6d:71:88:ff:\n" + " fe:7e:41:25:35:4c:b4:b9:62:65:dd:9f:1f:7a:06:\n" + " 6e:2b:20:58:78:da:08:66:a8:f1:89:de:8f:7f:5c:\n" + " 5e:c2:72:33:7f:b6:8e:41:4c:26:f6:4c:d4:0e:11:\n" + " 44:da:c7:14:f7:8b:79:4e:53:29:87:15:b1:12:e9:\n" + " 19:2b:54:33:d6:2e:7f:bd:42:20:be:fc:d7:9c:b4:\n" + " 7a:0a:db\n" " Exponent: 65537 (0x10001)\n" " X509v3 extensions:\n" - " X509v3 Subject Key Identifier: \n" - " 8A:22:C6:9C:2E:11:F3:40:0C:CE:82:0C:22:59:FF:F8:7F:D0:B9:13\n" - " X509v3 Authority Key Identifier: \n" - " keyid:8A:22:C6:9C:2E:11:F3:40:0C:CE:82:0C:22:59:FF:F8:7F:D0:B9:13\n" + " X509v3 Subject Key Identifier:\n" + " 4D:7D:AE:0D:A5:5E:22:5A:6A:8F:19:61:54:B3:58:CB:7B:C0:BD:DA\n" + " X509v3 Authority Key Identifier:\n" + " keyid:4D:7D:AE:0D:A5:5E:22:5A:6A:8F:19:61:54:B3:58:CB:7B:C0:BD:DA\n" "\n" - " X509v3 Basic Constraints: critical\n" + " X509v3 Basic Constraints:\n" " CA:TRUE\n" - " X509v3 Key Usage: critical\n" - " Digital Signature, Certificate Sign, CRL Sign\n" " Signature Algorithm: sha256WithRSAEncryption\n" - " b3:cb:33:eb:0e:02:64:f4:55:9a:3d:03:9a:cf:6a:4c:18:43:\n" - " f7:42:cb:65:dc:61:52:e5:9f:2f:42:97:3c:93:16:22:d4:af:\n" - " ae:b2:0f:c3:9b:ef:e0:cc:ee:b6:b1:69:a3:d8:da:26:c3:ad:\n" - " 3b:c5:64:dc:9f:d4:c2:53:4b:91:6d:c4:92:09:0b:ac:f0:99:\n" - " be:6f:b9:3c:03:4a:6d:9f:01:5d:ec:5a:9a:f3:a7:e5:3b:2c:\n" - " 99:57:7d:7e:25:15:68:20:12:30:96:16:86:f5:db:74:90:60:\n" - " fe:8b:df:99:f6:f7:62:49:9f:bc:8d:45:23:0a:c8:73:b8:79:\n" - " 80:3c:b9:e5:72:85:4b:b3:81:66:74:a2:72:92:4c:44:fd:7b:\n" - " 46:2e:21:a2:a9:81:a2:f3:26:4d:e3:89:7d:78:b0:c6:6f:b5:\n" - " 87:cb:ee:25:ed:27:1f:75:13:fa:6d:e9:37:73:ad:07:bb:af:\n" - " d3:6c:87:ea:02:01:70:bd:53:aa:ce:39:2c:d4:66:39:33:aa:\n" - " d1:9c:ee:67:e3:a9:45:d2:7b:2e:54:09:af:70:5f:3f:5a:67:\n" - " 2e:6c:72:ef:e0:9d:92:28:4a:df:ba:0b:b7:23:ca:5b:04:11:\n" - " 45:d1:51:e9:ea:c9:ec:54:fa:34:46:ae:fc:dc:6c:f8:1e:2c:\n" - " 9e:f4:71:51:8d:b5:a1:26:9a:13:30:be:1e:41:25:59:58:05:\n" - " 2c:64:c8:f9:5e:38:ae:dc:93:b0:8a:d6:38:74:02:cb:ce:ce:\n" - " 95:31:76:f6:7c:bf:a4:a1:8e:27:fd:ca:74:82:d1:e1:4d:b6:\n" - " 48:51:fa:c5:17:59:22:a3:84:be:82:c8:83:ec:61:a0:f4:ee:\n" - " 2c:e3:a3:ea:e5:51:c9:d3:4f:db:85:bd:ba:7a:52:14:b6:03:\n" - " ed:43:17:d8:d7:1c:22:5e:c9:56:d9:d6:81:96:11:e3:5e:01:\n" - " 40:91:30:09:da:a3:5f:d3:27:60:e5:9d:6c:da:d0:f0:39:01:\n" - " 23:4a:a6:15:7a:4a:82:eb:ec:72:4a:1d:36:dc:6f:83:c4:85:\n" - " 84:b5:8d:cd:09:e5:12:63:f3:21:56:c8:64:6b:db:b8:cf:d4:\n" - " df:ca:a8:24:8e:df:8d:63:a5:96:84:bf:ff:8b:7e:46:7a:f0:\n" - " c7:73:7c:70:8a:f5:17:d0:ac:c8:89:1e:d7:89:42:0f:4d:66:\n" - " c4:d8:bb:36:a8:ae:ca:e1:cf:e2:88:f6:cf:b0:44:4a:5f:81:\n" - " 50:4b:d6:28:81:cd:6c:f0:ec:e6:09:08:f2:59:91:a2:69:ac:\n" - " c7:81:fa:ab:61:3e:db:6f:f6:7f:db:1a:9e:b9:5d:cc:cc:33:\n" - " fa:95:c6:f7:8d:4b:30:f3\n" + " 5b:40:71:96:c8:d1:57:3f:fc:f2:3c:75:fb:c9:a6:a7:63:8a:\n" + " 22:23:96:0f:40:77:77:e2:7f:76:fc:5f:7b:1c:bd:ea:ca:f0:\n" + " be:1a:fd:59:e6:0e:00:d1:78:44:01:28:f4:01:68:67:78:cf:\n" + " 78:43:36:ac:b2:5c:13:0e:2a:94:59:88:9e:64:46:42:0a:9b:\n" + " be:7d:2d:10:11:fe:8b:64:01:fb:00:c5:2e:47:63:c0:93:3a:\n" + " 4a:f8:6c:fc:a9:16:58:ab:bc:7b:6b:20:31:9d:d7:d8:84:01:\n" + " cc:ce:52:7f:a1:18:2f:5c:c9:59:58:9a:98:b9:ef:54:d7:a0:\n" + " 56:79:28:ba:ad:f5:e5:fd:7e:d8:d6:be:dd:25:76:6f:fa:8a:\n" + " 07:f6:8e:0f:83:43:19:ee:96:c4:c9:54:df:19:5a:4c:ae:25:\n" + " 57:a2:5d:d5:e8:0a:66:d8:19:e9:c4:44:ba:6a:3b:b3:86:ae:\n" + " 44:c0:7c:6e:e5:a0:6c:45:bb:7f:34:94:e9:d3:d4:f4:04:0b:\n" + " eb:fc:9a:fa:67:d4:e5:83:5e:08:09:9c:70:a9:d3:0d:8a:08:\n" + " ed:3c:04:33:4f:ac:02:d9:5c:99:62:12:fc:0e:8d:55:8a:ce:\n" + " ca:28:5a:1a:9e:c9:59:8e:f0:f5:19:c7:30:1e:59:1f:3c:77:\n" + " 6d:fc:a2:31:ec:bf:83:fd:14:26:91:68:88:05:4c:87:82:e0:\n" + " 33:f4:ee:d8:56:97:23:3a:00:9b:e7:a2:10:c2:83:28:c6:c0:\n" + " c1:92:49:95:c1:d3:e1:43:e8:8f:0c:d0:ae:e3:50:17:1a:8d:\n" + " 0f:4a:60:71:76:8e:9e:fb:15:76:cd:cd:69:2c:59:24:69:d2:\n" + " 0f:f2:d5:0e:96:95:2b:2e:d7:81:ed:b3:7b:6f:ce:60:32:b5:\n" + " f0:f6:74:ea:27:3a:ee:2c:96:7b:e0:06:6c:33:25:c4:60:da:\n" + " 76:de:c4:a1:22:b6:b1:63:57:10:3c:62:60:98:47:39:9e:38:\n" + " ce:c7:ef:75:75:19:d3:26:2a:cf:46:e3:b0:72:38:49:ee:c3:\n" + " 4e:52:97:e5:e5:b8:bc:b1:45:56:98:54:0a:63:c8:87:ff:a0:\n" + " cb:28:12:5c:8f:a2:6e:a7:f9:50:98:2d:a5:26:08:df:16:29:\n" + " 19:63:7f:6c:b4:41:20:f7:5d:ef:6a:90:fd:1a:08:1c:c2:4c:\n" + " 3e:77:ea:e0:df:c0:dd:aa:a2:36:e7:e8:be:98:39:0a:68:59:\n" + " 8e:a0:71:2f:7c:92:ab:e0:c4:c1:c2:eb:89:b6:34:ce:44:ab:\n" + " f9:f6:a4:c8:7b:ad:a8:bc:c9:04:7c:d5:4c:a4:d2:8b:54:23:\n" + " 89:68:86:4e:07:36:d9:bc\n" "-----BEGIN CERTIFICATE-----\n" - "MIIGXDCCBESgAwIBAgIJAIIvj+uNBiSwMA0GCSqGSIb3DQEBCwUAMIG6MQswCQYD\n" + "MIIGSTCCBDGgAwIBAgIJAO9U2PfaGOgZMA0GCSqGSIb3DQEBCwUAMIG6MQswCQYD\n" "VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\n" "aXNjbzETMBEGA1UECgwKTGluZGVuIExhYjEgMB4GA1UECwwXU2Vjb25kIExpZmUg\n" "RW5naW5lZXJpbmcxITAfBgNVBAMMGEludGVncmF0aW9uIFRlc3QgUm9vdCBDQTEk\n" - "MCIGCSqGSIb3DQEJARYVbm9yZXBseUBsaW5kZW5sYWIuY29tMB4XDTE4MDUyMjIy\n" - "MTk0NVoXDTM4MDUxNzIyMTk0NVowgboxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD\n" + "MCIGCSqGSIb3DQEJARYVbm9yZXBseUBsaW5kZW5sYWIuY29tMB4XDTI0MDcyMzEx\n" + "NDYyNloXDTM0MDcyMTExNDYyNlowgboxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD\n" "YWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApMaW5k\n" "ZW4gTGFiMSAwHgYDVQQLDBdTZWNvbmQgTGlmZSBFbmdpbmVlcmluZzEhMB8GA1UE\n" "AwwYSW50ZWdyYXRpb24gVGVzdCBSb290IENBMSQwIgYJKoZIhvcNAQkBFhVub3Jl\n" "cGx5QGxpbmRlbmxhYi5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n" - "AQC94HndO6ash9A58FjHpEJC9l+TsDYEteLV9yrAbKAT0h4CgVcCUExXt+8nnvbx\n" - "8TAwch5XNOU/gjwhxGbSc2NskebdSZ6csTRqgUWhbsRQKPLY4/6AL4OqKJG0jFfJ\n" - "8RbZDIc8JYCggY1x8pbiFvGXxLDYU7sTbHNULymUhc+GbnVxrTnj/DkSU5Mczjng\n" - "M9pJtz2vsDfOdwkDJzJwwJx/nInOkEWwfZSL/xMnuoh/rsSqc9VHuIdpiYAMwSIY\n" - "eMINR9kQ/4B5DUZx7Nm6yfN3/ZJtHw/ZVBht9nIkXFw9Q0k1Phwo3n5E3CnDn2IE\n" - "RqrE5mlqFfjjdBwU6fSXfDBs1Cj8Kg4dbTkuHfkXQzVdI+e646jpl2s8PiPv2Lz7\n" - "elc3OZNZA/x4yrEx7yYZ7VbhY8OtmYBbR7UDNV/+aqYhY+xQ+07J+a6lZtBVM43m\n" - "xVBaxo9cNEWnctpQ9mZMGfXR5PsRi6G1TglDgT05KIY7/gcolwK1OgdfSiCAGn2k\n" - "jPds9sWb9mHlx7DD1Vg4e7tHHjTWFlXF0mywk3exkGkGsVPLG4Rxz7iHGx5ENbQr\n" - "uwRZWAvok9iuIZuxHIkwrhGAd8wW89Y17aGzcLNPzaFWme4OwACkCXDDWwu+oQcY\n" - "3cb0bYtYvPm7SwEs9swsm4cOsU+cEL78ReKk7H78/0W4UwIDAQABo2MwYTAdBgNV\n" - "HQ4EFgQUiiLGnC4R80AMzoIMIln/+H/QuRMwHwYDVR0jBBgwFoAUiiLGnC4R80AM\n" - "zoIMIln/+H/QuRMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJ\n" - "KoZIhvcNAQELBQADggIBALPLM+sOAmT0VZo9A5rPakwYQ/dCy2XcYVLlny9ClzyT\n" - "FiLUr66yD8Ob7+DM7raxaaPY2ibDrTvFZNyf1MJTS5FtxJIJC6zwmb5vuTwDSm2f\n" - "AV3sWprzp+U7LJlXfX4lFWggEjCWFob123SQYP6L35n292JJn7yNRSMKyHO4eYA8\n" - "ueVyhUuzgWZ0onKSTET9e0YuIaKpgaLzJk3jiX14sMZvtYfL7iXtJx91E/pt6Tdz\n" - "rQe7r9Nsh+oCAXC9U6rOOSzUZjkzqtGc7mfjqUXSey5UCa9wXz9aZy5scu/gnZIo\n" - "St+6C7cjylsEEUXRUenqyexU+jRGrvzcbPgeLJ70cVGNtaEmmhMwvh5BJVlYBSxk\n" - "yPleOK7ck7CK1jh0AsvOzpUxdvZ8v6Shjif9ynSC0eFNtkhR+sUXWSKjhL6CyIPs\n" - "YaD07izjo+rlUcnTT9uFvbp6UhS2A+1DF9jXHCJeyVbZ1oGWEeNeAUCRMAnao1/T\n" - "J2DlnWza0PA5ASNKphV6SoLr7HJKHTbcb4PEhYS1jc0J5RJj8yFWyGRr27jP1N/K\n" - "qCSO341jpZaEv/+LfkZ68MdzfHCK9RfQrMiJHteJQg9NZsTYuzaorsrhz+KI9s+w\n" - "REpfgVBL1iiBzWzw7OYJCPJZkaJprMeB+qthPttv9n/bGp65XczMM/qVxveNSzDz\n" + "AQDGzAf0CxcGTaYwtMcCa52kR6YJDmAaMtRrQojuxbnp+7ULYNyiRZKlu4gS/EIa\n" + "gDJ5FmJ6l6+EKFM8wfJowE5F5Apj+TQdoovMcN/GZcC6MTLSnQzIztwREqQR+tPI\n" + "VuIxiuP7kUDaJVXR8nWbTfq4H7Vtm+H+XejEAnkU731aszoettBgLJDcIuLFroUf\n" + "tJ16IPivY1YlGmTznD+az2gICjfb0KNlJtuAgv/gG1HI7vatwrTyq9LohYZ3KNBj\n" + "SnF4QeOMf3FRMa8kP/qN0NgL4n55M4q70gCeLsjN1VCSuFxaC5nvBTln2r5wNlE3\n" + "NyBvhKspEQB7ODK6C7w0prXGp/DAJS04C3JAq8/m/5d1/+KpPCpXzuRSIIze/mjO\n" + "VIU3urN/LlNY6puseWsWZbgRiFpG656egDyJkTXgxTNFyIZNJVE5sXKXK7PIyegR\n" + "zTJByMFWIn4zgYVhq9qebl8kHA+b+tqdhhpm9jIqEIDqcnpK78DyfEMC5nAZauEC\n" + "CgCAURyjA4ttiZ+RN5DW2JxzdwaevJWJZu5DQKPuQ6P2LUPde/AvCxI3SbeBWuJU\n" + "bXGI//5+QSU1TLS5YmXdnx96Bm4rIFh42ghmqPGJ3o9/XF7CcjN/to5BTCb2TNQO\n" + "EUTaxxT3i3lOUymHFbES6RkrVDPWLn+9QiC+/NectHoK2wIDAQABo1AwTjAdBgNV\n" + "HQ4EFgQUTX2uDaVeIlpqjxlhVLNYy3vAvdowHwYDVR0jBBgwFoAUTX2uDaVeIlpq\n" + "jxlhVLNYy3vAvdowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAW0Bx\n" + "lsjRVz/88jx1+8mmp2OKIiOWD0B3d+J/dvxfexy96srwvhr9WeYOANF4RAEo9AFo\n" + "Z3jPeEM2rLJcEw4qlFmInmRGQgqbvn0tEBH+i2QB+wDFLkdjwJM6Svhs/KkWWKu8\n" + "e2sgMZ3X2IQBzM5Sf6EYL1zJWViamLnvVNegVnkouq315f1+2Na+3SV2b/qKB/aO\n" + "D4NDGe6WxMlU3xlaTK4lV6Jd1egKZtgZ6cREumo7s4auRMB8buWgbEW7fzSU6dPU\n" + "9AQL6/ya+mfU5YNeCAmccKnTDYoI7TwEM0+sAtlcmWIS/A6NVYrOyihaGp7JWY7w\n" + "9RnHMB5ZHzx3bfyiMey/g/0UJpFoiAVMh4LgM/Tu2FaXIzoAm+eiEMKDKMbAwZJJ\n" + "lcHT4UPojwzQruNQFxqND0pgcXaOnvsVds3NaSxZJGnSD/LVDpaVKy7Xge2ze2/O\n" + "YDK18PZ06ic67iyWe+AGbDMlxGDadt7EoSK2sWNXEDxiYJhHOZ44zsfvdXUZ0yYq\n" + "z0bjsHI4Se7DTlKX5eW4vLFFVphUCmPIh/+gyygSXI+ibqf5UJgtpSYI3xYpGWN/\n" + "bLRBIPdd72qQ/RoIHMJMPnfq4N/A3aqiNufovpg5CmhZjqBxL3ySq+DEwcLribY0\n" + "zkSr+fakyHutqLzJBHzVTKTSi1QjiWiGTgc22bw=\n" "-----END CERTIFICATE-----\n" - ); + ); + const std::string mPemIntermediateCert( "Certificate:\n" " Data:\n" " Version: 3 (0x2)\n" - " Serial Number: 4096 (0x1000)\n" + " Serial Number: 85:bb:4b:66:26:db:9a:c6\n" " Signature Algorithm: sha256WithRSAEncryption\n" " Issuer: C=US, ST=California, L=San Francisco, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Root CA/emailAddress=noreply@lindenlab.com\n" " Validity\n" - " Not Before: May 22 22:39:08 2018 GMT\n" - " Not After : May 19 22:39:08 2028 GMT\n" - " Subject: C=US, ST=California, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Intermediate CA/emailAddress=noreply@lindenlab.com\n" + " Not Before: Jul 23 11:46:33 2024 GMT\n" + " Not After : Jul 21 11:46:33 2034 GMT\n" + " Subject: C=US, ST=California, L=San Francisco, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Intermediate CA/emailAddress=noreply@lindenlab.com\n" " Subject Public Key Info:\n" " Public Key Algorithm: rsaEncryption\n" " Public-Key: (4096 bit)\n" " Modulus:\n" - " 00:ce:a3:70:e2:c4:fb:4b:97:90:a1:30:bb:c1:1b:\n" - " 13:b9:aa:7e:46:17:a3:26:8d:69:3f:5e:73:95:e8:\n" - " 6a:b1:0a:b4:8f:50:65:e3:c6:5c:39:24:34:df:0b:\n" - " b7:cc:ce:62:0c:36:5a:12:2c:fe:35:4c:e9:1c:ac:\n" - " 80:5e:24:99:d7:aa:bd:be:48:c0:62:64:77:36:88:\n" - " 66:ce:f4:a8:dd:d2:76:24:62:90:55:41:fc:1d:13:\n" - " 4e:a7:4e:57:bc:a8:a4:59:4b:2c:5a:1c:d8:cc:16:\n" - " de:e8:88:30:c9:95:df:2f:a6:14:28:0f:eb:34:46:\n" - " 12:58:ba:da:0e:e6:de:9c:15:f6:f4:e3:9f:74:aa:\n" - " 70:89:79:8b:e9:5a:7b:18:54:15:94:3a:23:0a:65:\n" - " 78:05:d9:33:90:2a:ce:15:18:0d:52:fc:5c:31:65:\n" - " 20:d0:12:37:8c:11:80:ba:d4:b0:82:73:00:4b:49:\n" - " be:cb:d6:bc:e7:cd:61:f3:00:98:99:74:5a:37:81:\n" - " 49:96:7e:14:01:1b:86:d2:d0:06:94:40:63:63:46:\n" - " 11:fc:33:5c:bd:3a:5e:d4:e5:44:47:64:50:bd:a6:\n" - " 97:55:70:64:9b:26:cc:de:20:82:90:6a:83:41:9c:\n" - " 6f:71:47:14:be:cb:68:7c:85:be:ef:2e:76:12:19:\n" - " d3:c9:87:32:b4:ac:60:20:16:28:2d:af:bc:e8:01:\n" - " c6:7f:fb:d8:11:d5:f4:b7:14:bd:27:08:5b:72:be:\n" - " 09:e0:91:c8:9c:7b:b4:b3:12:ef:32:36:be:b1:b9:\n" - " a2:b7:e3:69:47:30:76:ba:9c:9b:19:99:4d:53:dd:\n" - " 5c:e8:2c:f1:b2:64:69:cf:15:bd:f8:bb:58:95:73:\n" - " 58:38:95:b4:7a:cf:84:29:a6:c2:db:f0:bd:ef:97:\n" - " 26:d4:99:ac:d7:c7:be:b0:0d:11:f4:26:86:2d:77:\n" - " 42:52:25:d7:56:c7:e3:97:b1:36:5c:97:71:d0:9b:\n" - " f5:b5:50:8d:f9:ff:fb:10:77:3c:b5:53:6d:a1:43:\n" - " 35:a9:03:32:05:ab:d7:f5:d1:19:bd:5f:92:a3:00:\n" - " 2a:79:37:a4:76:4f:e9:32:0d:e4:86:bb:ea:c3:1a:\n" - " c5:33:e8:16:d4:a5:d8:e0:e8:bb:c2:f0:22:15:e2:\n" - " d9:8c:ae:ac:7d:2b:bf:eb:a3:4c:3b:29:1d:94:ac:\n" - " a3:bb:6d:ba:6d:03:91:03:cf:46:12:c4:66:21:c5:\n" - " c6:67:d8:11:19:79:01:0e:6e:84:1c:76:6f:11:3d:\n" - " eb:94:89:c5:6a:26:1f:cd:e0:11:8b:51:ee:99:35:\n" - " 69:e5:7f:0b:77:2a:94:e4:4b:64:b9:83:04:30:05:\n" - " e4:a2:e3\n" + " 00:be:f7:d2:cb:e4:5c:46:7b:e2:11:22:89:72:da:\n" + " 77:72:ec:05:87:19:f7:77:07:fd:67:d7:af:13:d5:\n" + " 76:12:92:dd:69:4d:22:47:b0:3d:94:8a:6a:95:85:\n" + " 34:b8:78:c3:9d:63:32:b1:4b:0a:b6:0e:05:7b:ab:\n" + " 06:23:fc:0d:21:b5:fc:c6:6a:5a:36:be:6e:fc:c7:\n" + " 47:97:a3:18:2e:33:cd:0e:8a:75:2b:b7:29:e9:68:\n" + " 4a:90:53:45:db:73:ff:b3:e5:c1:d4:6b:dd:3a:b1:\n" + " ef:53:9f:23:e9:c6:87:ce:67:b9:fb:a4:d5:76:21:\n" + " 03:cb:c5:72:6b:c5:a6:07:55:fb:47:90:e8:92:38:\n" + " 73:14:11:8e:ff:21:b9:35:64:5a:61:c7:fc:1f:e4:\n" + " 4d:47:e5:03:cc:0b:c3:69:66:71:84:0c:18:2f:61:\n" + " 7f:34:dd:f2:91:e3:b7:9d:a8:b8:db:3f:6e:6f:96:\n" + " fa:34:06:82:04:c8:18:cc:de:8b:7f:26:b5:48:53:\n" + " fb:fb:15:7b:0e:38:60:fe:da:21:98:8d:73:07:b2:\n" + " 6b:fd:ad:21:59:e7:84:66:e1:04:16:1c:be:13:34:\n" + " 28:43:2c:09:3d:e4:77:2a:a4:ad:6d:f9:26:04:f7:\n" + " 43:73:9b:d9:ea:1a:43:6a:b4:db:88:f8:f9:bd:34:\n" + " f8:a6:e8:7a:ab:b4:b2:e1:29:47:a6:ba:b8:65:9c:\n" + " c6:b3:af:13:43:38:ef:2a:05:77:9f:8f:f0:0c:56:\n" + " 21:c2:92:d2:2c:c3:32:50:d1:62:ae:51:fc:99:e6:\n" + " b8:38:f8:83:1d:8d:40:11:e0:1d:51:5d:3f:fa:55:\n" + " 61:b6:18:09:1e:71:af:95:64:9c:ea:c6:11:64:f0:\n" + " a8:02:7d:bb:c8:54:2e:57:48:32:7c:51:66:0d:d6:\n" + " 3e:0e:ed:5e:30:a8:a6:47:03:64:5c:89:21:45:90:\n" + " e1:4c:91:bc:bd:81:6e:73:a9:14:27:e6:0d:6d:38:\n" + " dc:50:9d:b2:56:66:60:6c:66:b9:5d:bb:8c:96:2d:\n" + " 89:5e:0d:2b:ed:b8:03:31:ce:0a:ff:82:03:f5:b2:\n" + " 3b:e5:27:de:61:d8:8f:bf:a2:6a:64:b0:4a:87:23:\n" + " 40:28:a3:f1:ec:96:50:cd:83:50:2d:78:71:92:f2:\n" + " 88:75:b0:9d:cd:0b:e4:62:a6:a5:63:11:fc:b4:ba:\n" + " 9f:c6:67:40:2c:ad:a4:ef:94:f0:f9:a0:ba:e1:52:\n" + " 2e:27:d9:6b:1d:82:23:ed:3c:0b:0b:d2:bc:14:be:\n" + " 6d:b1:69:ad:3e:25:3a:66:d2:d1:af:9f:88:45:25:\n" + " 6b:6e:be:1f:a0:e7:b2:9f:6d:24:94:0d:f4:c2:75:\n" + " f9:1f:5d\n" " Exponent: 65537 (0x10001)\n" " X509v3 extensions:\n" - " X509v3 Subject Key Identifier: \n" - " 83:21:DE:EC:C0:79:03:6D:1E:83:F3:E5:97:29:D5:5A:C0:96:40:FA\n" - " X509v3 Authority Key Identifier: \n" - " keyid:8A:22:C6:9C:2E:11:F3:40:0C:CE:82:0C:22:59:FF:F8:7F:D0:B9:13\n" - "\n" - " X509v3 Basic Constraints: critical\n" + " X509v3 Basic Constraints:\n" " CA:TRUE, pathlen:0\n" - " X509v3 Key Usage: critical\n" + " X509v3 Key Usage:\n" " Digital Signature, Certificate Sign, CRL Sign\n" + " X509v3 Subject Key Identifier:\n" + " 56:98:DC:45:25:11:E2:8C:2B:EA:D6:C6:E2:C8:BE:2C:C8:69:FF:FF\n" + " X509v3 Authority Key Identifier:\n" + " keyid:4D:7D:AE:0D:A5:5E:22:5A:6A:8F:19:61:54:B3:58:CB:7B:C0:BD:DA\n" + " DirName:/C=US/ST=California/L=San Francisco/O=Linden Lab/OU=Second Life Engineering/CN=Integration Test Root CA/emailAddress=noreply@lindenlab.com\n" + " serial:EF:54:D8:F7:DA:18:E8:19\n" " Signature Algorithm: sha256WithRSAEncryption\n" - " a3:6c:85:9a:2e:4e:7e:5d:83:63:0f:f5:4f:a9:7d:ec:0e:6f:\n" - " ae:d7:ba:df:64:e0:46:0e:3d:da:18:15:2c:f3:73:ca:81:b1:\n" - " 10:d9:53:14:21:7d:72:5c:94:88:a5:9d:ad:ab:45:42:c6:64:\n" - " a9:d9:2e:4e:29:47:2c:b1:95:07:b7:62:48:68:1f:68:13:1c:\n" - " d2:a0:fb:5e:38:24:4a:82:0a:87:c9:93:20:43:7e:e9:f9:79:\n" - " ef:03:a2:bd:9e:24:6b:0a:01:5e:4a:36:c5:7d:7a:fe:d6:aa:\n" - " 2f:c2:8c:38:8a:99:3c:b0:6a:e5:60:be:56:d6:eb:60:03:55:\n" - " 24:42:a0:1a:fa:91:24:a3:53:15:75:5d:c8:eb:7c:1e:68:5a:\n" - " 7e:13:34:e3:85:37:1c:76:3f:77:67:1b:ed:1b:52:17:fc:4a:\n" - " a3:e2:74:84:80:2c:69:fc:dd:7d:26:97:c4:2a:69:7d:9c:dc:\n" - " 61:97:70:29:a7:3f:2b:5b:2b:22:51:fd:fe:6a:5d:f9:e7:14:\n" - " 48:b7:2d:c8:33:58:fc:f2:5f:27:f7:26:16:be:be:b5:aa:a2:\n" - " 64:53:3c:69:e8:b5:61:eb:ab:91:a5:b4:09:9b:f6:98:b8:5c:\n" - " 5b:24:2f:93:f5:2b:9c:8c:58:fb:26:3f:67:53:d7:42:64:e8:\n" - " 79:77:73:41:4e:e3:02:39:0b:b6:68:97:8b:84:e8:1d:83:a8:\n" - " 15:f1:06:46:47:80:42:5e:14:e2:61:8a:76:84:d5:d4:71:7f:\n" - " 4e:ff:d9:74:87:ff:32:c5:87:20:0a:d4:59:40:3e:d8:17:ef:\n" - " da:65:e9:0a:51:fe:1e:c3:46:91:d2:ee:e4:23:57:97:87:d4:\n" - " a6:a5:eb:ef:81:6a:d8:8c:d6:1f:8e:b1:18:4c:6b:89:32:55:\n" - " 53:68:26:9e:bb:03:be:2c:e9:8b:ff:97:9c:1c:ac:28:c3:9f:\n" - " 0b:b7:93:23:24:31:63:e4:19:13:f2:bb:08:71:b7:c5:c5:c4:\n" - " 10:ff:dc:fc:33:54:a4:5e:ec:a3:fe:0a:80:ca:9c:bc:95:6f:\n" - " 5f:39:91:3b:61:69:16:94:0f:57:4b:fc:4b:b1:be:72:98:5d:\n" - " 10:f9:08:a7:d6:e0:e8:3d:5d:54:7d:fa:4b:6a:dd:98:41:ed:\n" - " 84:a1:39:67:5c:6c:7f:0c:b0:e1:98:c1:14:ed:fe:1e:e8:05:\n" - " 8d:7f:6a:24:cb:1b:05:42:0d:7f:13:ba:ca:b5:91:db:a5:f0:\n" - " 40:2b:70:7a:2a:a5:5d:ed:56:0c:f0:c2:72:ee:63:dd:cb:5d:\n" - " 76:f6:08:e6:e6:30:ef:3a:b2:16:34:41:a4:e1:30:14:bc:c7:\n" - " f9:23:3a:1a:70:df:b8:cc\n" + " ae:d0:30:ac:31:49:20:86:0b:34:01:58:08:94:68:cc:38:9c:\n" + " f7:13:5c:46:19:33:ed:54:5e:e4:43:f3:59:33:5c:50:d9:89:\n" + " 8b:ee:75:67:a8:c7:0e:d1:30:c2:4e:a3:2e:a8:64:2d:6a:a8:\n" + " f4:bd:b1:32:dc:bc:46:48:5d:1a:18:d8:e8:0b:8c:fe:7b:51:\n" + " d9:dd:b9:e3:4b:d1:f9:e0:22:46:dd:37:5b:b2:cb:72:8e:9c:\n" + " 4b:da:67:df:fd:ce:86:49:21:31:4e:99:b6:d4:38:0b:14:5d:\n" + " ad:97:ba:8f:e2:08:15:85:73:eb:4a:7d:01:49:af:63:ae:2d:\n" + " e3:9d:0a:d7:11:c2:03:d3:15:21:97:be:3d:d2:ea:ab:cc:93:\n" + " 16:98:64:80:72:eb:c2:78:0a:09:69:c4:2b:5d:df:30:7b:be:\n" + " 9b:02:34:73:62:9f:95:b1:cf:08:e8:9e:57:a8:37:31:cf:2c:\n" + " 8c:18:b1:d5:7a:25:90:d6:b6:76:28:1b:e2:b1:cf:1b:f1:ef:\n" + " dd:2f:d3:07:af:81:e3:5f:fc:5a:e7:3c:a9:37:0d:9c:78:5b:\n" + " 58:dc:89:54:70:a4:5b:ff:9f:64:30:a3:85:12:32:69:a5:02:\n" + " 73:d9:1d:ff:69:1f:d4:97:8f:d0:a8:90:8c:dd:2e:45:a1:b1:\n" + " e3:8a:82:fc:fc:08:41:01:51:92:87:9a:09:7b:35:c3:cc:48:\n" + " 81:39:30:a9:f4:41:3b:06:a3:06:21:cc:4b:bc:1b:76:58:94:\n" + " d1:e4:22:70:7f:20:7e:7a:b4:fa:7f:e8:79:c1:8c:89:9e:e9:\n" + " e3:72:2a:43:72:47:9e:bb:26:ed:64:2c:c8:54:f7:b4:95:c2:\n" + " c4:e9:8b:df:d5:10:a7:ed:a5:7a:94:97:c4:76:45:e3:6c:c0:\n" + " 0e:a6:2a:76:d5:1d:2f:ad:99:32:c6:7b:f6:41:e0:65:37:0f:\n" + " c0:1f:c5:99:4a:75:fd:6c:e0:f1:f0:58:49:2d:81:10:ca:d8:\n" + " eb:2b:c3:9b:a9:d9:a9:f5:6c:6d:26:fd:b8:32:92:58:f4:65:\n" + " 0b:d1:8e:03:1e:d5:6a:95:d4:46:9e:65:dd:e5:85:36:e6:31:\n" + " 77:3a:1a:20:2b:07:b7:f1:9a:4e:8d:54:22:5a:54:1c:72:5c:\n" + " 1f:b4:1a:5b:21:ed:06:5a:9a:e5:3c:01:c9:9b:af:50:61:f2:\n" + " 29:6b:ec:6d:19:bb:2e:02:94:ca:36:71:ef:45:39:f1:a5:25:\n" + " 10:0e:90:bc:a7:b3:5b:ab:af:f1:19:88:6a:09:2f:1f:d0:24:\n" + " a8:62:ed:d9:1a:65:89:65:16:a5:55:de:33:e8:7a:81:66:72:\n" + " 91:17:5e:1d:22:72:f7:b8\n" "-----BEGIN CERTIFICATE-----\n" - "MIIGSDCCBDCgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgboxCzAJBgNVBAYTAlVT\n" - "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMw\n" - "EQYDVQQKDApMaW5kZW4gTGFiMSAwHgYDVQQLDBdTZWNvbmQgTGlmZSBFbmdpbmVl\n" - "cmluZzEhMB8GA1UEAwwYSW50ZWdyYXRpb24gVGVzdCBSb290IENBMSQwIgYJKoZI\n" - "hvcNAQkBFhVub3JlcGx5QGxpbmRlbmxhYi5jb20wHhcNMTgwNTIyMjIzOTA4WhcN\n" - "MjgwNTE5MjIzOTA4WjCBqjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3Ju\n" - "aWExEzARBgNVBAoMCkxpbmRlbiBMYWIxIDAeBgNVBAsMF1NlY29uZCBMaWZlIEVu\n" - "Z2luZWVyaW5nMSkwJwYDVQQDDCBJbnRlZ3JhdGlvbiBUZXN0IEludGVybWVkaWF0\n" - "ZSBDQTEkMCIGCSqGSIb3DQEJARYVbm9yZXBseUBsaW5kZW5sYWIuY29tMIICIjAN\n" - "BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzqNw4sT7S5eQoTC7wRsTuap+Rhej\n" - "Jo1pP15zlehqsQq0j1Bl48ZcOSQ03wu3zM5iDDZaEiz+NUzpHKyAXiSZ16q9vkjA\n" - "YmR3NohmzvSo3dJ2JGKQVUH8HRNOp05XvKikWUssWhzYzBbe6IgwyZXfL6YUKA/r\n" - "NEYSWLraDubenBX29OOfdKpwiXmL6Vp7GFQVlDojCmV4BdkzkCrOFRgNUvxcMWUg\n" - "0BI3jBGAutSwgnMAS0m+y9a8581h8wCYmXRaN4FJln4UARuG0tAGlEBjY0YR/DNc\n" - "vTpe1OVER2RQvaaXVXBkmybM3iCCkGqDQZxvcUcUvstofIW+7y52EhnTyYcytKxg\n" - "IBYoLa+86AHGf/vYEdX0txS9Jwhbcr4J4JHInHu0sxLvMja+sbmit+NpRzB2upyb\n" - "GZlNU91c6CzxsmRpzxW9+LtYlXNYOJW0es+EKabC2/C975cm1Jms18e+sA0R9CaG\n" - "LXdCUiXXVsfjl7E2XJdx0Jv1tVCN+f/7EHc8tVNtoUM1qQMyBavX9dEZvV+SowAq\n" - "eTekdk/pMg3khrvqwxrFM+gW1KXY4Oi7wvAiFeLZjK6sfSu/66NMOykdlKyju226\n" - "bQORA89GEsRmIcXGZ9gRGXkBDm6EHHZvET3rlInFaiYfzeARi1HumTVp5X8LdyqU\n" - "5EtkuYMEMAXkouMCAwEAAaNmMGQwHQYDVR0OBBYEFIMh3uzAeQNtHoPz5Zcp1VrA\n" - "lkD6MB8GA1UdIwQYMBaAFIoixpwuEfNADM6CDCJZ//h/0LkTMBIGA1UdEwEB/wQI\n" - "MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQCjbIWa\n" - "Lk5+XYNjD/VPqX3sDm+u17rfZOBGDj3aGBUs83PKgbEQ2VMUIX1yXJSIpZ2tq0VC\n" - "xmSp2S5OKUcssZUHt2JIaB9oExzSoPteOCRKggqHyZMgQ37p+XnvA6K9niRrCgFe\n" - "SjbFfXr+1qovwow4ipk8sGrlYL5W1utgA1UkQqAa+pEko1MVdV3I63weaFp+EzTj\n" - "hTccdj93ZxvtG1IX/Eqj4nSEgCxp/N19JpfEKml9nNxhl3Appz8rWysiUf3+al35\n" - "5xRIty3IM1j88l8n9yYWvr61qqJkUzxp6LVh66uRpbQJm/aYuFxbJC+T9SucjFj7\n" - "Jj9nU9dCZOh5d3NBTuMCOQu2aJeLhOgdg6gV8QZGR4BCXhTiYYp2hNXUcX9O/9l0\n" - "h/8yxYcgCtRZQD7YF+/aZekKUf4ew0aR0u7kI1eXh9SmpevvgWrYjNYfjrEYTGuJ\n" - "MlVTaCaeuwO+LOmL/5ecHKwow58Lt5MjJDFj5BkT8rsIcbfFxcQQ/9z8M1SkXuyj\n" - "/gqAypy8lW9fOZE7YWkWlA9XS/xLsb5ymF0Q+Qin1uDoPV1UffpLat2YQe2EoTln\n" - "XGx/DLDhmMEU7f4e6AWNf2okyxsFQg1/E7rKtZHbpfBAK3B6KqVd7VYM8MJy7mPd\n" - "y1129gjm5jDvOrIWNEGk4TAUvMf5IzoacN+4zA==\n" + "MIIHNjCCBR6gAwIBAgIJAIW7S2Ym25rGMA0GCSqGSIb3DQEBCwUAMIG6MQswCQYD\n" + "VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\n" + "aXNjbzETMBEGA1UECgwKTGluZGVuIExhYjEgMB4GA1UECwwXU2Vjb25kIExpZmUg\n" + "RW5naW5lZXJpbmcxITAfBgNVBAMMGEludGVncmF0aW9uIFRlc3QgUm9vdCBDQTEk\n" + "MCIGCSqGSIb3DQEJARYVbm9yZXBseUBsaW5kZW5sYWIuY29tMB4XDTI0MDcyMzEx\n" + "NDYzM1oXDTM0MDcyMTExNDYzM1owgcIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD\n" + "YWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApMaW5k\n" + "ZW4gTGFiMSAwHgYDVQQLDBdTZWNvbmQgTGlmZSBFbmdpbmVlcmluZzEpMCcGA1UE\n" + "AwwgSW50ZWdyYXRpb24gVGVzdCBJbnRlcm1lZGlhdGUgQ0ExJDAiBgkqhkiG9w0B\n" + "CQEWFW5vcmVwbHlAbGluZGVubGFiLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\n" + "ADCCAgoCggIBAL730svkXEZ74hEiiXLad3LsBYcZ93cH/WfXrxPVdhKS3WlNIkew\n" + "PZSKapWFNLh4w51jMrFLCrYOBXurBiP8DSG1/MZqWja+bvzHR5ejGC4zzQ6KdSu3\n" + "KeloSpBTRdtz/7PlwdRr3Tqx71OfI+nGh85nufuk1XYhA8vFcmvFpgdV+0eQ6JI4\n" + "cxQRjv8huTVkWmHH/B/kTUflA8wLw2lmcYQMGC9hfzTd8pHjt52ouNs/bm+W+jQG\n" + "ggTIGMzei38mtUhT+/sVew44YP7aIZiNcweya/2tIVnnhGbhBBYcvhM0KEMsCT3k\n" + "dyqkrW35JgT3Q3Ob2eoaQ2q024j4+b00+Kboequ0suEpR6a6uGWcxrOvE0M47yoF\n" + "d5+P8AxWIcKS0izDMlDRYq5R/JnmuDj4gx2NQBHgHVFdP/pVYbYYCR5xr5VknOrG\n" + "EWTwqAJ9u8hULldIMnxRZg3WPg7tXjCopkcDZFyJIUWQ4UyRvL2BbnOpFCfmDW04\n" + "3FCdslZmYGxmuV27jJYtiV4NK+24AzHOCv+CA/WyO+Un3mHYj7+iamSwSocjQCij\n" + "8eyWUM2DUC14cZLyiHWwnc0L5GKmpWMR/LS6n8ZnQCytpO+U8PmguuFSLifZax2C\n" + "I+08CwvSvBS+bbFprT4lOmbS0a+fiEUla26+H6Dnsp9tJJQN9MJ1+R9dAgMBAAGj\n" + "ggEzMIIBLzAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBhjAdBgNVHQ4EFgQU\n" + "VpjcRSUR4owr6tbG4si+LMhp//8wge8GA1UdIwSB5zCB5IAUTX2uDaVeIlpqjxlh\n" + "VLNYy3vAvdqhgcCkgb0wgboxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y\n" + "bmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApMaW5kZW4gTGFi\n" + "MSAwHgYDVQQLDBdTZWNvbmQgTGlmZSBFbmdpbmVlcmluZzEhMB8GA1UEAwwYSW50\n" + "ZWdyYXRpb24gVGVzdCBSb290IENBMSQwIgYJKoZIhvcNAQkBFhVub3JlcGx5QGxp\n" + "bmRlbmxhYi5jb22CCQDvVNj32hjoGTANBgkqhkiG9w0BAQsFAAOCAgEArtAwrDFJ\n" + "IIYLNAFYCJRozDic9xNcRhkz7VRe5EPzWTNcUNmJi+51Z6jHDtEwwk6jLqhkLWqo\n" + "9L2xMty8RkhdGhjY6AuM/ntR2d2540vR+eAiRt03W7LLco6cS9pn3/3OhkkhMU6Z\n" + "ttQ4CxRdrZe6j+IIFYVz60p9AUmvY64t450K1xHCA9MVIZe+PdLqq8yTFphkgHLr\n" + "wngKCWnEK13fMHu+mwI0c2KflbHPCOieV6g3Mc8sjBix1XolkNa2digb4rHPG/Hv\n" + "3S/TB6+B41/8Wuc8qTcNnHhbWNyJVHCkW/+fZDCjhRIyaaUCc9kd/2kf1JeP0KiQ\n" + "jN0uRaGx44qC/PwIQQFRkoeaCXs1w8xIgTkwqfRBOwajBiHMS7wbdliU0eQicH8g\n" + "fnq0+n/oecGMiZ7p43IqQ3JHnrsm7WQsyFT3tJXCxOmL39UQp+2lepSXxHZF42zA\n" + "DqYqdtUdL62ZMsZ79kHgZTcPwB/FmUp1/Wzg8fBYSS2BEMrY6yvDm6nZqfVsbSb9\n" + "uDKSWPRlC9GOAx7VapXURp5l3eWFNuYxdzoaICsHt/GaTo1UIlpUHHJcH7QaWyHt\n" + "Blqa5TwByZuvUGHyKWvsbRm7LgKUyjZx70U58aUlEA6QvKezW6uv8RmIagkvH9Ak\n" + "qGLt2RpliWUWpVXeM+h6gWZykRdeHSJy97g=\n" "-----END CERTIFICATE-----\n" - ); + ); const std::string mPemChildCert( "Certificate:\n" " Data:\n" " Version: 3 (0x2)\n" - " Serial Number: 4096 (0x1000)\n" + " Serial Number: 9e:8d:34:13:e7:9b:f9:31\n" " Signature Algorithm: sha256WithRSAEncryption\n" - " Issuer: C=US, ST=California, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Intermediate CA/emailAddress=noreply@lindenlab.com\n" + " Issuer: C=US, ST=California, L=San Francisco, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Intermediate CA/emailAddress=noreply@lindenlab.com\n" " Validity\n" - " Not Before: May 22 22:58:15 2018 GMT\n" - " Not After : Jul 19 22:58:15 2024 GMT\n" + " Not Before: Jul 23 11:46:39 2024 GMT\n" + " Not After : Jul 21 11:46:39 2034 GMT\n" " Subject: C=US, ST=California, L=San Francisco, O=Linden Lab, OU=Second Life Engineering, CN=Integration Test Server Cert/emailAddress=noreply@lindenlab.com\n" " Subject Public Key Info:\n" " Public Key Algorithm: rsaEncryption\n" - " Public-Key: (2048 bit)\n" + " Public-Key: (4096 bit)\n" " Modulus:\n" - " 00:bf:a1:1c:76:82:4a:10:1d:25:0e:02:e2:7a:64:\n" - " 54:c7:94:c5:c0:98:d5:35:f3:cb:cb:30:ba:31:9c:\n" - " bd:4c:2f:4a:4e:24:03:4b:87:5c:c1:5c:fe:d9:89:\n" - " 3b:cb:01:bc:eb:a5:b7:78:dc:b3:58:e5:78:a7:15:\n" - " 34:50:30:aa:16:3a:b2:94:17:6d:1e:7f:b2:70:1e:\n" - " 96:41:bb:1d:e3:22:80:fa:dc:00:6a:fb:34:3e:67:\n" - " e7:c2:21:2f:1b:d3:af:04:49:91:eb:bb:60:e0:26:\n" - " 52:75:28:8a:08:5b:91:56:4e:51:50:40:51:70:af:\n" - " cb:80:66:c8:59:e9:e2:48:a8:62:d0:26:67:80:0a:\n" - " 12:16:d1:f6:15:9e:1f:f5:92:37:f3:c9:2f:03:9e:\n" - " 22:f6:60:5a:76:45:8c:01:2c:99:54:72:19:db:b7:\n" - " 72:e6:5a:69:f3:e9:31:65:5d:0f:c7:5c:9c:17:29:\n" - " 71:14:7f:db:47:c9:1e:65:a2:41:b0:2f:14:17:ec:\n" - " 4b:25:f2:43:8f:b4:a3:8d:37:1a:07:34:b3:29:bb:\n" - " 8a:44:8e:84:08:a2:1b:76:7a:cb:c2:39:2f:6e:e3:\n" - " fc:d6:91:b5:1f:ce:58:91:57:70:35:6e:25:a9:48:\n" - " 0e:07:cf:4e:dd:16:42:65:cf:8a:42:b3:27:e6:fe:\n" - " 6a:e3\n" + " 00:d8:ac:0c:27:8f:ea:c0:4d:21:e4:75:55:31:57:\n" + " 83:46:47:14:1e:f5:67:ae:98:60:c4:97:6d:e8:53:\n" + " f2:4d:3b:ec:6f:08:bc:1e:c0:e2:a6:75:b5:90:1d:\n" + " 30:a2:59:68:32:10:2b:29:67:fc:99:f1:24:6a:36:\n" + " 73:60:31:6b:c7:a0:b8:b0:38:60:b1:59:23:2c:ab:\n" + " 25:a2:c8:b0:bc:2c:c6:d7:4c:87:37:1b:5e:51:a4:\n" + " 63:3e:c4:6d:ed:da:5e:d3:ad:8a:6d:52:e4:87:38:\n" + " 33:76:cf:f2:86:58:b3:10:a4:91:8d:3d:4f:27:9a:\n" + " 8b:b4:d7:67:90:31:1c:f5:7f:78:af:6f:f2:dd:39:\n" + " d0:16:16:7b:46:ad:88:1b:3b:74:6b:10:29:8b:64:\n" + " ba:ed:9f:a7:69:99:55:8f:73:0d:18:a3:7f:40:20:\n" + " 3a:41:4a:94:39:62:8b:fe:c6:9d:79:d0:cd:1c:e2:\n" + " d4:74:bb:43:75:eb:86:8b:30:c1:8d:cc:14:ab:75:\n" + " 2e:f5:3e:0c:05:cb:e4:c3:92:d8:81:8c:df:a5:4e:\n" + " 2e:0b:ae:17:15:9b:e6:dd:9e:16:46:42:27:92:8a:\n" + " 0e:3a:74:1e:d1:3f:ee:7e:a5:d7:ec:1c:63:d4:96:\n" + " 5b:36:f9:15:ee:da:66:ac:5e:de:91:d9:08:24:fb:\n" + " 5d:fc:9b:77:dd:ff:20:a6:67:6f:48:41:5e:5a:ac:\n" + " 13:a4:2c:2a:f2:a3:15:86:e2:84:33:34:e3:91:27:\n" + " 8b:37:ba:b0:c7:5e:1a:0d:b9:f2:4e:0c:55:e6:bb:\n" + " d9:63:f5:05:7b:aa:19:e5:57:ce:a5:b1:46:4b:b3:\n" + " 04:f6:a0:97:26:ed:48:ed:97:93:a6:75:b1:a3:42:\n" + " fc:cc:57:89:da:44:e9:16:a6:30:2c:01:8e:f2:ed:\n" + " be:45:05:08:8a:af:1e:07:51:89:cf:51:4c:aa:f3:\n" + " b3:f0:6f:db:21:80:11:32:0a:23:e2:ff:cc:59:15:\n" + " eb:ff:d2:b8:d6:a1:c1:b4:96:12:82:bf:3f:68:ad:\n" + " c8:61:50:f8:88:4f:d0:be:8e:29:64:1a:16:a5:d9:\n" + " 29:76:16:cd:70:37:c4:f2:1f:4e:c6:57:36:dd:c1:\n" + " 27:19:72:ef:98:7e:34:25:3f:76:b1:ea:15:b2:38:\n" + " 6e:d3:43:03:7a:2b:78:91:9a:19:26:2a:31:b7:5e:\n" + " b7:22:c4:fd:bf:93:10:a4:23:3f:d7:79:53:28:5d:\n" + " 2e:ba:0c:b0:5e:0a:b4:c4:a1:71:75:88:1b:b2:0e:\n" + " 2c:67:08:7b:f0:f6:37:d3:aa:39:50:03:a3:7c:17:\n" + " 1d:52:52:2a:6b:d0:a2:54:2e:ba:11:bc:26:a9:16:\n" + " a6:1b:79\n" " Exponent: 65537 (0x10001)\n" " X509v3 extensions:\n" - " X509v3 Basic Constraints: \n" + " X509v3 Basic Constraints:\n" " CA:FALSE\n" - " Netscape Cert Type: \n" - " SSL Server\n" - " Netscape Comment: \n" - " OpenSSL Generated Server Certificate\n" - " X509v3 Subject Key Identifier: \n" - " BB:59:9F:DE:6B:51:A7:6C:B3:6D:5B:8B:42:F7:B1:65:77:17:A4:E4\n" - " X509v3 Authority Key Identifier: \n" - " keyid:83:21:DE:EC:C0:79:03:6D:1E:83:F3:E5:97:29:D5:5A:C0:96:40:FA\n" - " DirName:/C=US/ST=California/L=San Francisco/O=Linden Lab/OU=Second Life Engineering/CN=Integration Test Root CA/emailAddress=noreply@lindenlab.com\n" - " serial:10:00\n" - "\n" - " X509v3 Key Usage: critical\n" + " X509v3 Key Usage:\n" " Digital Signature, Key Encipherment\n" - " X509v3 Extended Key Usage: \n" + " X509v3 Extended Key Usage:\n" " TLS Web Server Authentication\n" + " X509v3 Subject Key Identifier:\n" + " 7B:1A:F9:2B:C4:B2:F6:AE:D6:F2:8E:B1:73:FB:DD:11:CA:DB:F8:87\n" + " X509v3 Authority Key Identifier:\n" + " keyid:56:98:DC:45:25:11:E2:8C:2B:EA:D6:C6:E2:C8:BE:2C:C8:69:FF:FF\n" + " DirName:/C=US/ST=California/L=San Francisco/O=Linden Lab/OU=Second Life Engineering/CN=Integration Test Root CA/emailAddress=noreply@lindenlab.com\n" + " serial:85:BB:4B:66:26:DB:9A:C6\n" " Signature Algorithm: sha256WithRSAEncryption\n" - " 18:a6:58:55:9b:d4:af:7d:8a:27:d3:28:3a:4c:4b:42:4e:f0:\n" - " 30:d6:d9:95:11:48:12:0a:96:40:d9:2b:21:39:c5:d4:8d:e5:\n" - " 10:bc:68:78:69:0b:9f:15:4a:0b:f1:ab:99:45:0c:20:5f:27:\n" - " df:e7:14:2d:4a:30:f2:c2:8d:37:73:36:1a:27:55:5a:08:5f:\n" - " 71:a1:5e:05:83:b2:59:fe:02:5e:d7:4a:30:15:23:58:04:cf:\n" - " 48:cc:b0:71:88:9c:6b:57:f0:04:0a:d3:a0:64:6b:ee:f3:5f:\n" - " ea:ac:e1:2b:b9:7f:79:b8:db:ce:72:48:72:db:c8:5c:38:72:\n" - " 31:55:d0:ff:6b:bd:73:23:a7:30:18:5d:ed:47:18:0a:67:8e:\n" - " 53:32:0e:99:9b:96:72:45:7f:c6:00:2c:5d:1a:97:53:75:3a:\n" - " 0b:49:3d:3a:00:37:14:67:0c:28:97:34:87:aa:c5:32:e4:ae:\n" - " 34:83:12:4a:10:f7:0e:74:d4:5f:73:bd:ef:0c:b7:d8:0a:7d:\n" - " 8e:8d:5a:48:bd:f4:8e:7b:f9:4a:15:3b:61:c9:5e:40:59:6e:\n" - " c7:a8:a4:02:28:72:c5:54:8c:77:f4:55:a7:86:c0:38:a0:68:\n" - " 19:da:0f:72:5a:a9:7e:69:9f:9c:3a:d6:66:aa:e1:f4:fd:f9:\n" - " b8:4b:6c:71:9e:f0:38:02:c7:6a:9e:dc:e6:fb:ef:23:59:4f:\n" - " 5c:84:0a:df:ea:86:1f:fd:0e:5c:fa:c4:e5:50:1c:10:cf:89:\n" - " 4e:08:0e:4c:4b:61:1a:49:12:f7:e9:4b:17:71:43:7b:6d:b6:\n" - " b5:9f:d4:3b:c7:88:53:48:63:b6:00:80:8f:49:0a:c5:7e:58:\n" - " ac:78:d8:b9:06:b0:bc:86:e2:2e:48:5b:c3:24:fa:aa:72:d8:\n" - " ec:f6:c7:91:9f:0f:c8:b5:fd:2b:b2:a7:bc:2f:40:20:2b:47:\n" - " e0:d1:1d:94:52:6f:6b:be:12:b6:8c:dc:11:db:71:e6:19:ef:\n" - " a8:71:8b:ad:d3:32:c0:1c:a4:3f:b3:0f:af:e5:50:e1:ff:41:\n" - " a4:b7:6f:57:71:af:fd:16:4c:e8:24:b3:99:1b:cf:12:8f:43:\n" - " 05:80:ba:18:19:0a:a5:ec:49:81:41:4c:7e:28:b2:21:f2:59:\n" - " 6e:4a:ed:de:f9:fa:99:85:60:1f:e6:c2:42:5c:08:00:3c:84:\n" - " 06:a9:24:d4:cf:7b:6e:1b:59:1d:f4:70:16:03:a1:e0:0b:00:\n" - " 95:5c:39:03:fc:9d:1c:8e:f7:59:0c:61:47:f6:7f:07:22:48:\n" - " 83:40:ac:e1:98:5f:c7:be:05:d5:29:2b:bf:0d:03:0e:e9:5e:\n" - " 2b:dd:09:18:fe:5e:30:61\n" + " ad:7c:50:12:24:62:62:83:e9:dd:81:1a:12:1c:6d:ae:1e:a6:\n" + " 01:cc:93:8b:ac:83:7c:3d:57:d7:7f:d2:13:40:82:c7:27:07:\n" + " 31:d8:c4:01:04:64:9c:dc:ae:7b:52:bd:f5:62:7a:d0:7c:13:\n" + " 1a:19:86:6a:ce:9a:ba:69:07:77:75:b6:67:56:d0:c3:8d:6f:\n" + " 59:5f:ac:31:83:32:2c:4f:8c:85:8c:f3:56:5b:e0:83:16:19:\n" + " c9:55:4d:56:2c:e0:06:f8:71:85:4b:7e:c6:20:b3:f6:5b:85:\n" + " 6a:b7:0f:0e:0c:75:38:6a:aa:53:cc:b0:bf:c1:fd:a1:01:8a:\n" + " 7e:5a:0b:4d:51:fc:1b:14:b0:8d:62:17:b7:5d:6a:64:30:80:\n" + " aa:50:9a:23:9e:19:46:11:9d:49:d1:35:81:87:80:8c:9c:71:\n" + " 61:26:07:23:5d:a7:ea:4e:0c:53:77:bd:eb:18:6d:63:8b:2c:\n" + " e1:83:bb:bb:f8:3e:7c:e8:0d:19:1e:be:35:aa:99:0f:c7:25:\n" + " 0c:a8:f9:74:02:c8:4c:8e:bb:13:18:fd:aa:21:34:bc:2d:9f:\n" + " 10:96:e2:99:e3:9a:d7:91:0e:1e:77:20:70:e9:b4:63:25:f8:\n" + " ea:14:1f:24:b0:6a:8b:2a:f4:61:b1:0d:7d:18:bc:1d:6d:04:\n" + " 11:b2:9f:a2:a7:55:be:2b:2c:2f:c1:d8:95:13:73:af:1c:96:\n" + " 49:30:9c:9c:94:81:6c:9b:a7:87:5c:cf:46:95:95:4a:6f:bf:\n" + " df:c9:3d:74:3e:24:6e:44:1e:14:8b:68:23:e4:00:b5:a5:b7:\n" + " 5b:a9:ea:16:5f:fa:b1:d3:1a:b1:9b:36:ef:a4:7a:6f:a3:b0:\n" + " 97:35:ac:70:c0:cc:8e:a2:d3:40:0e:c1:70:0b:d5:ce:cd:51:\n" + " 82:8a:40:72:04:8d:62:af:ba:a8:e7:a8:e9:b9:99:b7:5c:5d:\n" + " 27:96:b2:3d:f9:0d:26:8c:3f:db:ac:86:97:be:f1:2c:0b:ca:\n" + " 90:07:93:96:f4:75:c3:e8:4c:f6:a8:a2:3f:da:11:21:e7:b1:\n" + " 8c:62:36:ae:91:a9:2a:73:ba:67:f5:24:16:c3:ee:b7:b1:b4:\n" + " e3:8a:28:23:84:cf:38:c6:f0:8e:21:f6:b8:76:9a:6d:d1:e3:\n" + " 74:81:7a:22:20:a0:82:2a:31:8a:ba:44:0b:61:5a:aa:ba:c6:\n" + " 07:99:36:0a:24:06:2f:8e:c1:1c:4b:f0:65:72:fb:e9:b5:31:\n" + " 59:13:2c:c6:f8:5b:91:e2:d8:96:f3:1a:06:0b:2a:62:12:4d:\n" + " 5e:65:c9:e9:e4:00:99:a6:d3:60:1f:c3:d6:cc:a6:9b:a5:14:\n" + " 1b:4d:db:e7:3d:52:7e:2c\n" "-----BEGIN CERTIFICATE-----\n" - "MIIGbjCCBFagAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgaoxCzAJBgNVBAYTAlVT\n" - "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRMwEQYDVQQKDApMaW5kZW4gTGFiMSAwHgYD\n" - "VQQLDBdTZWNvbmQgTGlmZSBFbmdpbmVlcmluZzEpMCcGA1UEAwwgSW50ZWdyYXRp\n" - "b24gVGVzdCBJbnRlcm1lZGlhdGUgQ0ExJDAiBgkqhkiG9w0BCQEWFW5vcmVwbHlA\n" - "bGluZGVubGFiLmNvbTAeFw0xODA1MjIyMjU4MTVaFw0yNDA3MTkyMjU4MTVaMIG+\n" - "MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu\n" - "IEZyYW5jaXNjbzETMBEGA1UECgwKTGluZGVuIExhYjEgMB4GA1UECwwXU2Vjb25k\n" - "IExpZmUgRW5naW5lZXJpbmcxJTAjBgNVBAMMHEludGVncmF0aW9uIFRlc3QgU2Vy\n" - "dmVyIENlcnQxJDAiBgkqhkiG9w0BCQEWFW5vcmVwbHlAbGluZGVubGFiLmNvbTCC\n" - "ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+hHHaCShAdJQ4C4npkVMeU\n" - "xcCY1TXzy8swujGcvUwvSk4kA0uHXMFc/tmJO8sBvOult3jcs1jleKcVNFAwqhY6\n" - "spQXbR5/snAelkG7HeMigPrcAGr7ND5n58IhLxvTrwRJkeu7YOAmUnUoighbkVZO\n" - "UVBAUXCvy4BmyFnp4kioYtAmZ4AKEhbR9hWeH/WSN/PJLwOeIvZgWnZFjAEsmVRy\n" - "Gdu3cuZaafPpMWVdD8dcnBcpcRR/20fJHmWiQbAvFBfsSyXyQ4+0o403Ggc0sym7\n" - "ikSOhAiiG3Z6y8I5L27j/NaRtR/OWJFXcDVuJalIDgfPTt0WQmXPikKzJ+b+auMC\n" - "AwEAAaOCAYYwggGCMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCG\n" - "SAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUw\n" - "HQYDVR0OBBYEFLtZn95rUadss21bi0L3sWV3F6TkMIHoBgNVHSMEgeAwgd2AFIMh\n" - "3uzAeQNtHoPz5Zcp1VrAlkD6oYHApIG9MIG6MQswCQYDVQQGEwJVUzETMBEGA1UE\n" - "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzETMBEGA1UECgwK\n" - "TGluZGVuIExhYjEgMB4GA1UECwwXU2Vjb25kIExpZmUgRW5naW5lZXJpbmcxITAf\n" - "BgNVBAMMGEludGVncmF0aW9uIFRlc3QgUm9vdCBDQTEkMCIGCSqGSIb3DQEJARYV\n" - "bm9yZXBseUBsaW5kZW5sYWIuY29tggIQADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0l\n" - "BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggIBABimWFWb1K99iifTKDpM\n" - "S0JO8DDW2ZURSBIKlkDZKyE5xdSN5RC8aHhpC58VSgvxq5lFDCBfJ9/nFC1KMPLC\n" - "jTdzNhonVVoIX3GhXgWDsln+Al7XSjAVI1gEz0jMsHGInGtX8AQK06Bka+7zX+qs\n" - "4Su5f3m4285ySHLbyFw4cjFV0P9rvXMjpzAYXe1HGApnjlMyDpmblnJFf8YALF0a\n" - "l1N1OgtJPToANxRnDCiXNIeqxTLkrjSDEkoQ9w501F9zve8Mt9gKfY6NWki99I57\n" - "+UoVO2HJXkBZbseopAIocsVUjHf0VaeGwDigaBnaD3JaqX5pn5w61maq4fT9+bhL\n" - "bHGe8DgCx2qe3Ob77yNZT1yECt/qhh/9Dlz6xOVQHBDPiU4IDkxLYRpJEvfpSxdx\n" - "Q3tttrWf1DvHiFNIY7YAgI9JCsV+WKx42LkGsLyG4i5IW8Mk+qpy2Oz2x5GfD8i1\n" - "/Suyp7wvQCArR+DRHZRSb2u+EraM3BHbceYZ76hxi63TMsAcpD+zD6/lUOH/QaS3\n" - "b1dxr/0WTOgks5kbzxKPQwWAuhgZCqXsSYFBTH4osiHyWW5K7d75+pmFYB/mwkJc\n" - "CAA8hAapJNTPe24bWR30cBYDoeALAJVcOQP8nRyO91kMYUf2fwciSINArOGYX8e+\n" - "BdUpK78NAw7pXivdCRj+XjBh\n" + "MIIHSTCCBTGgAwIBAgIJAJ6NNBPnm/kxMA0GCSqGSIb3DQEBCwUAMIHCMQswCQYD\n" + "VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\n" + "aXNjbzETMBEGA1UECgwKTGluZGVuIExhYjEgMB4GA1UECwwXU2Vjb25kIExpZmUg\n" + "RW5naW5lZXJpbmcxKTAnBgNVBAMMIEludGVncmF0aW9uIFRlc3QgSW50ZXJtZWRp\n" + "YXRlIENBMSQwIgYJKoZIhvcNAQkBFhVub3JlcGx5QGxpbmRlbmxhYi5jb20wHhcN\n" + "MjQwNzIzMTE0NjM5WhcNMzQwNzIxMTE0NjM5WjCBvjELMAkGA1UEBhMCVVMxEzAR\n" + "BgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNV\n" + "BAoMCkxpbmRlbiBMYWIxIDAeBgNVBAsMF1NlY29uZCBMaWZlIEVuZ2luZWVyaW5n\n" + "MSUwIwYDVQQDDBxJbnRlZ3JhdGlvbiBUZXN0IFNlcnZlciBDZXJ0MSQwIgYJKoZI\n" + "hvcNAQkBFhVub3JlcGx5QGxpbmRlbmxhYi5jb20wggIiMA0GCSqGSIb3DQEBAQUA\n" + "A4ICDwAwggIKAoICAQDYrAwnj+rATSHkdVUxV4NGRxQe9WeumGDEl23oU/JNO+xv\n" + "CLwewOKmdbWQHTCiWWgyECspZ/yZ8SRqNnNgMWvHoLiwOGCxWSMsqyWiyLC8LMbX\n" + "TIc3G15RpGM+xG3t2l7TrYptUuSHODN2z/KGWLMQpJGNPU8nmou012eQMRz1f3iv\n" + "b/LdOdAWFntGrYgbO3RrECmLZLrtn6dpmVWPcw0Yo39AIDpBSpQ5Yov+xp150M0c\n" + "4tR0u0N164aLMMGNzBSrdS71PgwFy+TDktiBjN+lTi4LrhcVm+bdnhZGQieSig46\n" + "dB7RP+5+pdfsHGPUlls2+RXu2masXt6R2Qgk+138m3fd/yCmZ29IQV5arBOkLCry\n" + "oxWG4oQzNOORJ4s3urDHXhoNufJODFXmu9lj9QV7qhnlV86lsUZLswT2oJcm7Ujt\n" + "l5OmdbGjQvzMV4naROkWpjAsAY7y7b5FBQiKrx4HUYnPUUyq87Pwb9shgBEyCiPi\n" + "/8xZFev/0rjWocG0lhKCvz9orchhUPiIT9C+jilkGhal2Sl2Fs1wN8TyH07GVzbd\n" + "wScZcu+YfjQlP3ax6hWyOG7TQwN6K3iRmhkmKjG3XrcixP2/kxCkIz/XeVMoXS66\n" + "DLBeCrTEoXF1iBuyDixnCHvw9jfTqjlQA6N8Fx1SUipr0KJULroRvCapFqYbeQID\n" + "AQABo4IBQjCCAT4wCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYI\n" + "KwYBBQUHAwEwHQYDVR0OBBYEFHsa+SvEsvau1vKOsXP73RHK2/iHMIHvBgNVHSME\n" + "gecwgeSAFFaY3EUlEeKMK+rWxuLIvizIaf//oYHApIG9MIG6MQswCQYDVQQGEwJV\n" + "UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzET\n" + "MBEGA1UECgwKTGluZGVuIExhYjEgMB4GA1UECwwXU2Vjb25kIExpZmUgRW5naW5l\n" + "ZXJpbmcxITAfBgNVBAMMGEludGVncmF0aW9uIFRlc3QgUm9vdCBDQTEkMCIGCSqG\n" + "SIb3DQEJARYVbm9yZXBseUBsaW5kZW5sYWIuY29tggkAhbtLZibbmsYwDQYJKoZI\n" + "hvcNAQELBQADggIBAK18UBIkYmKD6d2BGhIcba4epgHMk4usg3w9V9d/0hNAgscn\n" + "BzHYxAEEZJzcrntSvfVietB8ExoZhmrOmrppB3d1tmdW0MONb1lfrDGDMixPjIWM\n" + "81Zb4IMWGclVTVYs4Ab4cYVLfsYgs/ZbhWq3Dw4MdThqqlPMsL/B/aEBin5aC01R\n" + "/BsUsI1iF7ddamQwgKpQmiOeGUYRnUnRNYGHgIyccWEmByNdp+pODFN3vesYbWOL\n" + "LOGDu7v4PnzoDRkevjWqmQ/HJQyo+XQCyEyOuxMY/aohNLwtnxCW4pnjmteRDh53\n" + "IHDptGMl+OoUHySwaosq9GGxDX0YvB1tBBGyn6KnVb4rLC/B2JUTc68clkkwnJyU\n" + "gWybp4dcz0aVlUpvv9/JPXQ+JG5EHhSLaCPkALWlt1up6hZf+rHTGrGbNu+kem+j\n" + "sJc1rHDAzI6i00AOwXAL1c7NUYKKQHIEjWKvuqjnqOm5mbdcXSeWsj35DSaMP9us\n" + "hpe+8SwLypAHk5b0dcPoTPaooj/aESHnsYxiNq6RqSpzumf1JBbD7rextOOKKCOE\n" + "zzjG8I4h9rh2mm3R43SBeiIgoIIqMYq6RAthWqq6xgeZNgokBi+OwRxL8GVy++m1\n" + "MVkTLMb4W5Hi2JbzGgYLKmISTV5lyenkAJmm02Afw9bMppulFBtN2+c9Un4s\n" "-----END CERTIFICATE-----\n" - ); + ); + // Test wrapper declaration : wrapping nothing for the moment struct sechandler_basic_test @@ -701,14 +722,13 @@ namespace tut //std::ostringstream llsd_value; //llsd_value << LLSDOStreamer<LLSDNotationFormatter>(llsd_cert) << std::endl; LL_DEBUGS() << "test 1 cert " << llsd_cert << LL_ENDL; - ensure_equals("Issuer Name/commonName", (std::string)llsd_cert["issuer_name"]["commonName"], "Integration Test Intermediate CA"); ensure_equals("Issuer Name/countryName", (std::string)llsd_cert["issuer_name"]["countryName"], "US"); ensure_equals("Issuer Name/state", (std::string)llsd_cert["issuer_name"]["stateOrProvinceName"], "California"); ensure_equals("Issuer Name/org name", (std::string)llsd_cert["issuer_name"]["organizationName"], "Linden Lab"); ensure_equals("Issuer Name/org unit", (std::string)llsd_cert["issuer_name"]["organizationalUnitName"], "Second Life Engineering"); ensure_equals("Issuer name string", (std::string)llsd_cert["issuer_name_string"], - "emailAddress=noreply@lindenlab.com,CN=Integration Test Intermediate CA,OU=Second Life Engineering,O=Linden Lab,ST=California,C=US"); + "emailAddress=noreply@lindenlab.com,CN=Integration Test Intermediate CA,OU=Second Life Engineering,O=Linden Lab,L=San Francisco,ST=California,C=US"); ensure_equals("subject Name/commonName", (std::string)llsd_cert["subject_name"]["commonName"], "Integration Test Server Cert"); ensure_equals("subject Name/countryName", (std::string)llsd_cert["subject_name"]["countryName"], "US"); @@ -721,9 +741,9 @@ namespace tut ensure_equals("subject name string", (std::string)llsd_cert["subject_name_string"], "emailAddress=noreply@lindenlab.com,CN=Integration Test Server Cert,OU=Second Life Engineering,O=Linden Lab,L=San Francisco,ST=California,C=US"); - ensure_equals("serial number", (std::string)llsd_cert["serial_number"], "1000"); - ensure_equals("valid from", (std::string)llsd_cert["valid_from"], "2018-05-22T22:58:15Z"); - ensure_equals("valid to", (std::string)llsd_cert["valid_to"], "2024-07-19T22:58:15Z"); + ensure_equals("serial number", (std::string)llsd_cert["serial_number"], "9E8D3413E79BF931"); + ensure_equals("valid from", (std::string)llsd_cert["valid_from"], "2024-07-23T11:46:39Z"); + ensure_equals("valid to", (std::string)llsd_cert["valid_to"], "2034-07-21T11:46:39Z"); LLSD expectedKeyUsage = LLSD::emptyArray(); expectedKeyUsage.append(LLSD((std::string)"digitalSignature")); expectedKeyUsage.append(LLSD((std::string)"keyEncipherment")); @@ -1042,7 +1062,7 @@ namespace tut //validate find LLSD find_info = LLSD::emptyMap(); - find_info["subjectKeyIdentifier"] = "bb:59:9f:de:6b:51:a7:6c:b3:6d:5b:8b:42:f7:b1:65:77:17:a4:e4"; + find_info["subjectKeyIdentifier"] = "7b:1a:f9:2b:c4:b2:f6:ae:d6:f2:8e:b1:73:fb:dd:11:ca:db:f8:87"; LLBasicCertificateVector::iterator found_cert = test_vector->find(find_info); ensure("found some cert", found_cert != test_vector->end()); X509* found_x509 = (*found_cert).get()->getOpenSSLX509(); @@ -1225,7 +1245,7 @@ namespace tut X509_STORE_CTX_set0_untrusted(test_store, NULL); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store", test_chain->size(), 1); + ensure_equals("two elements in store [1]", test_chain->size(), 1); X509* test_cert = (*test_chain)[0]->getOpenSSLX509(); ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); @@ -1238,7 +1258,7 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store", test_chain->size(), 2); + ensure_equals("two elements in store [2]", test_chain->size(), 2); test_cert = (*test_chain)[0]->getOpenSSLX509(); ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); @@ -1254,7 +1274,7 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store", test_chain->size(), 1); + ensure_equals("two elements in store [3]", test_chain->size(), 1); test_cert = (*test_chain)[0]->getOpenSSLX509(); ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); @@ -1267,7 +1287,7 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store", test_chain->size(), 2); + ensure_equals("two elements in store [4]", test_chain->size(), 2); test_cert = (*test_chain)[0]->getOpenSSLX509(); ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); -- cgit v1.2.3 From ffeb738afda99fca98a9c1ba7704d7f6144da70c Mon Sep 17 00:00:00 2001 From: nat-goodspeed <nat@lindenlab.com> Date: Wed, 31 Jul 2024 06:30:19 -0400 Subject: Represent the many "LLAgent" "setCameraParams" args in an array. This encapsulates the boilerplate associated with passing each distinct parameter to its corresponding LLFollowCamMgr method. --- indra/newview/llagentlistener.cpp | 106 +++++++++++----------- indra/newview/scripts/lua/test_camera_control.lua | 2 +- 2 files changed, 55 insertions(+), 53 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 045367dbdd..80460666a5 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -45,6 +45,7 @@ #include "lltoolgrab.h" #include "llhudeffectlookat.h" #include "llagentcamera.h" +#include <functional> LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -522,62 +523,63 @@ void LLAgentListener::getGroups(const LLSD& event) const sendReply(LLSDMap("groups", reply), event); } +/*----------------------------- camera control -----------------------------*/ +// specialize LLSDParam to support (const LLVector3&) arguments -- this +// wouldn't even be necessary except that the relevant LLVector3 constructor +// is explicitly explicit +template <> +class LLSDParam<const LLVector3&>: public LLSDParamBase +{ +public: + LLSDParam(const LLSD& value): value(LLVector3(value)) {} + + operator const LLVector3&() const { return value; } + +private: + LLVector3 value; +}; + +// accept any of a number of similar LLFollowCamMgr methods with different +// argument types, and return a wrapper lambda that accepts LLSD and converts +// to the target argument type +template <typename T> +auto wrap(void (LLFollowCamMgr::*method)(const LLUUID& source, T arg)) +{ + return [method](LLFollowCamMgr& followcam, const LLUUID& source, const LLSD& arg) + { (followcam.*method)(source, LLSDParam<T>(arg)); }; +} + +// table of supported LLFollowCamMgr methods, +// with the corresponding setFollowCamParams() argument keys +static std::pair<std::string, std::function<void(LLFollowCamMgr&, const LLUUID&, const LLSD&)>> +cam_params[] = +{ + { "camera_pos", wrap(&LLFollowCamMgr::setPosition) }, + { "focus_pos", wrap(&LLFollowCamMgr::setFocus) }, + { "focus_offset", wrap(&LLFollowCamMgr::setFocusOffset) }, + { "camera_locked", wrap(&LLFollowCamMgr::setPositionLocked) }, + { "focus_locked", wrap(&LLFollowCamMgr::setFocusLocked) }, + { "distance", wrap(&LLFollowCamMgr::setDistance) }, + { "focus_threshold", wrap(&LLFollowCamMgr::setFocusThreshold) }, + { "camera_threshold", wrap(&LLFollowCamMgr::setPositionThreshold) }, + { "focus_lag", wrap(&LLFollowCamMgr::setFocusLag) }, + { "camera_lag", wrap(&LLFollowCamMgr::setPositionLag) }, + { "camera_pitch", wrap(&LLFollowCamMgr::setPitch) }, + { "behindness_lag", wrap(&LLFollowCamMgr::setBehindnessLag) }, + { "behindness_angle", wrap(&LLFollowCamMgr::setBehindnessAngle) }, +}; + void LLAgentListener::setFollowCamParams(const LLSD& event) const { - if (event.has("camera_pos")) + auto& followcam{ LLFollowCamMgr::instance() }; + for (const auto& pair : cam_params) { - LLFollowCamMgr::getInstance()->setPosition(gAgentID, LLVector3(event["camera_pos"])); - } - if (event.has("focus_pos")) - { - LLFollowCamMgr::getInstance()->setFocus(gAgentID, LLVector3(event["focus_pos"])); - } - if (event.has("focus_offset")) - { - LLFollowCamMgr::getInstance()->setFocusOffset(gAgentID, LLVector3(event["focus_offset"])); - } - if (event.has("camera_locked")) - { - LLFollowCamMgr::getInstance()->setPositionLocked(gAgentID, event["camera_locked"]); - } - if (event.has("focus_locked")) - { - LLFollowCamMgr::getInstance()->setFocusLocked(gAgentID, event["focus_locked"]); - } - if (event.has("distance")) - { - LLFollowCamMgr::getInstance()->setDistance(gAgentID, event["distance"].asReal()); - } - if (event.has("focus_threshold")) - { - LLFollowCamMgr::getInstance()->setFocusThreshold(gAgentID, event["focus_threshold"].asReal()); - } - if (event.has("camera_threshold")) - { - LLFollowCamMgr::getInstance()->setPositionThreshold(gAgentID, event["camera_threshold"].asReal()); - } - if (event.has("focus_lag")) - { - LLFollowCamMgr::getInstance()->setFocusLag(gAgentID, event["focus_lag"].asReal()); - } - if (event.has("camera_lag")) - { - LLFollowCamMgr::getInstance()->setPositionLag(gAgentID, event["camera_lag"].asReal()); - } - if (event.has("camera_pitch")) - { - LLFollowCamMgr::getInstance()->setPitch(gAgentID, event["camera_pitch"].asReal()); - } - if (event.has("behindness_lag")) - { - LLFollowCamMgr::getInstance()->setBehindnessLag(gAgentID, event["behindness_lag"].asReal()); - } - if (event.has("behindness_angle")) - { - LLFollowCamMgr::getInstance()->setBehindnessAngle(gAgentID, event["behindness_angle"].asReal()); + if (event.has(pair.first)) + { + pair.second(followcam, gAgentID, event[pair.first]); + } } - - LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, true); + followcam.setCameraActive(gAgentID, true); } void LLAgentListener::setFollowCamActive(LLSD const & event) const diff --git a/indra/newview/scripts/lua/test_camera_control.lua b/indra/newview/scripts/lua/test_camera_control.lua index e7ad69b473..9b35cdf8cd 100644 --- a/indra/newview/scripts/lua/test_camera_control.lua +++ b/indra/newview/scripts/lua/test_camera_control.lua @@ -45,5 +45,5 @@ function flt:commit_reset_btn(event_data) LLAgent.setFollowCamActive(false) end -startup.wait('STATE_LOGIN_WAIT') +startup.wait('STATE_STARTED') flt:show() -- cgit v1.2.3 From fdb7207aa0d1f25ed3e14fbc4e8615e8383e508c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 1 Aug 2024 16:52:44 -0400 Subject: Add UI.callables() and corresponding entry point. --- indra/newview/lluilistener.cpp | 43 ++++++++++++++++++++++++++++ indra/newview/lluilistener.h | 1 + indra/newview/scripts/lua/require/UI.lua | 6 ++++ indra/newview/scripts/lua/test_callables.lua | 6 ++++ 4 files changed, 56 insertions(+) create mode 100644 indra/newview/scripts/lua/test_callables.lua (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index c73c93859a..2b2187a73b 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -55,6 +55,13 @@ LLUIListener::LLUIListener(): &LLUIListener::call, llsd::map("function", LLSD(), "reply", LLSD())); + add("callables", + "Return a list [\"callables\"] of dicts {name, access} of functions registered to\n" + "invoke with \"call\".\n" + "access has values \"allow\", \"block\" or \"throttle\".", + &LLUIListener::callables, + llsd::map("reply", LLSD::String())); + add("getValue", "For the UI control identified by the path in [\"path\"], return the control's\n" "current value as [\"value\"] reply.", @@ -131,6 +138,42 @@ void LLUIListener::call(const LLSD& event) (info->callback_func)(NULL, event["parameter"]); } +void LLUIListener::callables(const LLSD& event) const +{ + Response response(LLSD(), event); + + using Registry = LLUICtrl::CommitCallbackRegistry; + using Method = Registry::Registrar& (*)(); + static Method registrars[] = + { + &Registry::defaultRegistrar, + &Registry::currentRegistrar, + }; + LLSD list; + for (auto method : registrars) + { + auto& registrar{ (*method)() }; + for (auto it = registrar.beginItems(), end = registrar.endItems(); it != end; ++it) + { + LLSD entry{ llsd::map("name", it->first) }; + switch (it->second.handle_untrusted) + { + case LLUICtrl::CommitCallbackInfo::UNTRUSTED_ALLOW: + entry["access"] = "allow"; + break; + case LLUICtrl::CommitCallbackInfo::UNTRUSTED_BLOCK: + entry["access"] = "block"; + break; + case LLUICtrl::CommitCallbackInfo::UNTRUSTED_THROTTLE: + entry["access"] = "throttle"; + break; + } + list.append(entry); + } + } + response["callables"] = list; +} + void LLUIListener::getValue(const LLSD&event) const { Response response(LLSD(), event); diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index cbb5014300..c90253ab59 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -41,6 +41,7 @@ public: private: void call(const LLSD& event); + void callables(const LLSD& event) const; void getValue(const LLSD&event) const; void addMenu(const LLSD&event) const; diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 28488ff3e1..06b49c6269 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -14,6 +14,10 @@ function UI.call(func, parameter) leap.request('UI', {op='call', ['function']=func, parameter=parameter}) end +function UI.callables() + return leap.request('UI', {op='callables'}).callables +end + function UI.getValue(path) return leap.request('UI', {op='getValue', path=path})['value'] end @@ -152,6 +156,7 @@ function UI.addMenuBranch(...) return leap.request('UI', args) end +-- see UI.callables() for valid values of 'func' function UI.addMenuItem(...) local args = mapargs('name,label,parent_menu,func,param', ...) args.op = 'addMenuItem' @@ -163,4 +168,5 @@ function UI.addMenuSeparator(...) args.op = 'addMenuSeparator' return leap.request('UI', args) end + return UI diff --git a/indra/newview/scripts/lua/test_callables.lua b/indra/newview/scripts/lua/test_callables.lua new file mode 100644 index 0000000000..1bee062db8 --- /dev/null +++ b/indra/newview/scripts/lua/test_callables.lua @@ -0,0 +1,6 @@ +startup=require 'startup' +UI=require 'UI' +startup.wait('STATE_LOGIN_WAIT') +for _, cbl in pairs(UI.callables()) do + print(`{cbl.name} ({cbl.access})`) +end -- cgit v1.2.3 From c8ba633a4564da29d9b58b0e08ffb590bb3bce5f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 2 Aug 2024 10:12:57 -0400 Subject: Add 'UI' 'getParents' op to list top-menu 'parent_menu' names. --- indra/newview/lluilistener.cpp | 15 ++++++++++++++- indra/newview/lluilistener.h | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 2b2187a73b..b81859a764 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -68,6 +68,11 @@ LLUIListener::LLUIListener(): &LLUIListener::getValue, llsd::map("path", LLSD(), "reply", LLSD())); + add("getParents", + "List names of Top menus suitable for passing as \"parent_menu\"", + &LLUIListener::getParents, + llsd::map("reply", LLSD::String())); + LLSD required_args = llsd::map("name", LLSD(), "label", LLSD(), "reply", LLSD()); add("addMenu", "Add new drop-down menu [\"name\"] with displayed [\"label\"] to the Top menu.", @@ -174,7 +179,7 @@ void LLUIListener::callables(const LLSD& event) const response["callables"] = list; } -void LLUIListener::getValue(const LLSD&event) const +void LLUIListener::getValue(const LLSD& event) const { Response response(LLSD(), event); @@ -192,6 +197,14 @@ void LLUIListener::getValue(const LLSD&event) const } } +void LLUIListener::getParents(const LLSD& event) const +{ + Response response(LLSD(), event); + response["parents"] = llsd::toArray( + *gMenuBarView->getChildList(), + [](auto childp) {return childp->getName(); }); +} + LLMenuGL::Params get_params(const LLSD&event) { LLMenuGL::Params item_params; diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index c90253ab59..671eb5f29b 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -42,7 +42,8 @@ public: private: void call(const LLSD& event); void callables(const LLSD& event) const; - void getValue(const LLSD&event) const; + void getValue(const LLSD& event) const; + void getParents(const LLSD& event) const; void addMenu(const LLSD&event) const; void addMenuBranch(const LLSD&event) const; -- cgit v1.2.3 From 99307b619a5aa27bef3bb67027c4cb5e54f21ad4 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 2 Aug 2024 19:46:52 +0300 Subject: Lua api for adjusting toolbars --- indra/newview/lluilistener.cpp | 68 ++++++++++++++++++++++++++++++++ indra/newview/lluilistener.h | 6 +++ indra/newview/scripts/lua/require/UI.lua | 30 ++++++++++++++ 3 files changed, 104 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index b81859a764..6d1d5ac735 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -35,6 +35,7 @@ // external library headers // other Linden headers #include "llmenugl.h" +#include "lltoolbarview.h" #include "llui.h" // getRootView(), resolvePath() #include "lluictrl.h" #include "llerror.h" @@ -97,6 +98,32 @@ LLUIListener::LLUIListener(): "Add menu separator to the [\"parent_menu\"] within the Top menu.", &LLUIListener::addMenuSeparator, llsd::map("parent_menu", LLSD(), "reply", LLSD())); + + add("defaultToolbars", + "todo: defaultToolbars desc", + &LLUIListener::restoreDefaultToolbars); + + add("clearToolbars", + "Clear all buttons off the toolbars", + &LLUIListener::clearAllToolbars); + + add("addToolbarBtn", + "Add [\"btn_name\"] toolbar button to the [\"toolbar\"]\n" + "[1 (left toolbar), 2 (right toolbar), 3 (bottom toolbar)]\n" + "Position of the command in the original list can be specified as [\"rank\"]", + &LLUIListener::addToolbarBtn, + llsd::map("btn_name", LLSD(), "reply", LLSD())); + + add("removeToolbarBtn", + "Remove [\"btn_name\"] toolbar button off the toolbar,\n" + "return [\"rank\"] (old position) of the command in the original list", + &LLUIListener::removeToolbarBtn, + llsd::map("btn_name", LLSD(), "reply", LLSD())); + + add("getToolbarBtnNames", + "Return the table of Toolbar buttons names", + &LLUIListener::getToolbarBtnNames, + llsd::map("reply", LLSD())); } typedef LLUICtrl::CommitCallbackInfo cb_info; @@ -280,3 +307,44 @@ void LLUIListener::addMenuSeparator(const LLSD&event) const } } } + +void LLUIListener::restoreDefaultToolbars(const LLSD &event) const +{ + LLToolBarView::loadDefaultToolbars(); +} + +void LLUIListener::clearAllToolbars(const LLSD &event) const +{ + LLToolBarView::clearAllToolbars(); +} + +void LLUIListener::addToolbarBtn(const LLSD &event) const +{ + Response response(LLSD(), event); + + typedef LLToolBarEnums::EToolBarLocation ToolBarLocation; + ToolBarLocation toolbar = ToolBarLocation::TOOLBAR_BOTTOM; + if (event.has("toolbar")) + { + toolbar = llclamp((ToolBarLocation)event["toolbar"].asInteger(), ToolBarLocation::TOOLBAR_NONE, ToolBarLocation::TOOLBAR_BOTTOM); + } + S32 rank = event.has("rank") ? event["rank"].asInteger() : - 1; + if(!gToolBarView->addCommand(event["btn_name"].asString(), toolbar, rank)) + { + response.error(stringize("Toolbar button ", std::quoted(event["btn_name"].asString()), " was not found")); + } +} + +void LLUIListener::removeToolbarBtn(const LLSD &event) const +{ + Response response(LLSD(), event); + + S32 old_rank = LLToolBar::RANK_NONE; + gToolBarView->removeCommand(event["btn_name"].asString(), old_rank); + response["rank"] = old_rank; +} + +void LLUIListener::getToolbarBtnNames(const LLSD &event) const +{ + Response response(llsd::map("cmd_names", LLCommandManager::instance().getCommandNames()), event); +} diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index 671eb5f29b..f4bee00807 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -50,6 +50,12 @@ private: void addMenuItem(const LLSD&event) const; void addMenuSeparator(const LLSD&event) const; + void restoreDefaultToolbars(const LLSD &event) const; + void clearAllToolbars(const LLSD &event) const; + void addToolbarBtn(const LLSD &event) const; + void removeToolbarBtn(const LLSD &event) const; + void getToolbarBtnNames(const LLSD &event) const; + F64 mLastUntrustedThrottle {0}; F64 mLastMinThrottle {0}; }; diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 06b49c6269..30b7189c3c 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -169,4 +169,34 @@ function UI.addMenuSeparator(...) return leap.request('UI', args) end +-- *************************************************************************** +-- Toolbar buttons +-- *************************************************************************** +-- Clears all buttons off the toolbars +function UI.clearToolbars() + leap.send('UI', {op='clearToolbars'}) +end + +function UI.defaultToolbars() + leap.send('UI', {op='defaultToolbars'}) +end + +-- UI.addToolbarBtn{btn_name=btn_name +-- [, toolbar= 3] -- 1 [TOOLBAR_LEFT], 2 [TOOLBAR_RIGHT], 3 [TOOLBAR_BOTTOM] +-- [, rank=1]} -- position on the toolbar +function UI.addToolbarBtn(...) + local args = mapargs('btn_name,toolbar,rank', ...) + args.op = 'addToolbarBtn' + return leap.request('UI', args) +end + +-- Returns the rank(position) of the command in the original list +function UI.removeToolbarBtn(btn_name) + return leap.request('UI', {op = 'removeToolbarBtn', btn_name=btn_name}).rank +end + +function UI.getToolbarBtnNames() + return leap.request('UI', {op = 'getToolbarBtnNames'}).cmd_names +end + return UI -- cgit v1.2.3 From a67a01240cbd58a1800290294be83e7b874fefb6 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 2 Aug 2024 20:19:53 +0300 Subject: Lua api for showing/hiding floater; rename demo scripts --- indra/newview/lluilistener.cpp | 10 ++++++ indra/newview/lluilistener.h | 2 ++ indra/newview/scripts/lua/require/UI.lua | 23 +++++++++++++ indra/newview/scripts/lua/test_luafloater_demo.lua | 39 ++++++++++++++++++++++ .../newview/scripts/lua/test_luafloater_demo2.lua | 39 ---------------------- .../scripts/lua/test_luafloater_gesture_list.lua | 27 +++++++++++++++ .../scripts/lua/test_luafloater_gesture_list2.lua | 27 --------------- 7 files changed, 101 insertions(+), 66 deletions(-) create mode 100644 indra/newview/scripts/lua/test_luafloater_demo.lua delete mode 100644 indra/newview/scripts/lua/test_luafloater_demo2.lua create mode 100644 indra/newview/scripts/lua/test_luafloater_gesture_list.lua delete mode 100644 indra/newview/scripts/lua/test_luafloater_gesture_list2.lua (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 6d1d5ac735..07a8b45f89 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -39,6 +39,7 @@ #include "llui.h" // getRootView(), resolvePath() #include "lluictrl.h" #include "llerror.h" +#include "llviewermenufile.h" // close_all_windows() extern LLMenuBarGL* gMenuBarView; @@ -124,6 +125,10 @@ LLUIListener::LLUIListener(): "Return the table of Toolbar buttons names", &LLUIListener::getToolbarBtnNames, llsd::map("reply", LLSD())); + + add("closeAllFloaters", + "Close all the floaters", + &LLUIListener::closeAllFloaters); } typedef LLUICtrl::CommitCallbackInfo cb_info; @@ -348,3 +353,8 @@ void LLUIListener::getToolbarBtnNames(const LLSD &event) const { Response response(llsd::map("cmd_names", LLCommandManager::instance().getCommandNames()), event); } + +void LLUIListener::closeAllFloaters(const LLSD &event) const +{ + close_all_windows(); +} diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index f4bee00807..bae6724b3d 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -56,6 +56,8 @@ private: void removeToolbarBtn(const LLSD &event) const; void getToolbarBtnNames(const LLSD &event) const; + void closeAllFloaters(const LLSD &event) const; + F64 mLastUntrustedThrottle {0}; F64 mLastMinThrottle {0}; }; diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 30b7189c3c..df77eb2b56 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -199,4 +199,27 @@ function UI.getToolbarBtnNames() return leap.request('UI', {op = 'getToolbarBtnNames'}).cmd_names end +-- *************************************************************************** +-- Floaters +-- *************************************************************************** +function UI.showFloater(floater_name) + leap.send("LLFloaterReg", {op = "showInstance", name = floater_name}) +end + +function UI.hideFloater(floater_name) + leap.send("LLFloaterReg", {op = "hideInstance", name = floater_name}) +end + +function UI.toggleFloater(floater_name) + leap.send("LLFloaterReg", {op = "toggleInstance", name = floater_name}) +end + +function UI.isFloaterVisible(floater_name) + return leap.request("LLFloaterReg", {op = "instanceVisible", name = floater_name}).visible +end + +function UI.closeAllFloaters() + return leap.send("UI", {op = "closeAllFloaters"}) +end + return UI diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua new file mode 100644 index 0000000000..3903d01e65 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -0,0 +1,39 @@ +local Floater = require 'Floater' +local leap = require 'leap' +local startup = require 'startup' + +local flt = Floater( + 'luafloater_demo.xml', + {show_time_lbl = {"right_mouse_down", "double_click"}}) + +-- override base-class handleEvents() to report the event data in the floater's display field +function flt:handleEvents(event_data) + self:post({action="add_text", ctrl_name="events_editor", value = event_data}) + -- forward the call to base-class handleEvents() + return Floater.handleEvents(self, event_data) +end + +function flt:commit_disable_ctrl(event_data) + self:post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) +end + +function flt:commit_title_cmb(event_data) + self:post({action="set_title", value=event_data.value}) +end + +function flt:commit_open_btn(event_data) + floater_name = self:request({action="get_value", ctrl_name='openfloater_cmd'}).value + leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) +end + +local function getCurrentTime() + local currentTime = os.date("*t") + return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec) +end + +function flt:double_click_show_time_lbl(event_data) + self:post({action="set_value", ctrl_name="time_lbl", value=getCurrentTime()}) +end + +startup.wait('STATE_LOGIN_WAIT') +flt:show() diff --git a/indra/newview/scripts/lua/test_luafloater_demo2.lua b/indra/newview/scripts/lua/test_luafloater_demo2.lua deleted file mode 100644 index 3903d01e65..0000000000 --- a/indra/newview/scripts/lua/test_luafloater_demo2.lua +++ /dev/null @@ -1,39 +0,0 @@ -local Floater = require 'Floater' -local leap = require 'leap' -local startup = require 'startup' - -local flt = Floater( - 'luafloater_demo.xml', - {show_time_lbl = {"right_mouse_down", "double_click"}}) - --- override base-class handleEvents() to report the event data in the floater's display field -function flt:handleEvents(event_data) - self:post({action="add_text", ctrl_name="events_editor", value = event_data}) - -- forward the call to base-class handleEvents() - return Floater.handleEvents(self, event_data) -end - -function flt:commit_disable_ctrl(event_data) - self:post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)}) -end - -function flt:commit_title_cmb(event_data) - self:post({action="set_title", value=event_data.value}) -end - -function flt:commit_open_btn(event_data) - floater_name = self:request({action="get_value", ctrl_name='openfloater_cmd'}).value - leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) -end - -local function getCurrentTime() - local currentTime = os.date("*t") - return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec) -end - -function flt:double_click_show_time_lbl(event_data) - self:post({action="set_value", ctrl_name="time_lbl", value=getCurrentTime()}) -end - -startup.wait('STATE_LOGIN_WAIT') -flt:show() diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua new file mode 100644 index 0000000000..bd397ef2a6 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -0,0 +1,27 @@ +local Floater = require 'Floater' +local LLGesture = require 'LLGesture' +local startup = require 'startup' + +local flt = Floater( + "luafloater_gesture_list.xml", + {gesture_list = {"double_click"}}) + +function flt:post_build(event_data) + local gestures_uuid = LLGesture.getActiveGestures() + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "gesture_list" + local gestures = {} + for uuid, info in pairs(gestures_uuid) do + table.insert(gestures, {value = uuid, columns={column = "gesture_name", value = info.name}}) + end + action_data.value = gestures + self:post(action_data) +end + +function flt:double_click_gesture_list(event_data) + LLGesture.startGesture(event_data.value) +end + +startup.wait('STATE_STARTED') +flt:show() diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua deleted file mode 100644 index bd397ef2a6..0000000000 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua +++ /dev/null @@ -1,27 +0,0 @@ -local Floater = require 'Floater' -local LLGesture = require 'LLGesture' -local startup = require 'startup' - -local flt = Floater( - "luafloater_gesture_list.xml", - {gesture_list = {"double_click"}}) - -function flt:post_build(event_data) - local gestures_uuid = LLGesture.getActiveGestures() - local action_data = {} - action_data.action = "add_list_element" - action_data.ctrl_name = "gesture_list" - local gestures = {} - for uuid, info in pairs(gestures_uuid) do - table.insert(gestures, {value = uuid, columns={column = "gesture_name", value = info.name}}) - end - action_data.value = gestures - self:post(action_data) -end - -function flt:double_click_gesture_list(event_data) - LLGesture.startGesture(event_data.value) -end - -startup.wait('STATE_STARTED') -flt:show() -- cgit v1.2.3 From 1913ea4ec2f46458e2971e6e02afacf4da670af2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 2 Aug 2024 19:07:02 -0400 Subject: Search --luafile script on LuaCommandPath. --- indra/newview/llappviewer.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ef12fe0bd3..ff29f64aeb 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -113,6 +113,7 @@ #include "llgltfmateriallist.h" // Linden library includes +#include "fsyspath.h" #include "llavatarnamecache.h" #include "lldiriterator.h" #include "llexperiencecache.h" @@ -1216,8 +1217,23 @@ bool LLAppViewer::init() "--luafile", "LuaScript", [](const LLSD& script) { - // no completion callback: we don't need to know - LLLUAmanager::runScriptFile(script); + LLSD paths(gSavedSettings.getLLSD("LuaCommandPath")); + LL_DEBUGS("Lua") << "LuaCommandPath = " << paths << LL_ENDL; + for (const auto& path : llsd::inArray(paths)) + { + // if script path is already absolute, operator/() preserves it + auto abspath(fsyspath(gDirUtilp->getAppRODataDir()) / path.asString()); + auto absscript{ (abspath / script.asString()) }; + std::error_code ec; + if (std::filesystem::exists(absscript, ec)) + { + // no completion callback: we don't need to know + LLLUAmanager::runScriptFile(absscript.u8string()); + return; // from lambda + } + } + LL_WARNS("Lua") << "--luafile " << std::quoted(script.asString()) + << " not found on " << paths << LL_ENDL; }); processComposeSwitch( "LuaAutorunPath", "LuaAutorunPath", -- cgit v1.2.3 From af947de6928daa70098edb8346effb9dc8146f47 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 2 Aug 2024 19:24:07 -0400 Subject: Add 'LLPanelLogin' 'login', 'savedLogins' operations. 'login' accepts optional 'username', 'slurl', 'grid'. 'savedLogins' returns the list of saved usernames in both display form and internal form. Make LLPanelLogin::getUserName() accept (const LLPointer<LLCredential>&). There's a whole separate discussion pending as to whether const LLPointer<T> should provide access to non-const T methods. Similarly, make LLCredential::getIdentifier() a const method. These two changes enable read-only access to credentials. Make LLPanelLogin methods capture and reuse LLGridManager::instance() as appropriate. Add require/login.lua and test_login.lua. --- indra/newview/llpanellogin.cpp | 57 +++++---- indra/newview/llpanellogin.h | 2 +- indra/newview/llpanelloginlistener.cpp | 178 ++++++++++++++++++++++++++++ indra/newview/llpanelloginlistener.h | 2 + indra/newview/llsecapi.h | 2 +- indra/newview/scripts/lua/require/login.lua | 21 ++-- indra/newview/scripts/lua/test_login.lua | 10 +- 7 files changed, 226 insertions(+), 46 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 86f56f0949..a6dbcedc4b 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -81,15 +81,16 @@ BOOL LLPanelLogin::sCredentialSet = FALSE; LLPointer<LLCredential> load_user_credentials(std::string &user_key) { - if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + std::string grid{ LLGridManager::instance().getGrid() }; + if (gSecAPIHandler->hasCredentialMap("login_list", grid)) { // user_key should be of "name Resident" format - return gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + return gSecAPIHandler->loadFromCredentialMap("login_list", grid, user_key); } else { // legacy (or legacy^2, since it also tries to load from settings) - return gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + return gSecAPIHandler->loadCredential(grid); } } @@ -223,7 +224,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, sendChildToBack(getChildView("forgot_password_text")); sendChildToBack(getChildView("sign_up_text")); - std::string current_grid = LLGridManager::getInstance()->getGrid(); + LLGridManager& gridmgr{ LLGridManager::instance() }; + std::string current_grid = gridmgr.getGrid(); if (!mFirstLoginThisInstall) { LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); @@ -237,7 +239,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, // Load all of the grids, sorted, and then add a bar and the current grid at the top server_choice_combo->removeall(); - std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); + std::map<std::string, std::string> known_grids = gridmgr.getKnownGrids(); for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); grid_choice != known_grids.end(); grid_choice++) @@ -251,7 +253,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, server_choice_combo->sortByName(); LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + server_choice_combo->add(gridmgr.getGridLabel(), current_grid, ADD_TOP); server_choice_combo->selectFirstItem(); @@ -760,6 +762,7 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl) LL_DEBUGS("AppInit")<<new_start_slurl.asString()<<LL_ENDL; LLComboBox* location_combo = sInstance->getChild<LLComboBox>("start_location_combo"); + LLGridManager& gridmgr{ LLGridManager::instance() }; /* * Determine whether or not the new_start_slurl modifies the grid. * @@ -774,17 +777,17 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl) { case LLSLURL::LOCATION: { - std::string slurl_grid = LLGridManager::getInstance()->getGrid(new_start_slurl.getGrid()); + std::string slurl_grid = gridmgr.getGrid(new_start_slurl.getGrid()); if ( ! slurl_grid.empty() ) // is that a valid grid? { - if ( slurl_grid != LLGridManager::getInstance()->getGrid() ) // new grid? + if ( slurl_grid != gridmgr.getGrid() ) // new grid? { // the slurl changes the grid, so update everything to match - LLGridManager::getInstance()->setGridChoice(slurl_grid); + gridmgr.setGridChoice(slurl_grid); // update the grid selector to match the slurl LLComboBox* server_combo = sInstance->getChild<LLComboBox>("server_combo"); - std::string server_label(LLGridManager::getInstance()->getGridLabel(slurl_grid)); + std::string server_label(gridmgr.getGridLabel(slurl_grid)); server_combo->setSimple(server_label); updateServer(); // to change the links and splash screen @@ -831,8 +834,7 @@ void LLPanelLogin::autologinToLocation(const LLSLURL& slurl) if ( LLPanelLogin::sInstance != NULL ) { - void* unused_parameter = 0; - LLPanelLogin::sInstance->onClickConnect(unused_parameter); + LLPanelLogin::sInstance->onClickConnect(false); } } @@ -872,7 +874,8 @@ void LLPanelLogin::loadLoginPage() { if (!sInstance) return; - LLURI login_page = LLURI(LLGridManager::getInstance()->getLoginPage()); + LLGridManager& gridmgr{ LLGridManager::instance() }; + LLURI login_page = LLURI(gridmgr.getLoginPage()); LLSD params(login_page.queryMap()); LL_DEBUGS("AppInit") << "login_page: " << login_page << LL_ENDL; @@ -899,7 +902,7 @@ void LLPanelLogin::loadLoginPage() params["channel"] = LLVersionInfo::instance().getChannel(); // Grid - params["grid"] = LLGridManager::getInstance()->getGridId(); + params["grid"] = gridmgr.getGridId(); // add OS info params["os"] = LLOSInfo::instance().getOSStringSimple(); @@ -916,7 +919,7 @@ void LLPanelLogin::loadLoginPage() login_page.path(), params)); - gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid()); + gViewerWindow->setMenuBackgroundColor(false, !gridmgr.isInProductionGrid()); LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); if (web_browser->getCurrentNavUrl() != login_uri.asString()) @@ -949,9 +952,10 @@ void LLPanelLogin::onClickConnect(bool commit_fields) // the grid definitions may come from a user-supplied grids.xml, so they may not be good LL_DEBUGS("AppInit")<<"grid "<<combo_val.asString()<<LL_ENDL; + LLGridManager& gridmgr{ LLGridManager::instance() }; try { - LLGridManager::getInstance()->setGridChoice(combo_val.asString()); + gridmgr.setGridChoice(combo_val.asString()); } catch (LLInvalidGridName ex) { @@ -984,7 +988,7 @@ void LLPanelLogin::onClickConnect(bool commit_fields) std::string identifier_type; cred->identifierType(identifier_type); LLSD allowed_credential_types; - LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types); + gridmgr.getLoginIdentifierTypes(allowed_credential_types); // check the typed in credential type against the credential types expected by the server. for(LLSD::array_iterator i = allowed_credential_types.beginArray(); @@ -1133,6 +1137,7 @@ void LLPanelLogin::updateServer() { if (sInstance) { + LLGridManager& gridmgr{ LLGridManager::instance() }; try { // if they've selected another grid, we should load the credentials @@ -1152,7 +1157,7 @@ void LLPanelLogin::updateServer() // populate dropbox and setFields // Note: following call is related to initializeLoginInfo() - LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(gridmgr.getGrid()); sInstance->populateUserList(credential); // restore creds @@ -1165,12 +1170,12 @@ void LLPanelLogin::updateServer() { // populate dropbox and setFields // Note: following call is related to initializeLoginInfo() - LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(gridmgr.getGrid()); sInstance->populateUserList(credential); } // update the login panel links - bool system_grid = LLGridManager::getInstance()->isSystemGrid(); + bool system_grid = gridmgr.isSystemGrid(); // Want to vanish not only create_new_account_btn, but also the // title text over it, so turn on/off the whole layout_panel element. @@ -1219,11 +1224,12 @@ void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential) getChild<LLUICtrl>("password_edit")->setValue(std::string()); mUsernameLength = 0; mPasswordLength = 0; + std::string grid{ LLGridManager::instance().getGrid() }; - if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + if (gSecAPIHandler->hasCredentialMap("login_list", grid)) { LLSecAPIHandler::credential_map_t credencials; - gSecAPIHandler->loadCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), credencials); + gSecAPIHandler->loadCredentialMap("login_list", grid, credencials); LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); @@ -1278,7 +1284,8 @@ void LLPanelLogin::onSelectServer() LLComboBox* server_combo = getChild<LLComboBox>("server_combo"); LLSD server_combo_val = server_combo->getSelectedValue(); LL_INFOS("AppInit") << "grid "<<server_combo_val.asString()<< LL_ENDL; - LLGridManager::getInstance()->setGridChoice(server_combo_val.asString()); + auto& gridmgr{ LLGridManager::instance() }; + gridmgr.setGridChoice(server_combo_val.asString()); addFavoritesToStartLocation(); /* @@ -1308,7 +1315,7 @@ void LLPanelLogin::onSelectServer() LLSLURL slurl(location); // generata a slurl from the location combo contents if (location.empty() || (slurl.getType() == LLSLURL::LOCATION - && slurl.getGrid() != LLGridManager::getInstance()->getGrid()) + && slurl.getGrid() != gridmgr.getGrid()) ) { // the grid specified by the location is not this one, so clear the combo @@ -1338,7 +1345,7 @@ bool LLPanelLogin::getShowFavorites() } // static -std::string LLPanelLogin::getUserName(LLPointer<LLCredential> &cred) +std::string LLPanelLogin::getUserName(const LLPointer<LLCredential> &cred) { if (cred.isNull()) { diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 7f4c2487bf..a7019ea2a3 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -88,7 +88,7 @@ public: static bool getShowFavorites(); // extract name from cred in a format apropriate for username field - static std::string getUserName(LLPointer<LLCredential> &cred); + static std::string getUserName(const LLPointer<LLCredential> &cred); private: friend class LLPanelLoginListener; diff --git a/indra/newview/llpanelloginlistener.cpp b/indra/newview/llpanelloginlistener.cpp index fb6f034b7f..a4418145d7 100644 --- a/indra/newview/llpanelloginlistener.cpp +++ b/indra/newview/llpanelloginlistener.cpp @@ -32,9 +32,19 @@ #include "llpanelloginlistener.h" // STL headers // std headers +#include <iomanip> +#include <memory> // external library headers // other Linden headers +#include "llcombobox.h" #include "llpanellogin.h" +#include "llsdutil.h" +#include "llsecapi.h" +#include "llslurl.h" +#include "llstartup.h" +#include "lluictrl.h" +#include "llviewernetwork.h" +#include "stringize.h" LLPanelLoginListener::LLPanelLoginListener(LLPanelLogin* instance): LLEventAPI("LLPanelLogin", "Access to LLPanelLogin methods"), @@ -43,9 +53,177 @@ LLPanelLoginListener::LLPanelLoginListener(LLPanelLogin* instance): add("onClickConnect", "Pretend user clicked the \"Log In\" button", &LLPanelLoginListener::onClickConnect); + add("login", + "Login to Second Life with saved credentials.\n" + "Pass [\"username\"] to select credentials previously saved with that username.\n" + "Pass [\"slurl\"] to specify target location.\n" + "Pass [\"grid\"] to select one of the valid grids in grids.xml.", + &LLPanelLoginListener::login, + llsd::map("reply", LLSD::String())); + add("savedLogins", + "Return \"logins\" as a list of {} saved login names.\n" + "Pass [\"grid\"] to select one of the valid grids in grids.xml.", + &LLPanelLoginListener::savedLogins, + llsd::map("reply", LLSD::String())); } void LLPanelLoginListener::onClickConnect(const LLSD&) const { mPanel->onClickConnect(false); } + +void LLPanelLoginListener::login(const LLSD& args) const +{ + // Although we require a "reply" key, don't instantiate a Response object: + // if things go well, response to our invoker will come later, once the + // viewer gets the response from the login server. + std::string username(args["username"]), slurlstr(args["slurl"]), grid(args["grid"]); + LL_DEBUGS("AppInit") << "Login with saved credentials"; + if (! username.empty()) + { + LL_CONT << " for user " << std::quoted(username); + } + if (! slurlstr.empty()) + { + LL_CONT << " to location " << std::quoted(slurlstr); + } + if (! grid.empty()) + { + LL_CONT << " on grid " << std::quoted(grid); + } + LL_CONT << LL_ENDL; + + // change grid first, allowing slurl to override + auto& gridmgr{ LLGridManager::instance() }; + if (! grid.empty()) + { + // setGridChoice() can throw LLInvalidGridName -- but if so, let it + // propagate, trusting that LLEventAPI will catch it and send an + // appropriate reply. + auto server_combo = mPanel->getChild<LLComboBox>("server_combo"); + server_combo->setSimple(gridmgr.getGridLabel(grid)); + LLPanelLogin::updateServer(); + } + if (! slurlstr.empty()) + { + LLSLURL slurl(slurlstr); + if (! slurl.isSpatial()) + { + // don't bother with LLTHROW() because we expect LLEventAPI to + // catch and report back to invoker + throw DispatchError(stringize("Invalid start SLURL ", std::quoted(slurlstr))); + } + // Bypass LLStartUp::setStartSLURL() because, after validating as + // above, it bounces right back to LLPanelLogin::onUpdateStartSLURL(). + // It also sets the "NextLoginLocation" user setting, but as with grid, + // we don't yet know whether that's desirable for scripted login. + LLPanelLogin::onUpdateStartSLURL(slurl); + } + if (! username.empty()) + { + // Transform (e.g.) "Nat Linden" to the internal form expected by + // loadFromCredentialMap(), e.g. "nat_linden" + LLStringUtil::toLower(username); + LLStringUtil::replaceChar(username, ' ', '_'); + LLStringUtil::replaceChar(username, '.', '_'); + + // call gridmgr.getGrid() because our caller didn't necessarily pass + // ["grid"] -- or it might have been overridden by the SLURL + auto cred = gSecAPIHandler->loadFromCredentialMap("login_list", + gridmgr.getGrid(), + username); + LLPanelLogin::setFields(cred); + } + + if (mPanel->getChild<LLUICtrl>("username_combo")->getValue().asString().empty() || + mPanel->getChild<LLUICtrl>("password_edit") ->getValue().asString().empty()) + { + // as above, let LLEventAPI report back to invoker + throw DispatchError(stringize("Unrecognized username ", std::quoted(username))); + } + + // Here we're about to trigger actual login, which is all we can do in + // this method. All subsequent responses must come via the "login" + // LLEventPump. + LLEventPumps::instance().obtain("login").listen( + "Lua login", + [args] + (const LLBoundListener& conn, const LLSD& update) + { + LLSD response{ llsd::map("ok", false) }; + if (update["change"] == "connect") + { + // success! + response["ok"] = true; + } + else if (update["change"] == "disconnect") + { + // Does this ever actually happen? + // LLLoginInstance::handleDisconnect() says it's a placeholder. + response["error"] = "login disconnect"; + } + else if (update["change"] == "fail.login") + { + // why? + // LLLoginInstance::handleLoginFailure() has special code to + // handle "tos", "update" and "mfa_challenge". Do not respond + // automatically because these things are SUPPOSED to engage + // the user. + // Copy specific response fields because there's an enormous + // chunk of stuff that comes back on success. + LLSD data{ update["data"] }; + const char* fields[] = { + "reason", + "error_code" + }; + for (auto field : fields) + { + response[field] = data[field]; + } + response["error"] = update["message"]; + } + else + { + // Ignore all other "change" values: LLLogin sends multiple update + // events. Only a few of them (above) indicate completion. + return; + } + // For all the completion cases, disconnect from the "login" + // LLEventPump. + conn.disconnect(); + // and at last, send response to the original invoker + sendReply(response, args); + }); + + // Turn the Login crank. + mPanel->onClickConnect(false); +} + +LLSD LLPanelLoginListener::savedLogins(const LLSD& args) const +{ + LL_INFOS() << "called with " << args << LL_ENDL; + std::string grid = (args.has("grid")? args["grid"].asString() + : LLGridManager::instance().getGrid()); + if (! gSecAPIHandler->hasCredentialMap("login_list", grid)) + { + LL_INFOS() << "no creds for " << grid << LL_ENDL; + return llsd::map("error", + stringize("No saved logins for grid ", std::quoted(grid))); + } + LLSecAPIHandler::credential_map_t creds; + gSecAPIHandler->loadCredentialMap("login.list", grid, creds); + auto result = llsd::map( + "logins", + llsd::toArray( + creds, + [](const auto& pair) + { + return llsd::map( + "name", + LLPanelLogin::getUserName(pair.second), + "key", + pair.first); + })); + LL_INFOS() << "returning creds " << result << LL_ENDL; + return result; +} diff --git a/indra/newview/llpanelloginlistener.h b/indra/newview/llpanelloginlistener.h index b552ccd5b0..f2f4d70ff9 100644 --- a/indra/newview/llpanelloginlistener.h +++ b/indra/newview/llpanelloginlistener.h @@ -40,6 +40,8 @@ public: private: void onClickConnect(const LLSD&) const; + void login(const LLSD&) const; + LLSD savedLogins(const LLSD&) const; LLPanelLogin* mPanel; }; diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 5cc78d09dc..367bfe1469 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -311,7 +311,7 @@ public: mIdentifier = identifier; mAuthenticator = authenticator; } - virtual LLSD getIdentifier() { return mIdentifier; } + virtual LLSD getIdentifier() const { return mIdentifier; } virtual void identifierType(std::string& idType); virtual LLSD getAuthenticator() { return mAuthenticator; } virtual void authenticatorType(std::string& authType); diff --git a/indra/newview/scripts/lua/require/login.lua b/indra/newview/scripts/lua/require/login.lua index 0d8591cace..f4e65b1606 100644 --- a/indra/newview/scripts/lua/require/login.lua +++ b/indra/newview/scripts/lua/require/login.lua @@ -1,19 +1,12 @@ -local UI = require 'UI' local leap = require 'leap' +local startup = require 'startup' +local mapargs = require 'mapargs' -local function login(username, password) - if username and password then - local userpath = '//username_combo/Combo Text Entry' - local passpath = '//password_edit' - -- first clear anything presently in those text fields - for _, path in pairs({userpath, passpath}) do - UI.click(path) - UI.keypress{keysym='Backsp', path=path} - end - UI.type{path=userpath, text=username} - UI.type{path=passpath, text=password} - end - leap.send('LLPanelLogin', {op='onClickConnect'}) +local function login(...) + startup.wait('STATE_LOGIN_WAIT') + local args = mapargs('username,grid,slurl', ...) + args.op = 'login' + return leap.request('LLPanelLogin', args) end return login diff --git a/indra/newview/scripts/lua/test_login.lua b/indra/newview/scripts/lua/test_login.lua index a8c31807bc..f263940f79 100644 --- a/indra/newview/scripts/lua/test_login.lua +++ b/indra/newview/scripts/lua/test_login.lua @@ -1,7 +1,7 @@ -startup = require 'startup' +inspect = require 'inspect' login = require 'login' -startup.wait('STATE_LOGIN_WAIT') -login() --- Fill in valid credentials as they would be entered on the login screen --- login('My Username', 'password') +print(inspect(login{ + username='Nat Linden', +-- grid='agni' + })) -- cgit v1.2.3 From 6cd306e9bf3698551beb70ec6ddfde7f6cec12bd Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Sat, 3 Aug 2024 14:23:57 +0200 Subject: Use python raw string literals to remove any ambiguity with standard escape sequences like \n --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6be43f0021..d94bdc31d2 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -277,13 +277,13 @@ class ViewerManifest(LLManifest): # All lines up to and including the first blank line are the file header; skip them lines.reverse() # so that pop will pull from first to last line - while not re.match("\s*$", lines.pop()) : + while not re.match(r"\s*$", lines.pop()) : pass # do nothing # A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names names = [] for line in lines : - if re.match("\S", line) : + if re.match(r"\S", line) : names.append(line.rstrip()) # It's not fair to always put the same people at the head of the list random.shuffle(names) -- cgit v1.2.3 From f480075e1ffbcc026843a3d14fd6533aad1e7126 Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Sat, 3 Aug 2024 14:27:37 +0200 Subject: Cast RAND_MAX into F32 to avoid any implicit casting --- indra/newview/llvoicewebrtc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index d18a32cb05..59158922d0 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2096,7 +2096,7 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s { // retries wait a short period...randomize it so // all clients don't try to reconnect at once. - mRetryWaitSecs = (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs = (F32)((F32) rand() / ((F32)RAND_MAX)) + 0.5f; mWebRTCPeerConnectionInterface = llwebrtc::newPeerConnection(); mWebRTCPeerConnectionInterface->setSignalingObserver(this); @@ -2678,7 +2678,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() case VOICE_STATE_SESSION_UP: { mRetryWaitPeriod = 0; - mRetryWaitSecs = (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs = (F32)((F32) rand() / ((F32)RAND_MAX)) + 0.5f; // we'll stay here as long as the session remains up. if (mShutDown) @@ -2700,7 +2700,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { // back off the retry period, and do it by a small random // bit so all clients don't reconnect at once. - mRetryWaitSecs += (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs += (F32)((F32) rand() / ((F32)RAND_MAX)) + 0.5f; mRetryWaitPeriod = 0; } } -- cgit v1.2.3 From b12d135c38e327774c01594acfa96e37a9e67a64 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 5 Aug 2024 11:24:01 -0400 Subject: Fix a couple problems with "LLPanelLogin" listener (thanks Maxim!). Convert plain grid (e.g. "agni") to domain form (e.g. "util.agni.lindenlab.com"). Fix a typo in `savedLogins()`: "login_list", not "login.list". login.lua now returns a table with two functions: `login.login()` and `login.savedLogins()`. Defend Lua caller against trying to engage login features too late in startup sequence: in addition to waiting for "STATE_LOGIN_WAIT", produce an error if `startup.state()` is beyond that state. Since by then `LLPanelLogin` is destroyed, `leap.request("LLPanelLogin", ...)` would get no response, causing the calling Lua script to hang until viewer shutdown. --- indra/newview/llpanelloginlistener.cpp | 22 ++++++++++++++++++++-- indra/newview/scripts/lua/require/login.lua | 23 ++++++++++++++++++++++- indra/newview/scripts/lua/test_login.lua | 9 ++++++--- 3 files changed, 48 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelloginlistener.cpp b/indra/newview/llpanelloginlistener.cpp index a4418145d7..aeaf2d1d00 100644 --- a/indra/newview/llpanelloginlistener.cpp +++ b/indra/newview/llpanelloginlistener.cpp @@ -72,6 +72,23 @@ void LLPanelLoginListener::onClickConnect(const LLSD&) const mPanel->onClickConnect(false); } +namespace +{ + + std::string gridkey(const std::string& grid) + { + if (grid.find('.') != std::string::npos) + { + return grid; + } + else + { + return stringize("util.", grid, ".lindenlab.com"); + } + } + +} // anonymous namespace + void LLPanelLoginListener::login(const LLSD& args) const { // Although we require a "reply" key, don't instantiate a Response object: @@ -97,6 +114,7 @@ void LLPanelLoginListener::login(const LLSD& args) const auto& gridmgr{ LLGridManager::instance() }; if (! grid.empty()) { + grid = gridkey(grid); // setGridChoice() can throw LLInvalidGridName -- but if so, let it // propagate, trusting that LLEventAPI will catch it and send an // appropriate reply. @@ -202,7 +220,7 @@ void LLPanelLoginListener::login(const LLSD& args) const LLSD LLPanelLoginListener::savedLogins(const LLSD& args) const { LL_INFOS() << "called with " << args << LL_ENDL; - std::string grid = (args.has("grid")? args["grid"].asString() + std::string grid = (args.has("grid")? gridkey(args["grid"].asString()) : LLGridManager::instance().getGrid()); if (! gSecAPIHandler->hasCredentialMap("login_list", grid)) { @@ -211,7 +229,7 @@ LLSD LLPanelLoginListener::savedLogins(const LLSD& args) const stringize("No saved logins for grid ", std::quoted(grid))); } LLSecAPIHandler::credential_map_t creds; - gSecAPIHandler->loadCredentialMap("login.list", grid, creds); + gSecAPIHandler->loadCredentialMap("login_list", grid, creds); auto result = llsd::map( "logins", llsd::toArray( diff --git a/indra/newview/scripts/lua/require/login.lua b/indra/newview/scripts/lua/require/login.lua index f4e65b1606..50fc9e3793 100644 --- a/indra/newview/scripts/lua/require/login.lua +++ b/indra/newview/scripts/lua/require/login.lua @@ -2,11 +2,32 @@ local leap = require 'leap' local startup = require 'startup' local mapargs = require 'mapargs' -local function login(...) +local login = {} + +local function ensure_login_state(op) + -- no point trying to login until the viewer is ready startup.wait('STATE_LOGIN_WAIT') + -- Once we've actually started login, LLPanelLogin is destroyed, and so is + -- its "LLPanelLogin" listener. At that point, + -- leap.request("LLPanelLogin", ...) will hang indefinitely because no one + -- is listening on that LLEventPump any more. Intercept that case and + -- produce a sensible error. + local state = startup.state() + if startup.before('STATE_LOGIN_WAIT', state) then + error(`Can't engage login operation {op} once we've reached state {state}`, 2) + end +end + +function login.login(...) + ensure_login_state('login') local args = mapargs('username,grid,slurl', ...) args.op = 'login' return leap.request('LLPanelLogin', args) end +function login.savedLogins(grid) + ensure_login_state('savedLogins') + return leap.request('LLPanelLogin', {op='savedLogins'})['logins'] +end + return login diff --git a/indra/newview/scripts/lua/test_login.lua b/indra/newview/scripts/lua/test_login.lua index f263940f79..54d3635a41 100644 --- a/indra/newview/scripts/lua/test_login.lua +++ b/indra/newview/scripts/lua/test_login.lua @@ -1,7 +1,10 @@ inspect = require 'inspect' login = require 'login' -print(inspect(login{ - username='Nat Linden', --- grid='agni' +local grid = 'agni' +print(inspect(login.savedLogins(grid))) + +print(inspect(login.login{ + username='Your Username', + grid=grid })) -- cgit v1.2.3 From cf29b701b19644062a1428a64023c3cf9829e2de Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 5 Aug 2024 20:37:03 +0300 Subject: Allow getting the list of floater names, hide top menu items; add demo script --- indra/newview/lluilistener.cpp | 16 ++++++++++++++ indra/newview/lluilistener.h | 1 + indra/newview/scripts/lua/require/UI.lua | 8 +++++++ indra/newview/scripts/lua/test_LLChatListener.lua | 19 ++++++++++++---- indra/newview/scripts/lua/test_toolbars.lua | 27 +++++++++++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 indra/newview/scripts/lua/test_toolbars.lua (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 07a8b45f89..bcc13c5fe9 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -100,6 +100,11 @@ LLUIListener::LLUIListener(): &LLUIListener::addMenuSeparator, llsd::map("parent_menu", LLSD(), "reply", LLSD())); + add("setMenuVisible", + "Set menu [\"name\"] visibility to [\"visible\"]", + &LLUIListener::setMenuVisible, + llsd::map("name", LLSD(), "visible", LLSD(), "reply", LLSD())); + add("defaultToolbars", "todo: defaultToolbars desc", &LLUIListener::restoreDefaultToolbars); @@ -313,6 +318,17 @@ void LLUIListener::addMenuSeparator(const LLSD&event) const } } +void LLUIListener::setMenuVisible(const LLSD &event) const +{ + Response response(LLSD(), event); + std::string menu_name(event["name"]); + if (!gMenuBarView->getItem(menu_name)) + { + return response.error(stringize("Menu ", std::quoted(menu_name), " was not found")); + } + gMenuBarView->setItemVisible(menu_name, event["visible"].asBoolean()); +} + void LLUIListener::restoreDefaultToolbars(const LLSD &event) const { LLToolBarView::loadDefaultToolbars(); diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index bae6724b3d..98e4754306 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -49,6 +49,7 @@ private: void addMenuBranch(const LLSD&event) const; void addMenuItem(const LLSD&event) const; void addMenuSeparator(const LLSD&event) const; + void setMenuVisible(const LLSD &event) const; void restoreDefaultToolbars(const LLSD &event) const; void clearAllToolbars(const LLSD &event) const; diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index df77eb2b56..df76b1501c 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -150,6 +150,10 @@ function UI.addMenu(...) return leap.request('UI', args) end +function UI.setMenuVisible(name, visible) + return leap.request('UI', {op='setMenuVisible', name=name, visible=visible}) +end + function UI.addMenuBranch(...) local args = mapargs('name,label,parent_menu', ...) args.op = 'addMenuBranch' @@ -222,4 +226,8 @@ function UI.closeAllFloaters() return leap.send("UI", {op = "closeAllFloaters"}) end +function UI.getFloaterNames() + return leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters +end + return UI diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua index 18363ed43b..4a4d40bee5 100644 --- a/indra/newview/scripts/lua/test_LLChatListener.lua +++ b/indra/newview/scripts/lua/test_LLChatListener.lua @@ -1,11 +1,22 @@ local LLChatListener = require 'LLChatListener' local LLChat = require 'LLChat' -local leap = require 'leap' +local UI = require 'UI' +-- Chat listener script allows to use the following commands in Nearby chat: +-- open inventory -- open defined floater by name +-- close inventory -- close defined floater by name +-- closeall -- close all floaters +-- stop -- close the script +-- any other messages will be echoed. function openOrEcho(message) - local floater_name = string.match(message, "^open%s+(%w+)") - if floater_name then - leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"}) + local open_floater_name = string.match(message, "^open%s+(%w+)") + local close_floater_name = string.match(message, "^close%s+(%w+)") + if open_floater_name then + UI.showFloater(open_floater_name) + elseif close_floater_name then + UI.hideFloater(close_floater_name) + elseif message == 'closeall' then + UI.closeAllFloaters() else LLChat.sendNearby('Echo: ' .. message) end diff --git a/indra/newview/scripts/lua/test_toolbars.lua b/indra/newview/scripts/lua/test_toolbars.lua new file mode 100644 index 0000000000..70035db775 --- /dev/null +++ b/indra/newview/scripts/lua/test_toolbars.lua @@ -0,0 +1,27 @@ +popup = require 'popup' +UI = require 'UI' + +local OK = 'OK_okcancelbuttons' +local BUTTONS = UI.getToolbarBtnNames() + +-- Clear the toolbars and then add the toolbar buttons to the random toolbar +response = popup:alertYesCancel('Toolbars will be randomly reshuffled. Proceed?') +if next(response) == OK then + UI.clearToolbars() + math.randomseed(os.time()) + + -- add the buttons to the random toolbar + for i = 1, #BUTTONS do + UI.addToolbarBtn(BUTTONS[i], math.random(3)) + end + + -- remove some of the added buttons from the toolbars + for i = 1, #BUTTONS do + if math.random(100) < 30 then + UI.removeToolbarBtn(BUTTONS[i]) + end + end + popup:tip('Toolbars were reshuffled') +else + popup:tip('Canceled') +end -- cgit v1.2.3 From 143168f9d95afeac2058efa4f54435a654c770f8 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Tue, 6 Aug 2024 16:58:06 +0300 Subject: Force ReleaseOS builds on Linux --- indra/newview/viewer_manifest.py | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 8600efc91e..24b43192a9 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1428,7 +1428,6 @@ class Linux_x86_64_Manifest(LinuxManifest): self.path_optional("libjemalloc*.so") - self.path("libhunspell-1.3.so*") self.path("libalut.so*") self.path("libopenal.so*") self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname -- cgit v1.2.3 From eb82c78b071d71a0fd2d7be1c573997e41bab51e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 6 Aug 2024 20:38:06 +0300 Subject: code clean up --- indra/newview/lluilistener.cpp | 26 +++++++++++++++++++------- indra/newview/scripts/lua/require/UI.lua | 8 ++++---- indra/newview/scripts/lua/test_toolbars.lua | 5 +++-- 3 files changed, 26 insertions(+), 13 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index bcc13c5fe9..3e67531388 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -106,23 +106,24 @@ LLUIListener::LLUIListener(): llsd::map("name", LLSD(), "visible", LLSD(), "reply", LLSD())); add("defaultToolbars", - "todo: defaultToolbars desc", + "Restore default toolbar buttons", &LLUIListener::restoreDefaultToolbars); - add("clearToolbars", + add("clearAllToolbars", "Clear all buttons off the toolbars", &LLUIListener::clearAllToolbars); add("addToolbarBtn", - "Add [\"btn_name\"] toolbar button to the [\"toolbar\"]\n" - "[1 (left toolbar), 2 (right toolbar), 3 (bottom toolbar)]\n" + "Add [\"btn_name\"] toolbar button to the [\"toolbar\"]:\n" + "\"left\", \"right\", \"bottom\" (default is \"bottom\")\n" "Position of the command in the original list can be specified as [\"rank\"]", &LLUIListener::addToolbarBtn, llsd::map("btn_name", LLSD(), "reply", LLSD())); add("removeToolbarBtn", "Remove [\"btn_name\"] toolbar button off the toolbar,\n" - "return [\"rank\"] (old position) of the command in the original list", + "return [\"rank\"] (old position) of the command in the original list,\n" + "rank -1 means that [\"btn_name\"] was not found", &LLUIListener::removeToolbarBtn, llsd::map("btn_name", LLSD(), "reply", LLSD())); @@ -347,9 +348,20 @@ void LLUIListener::addToolbarBtn(const LLSD &event) const ToolBarLocation toolbar = ToolBarLocation::TOOLBAR_BOTTOM; if (event.has("toolbar")) { - toolbar = llclamp((ToolBarLocation)event["toolbar"].asInteger(), ToolBarLocation::TOOLBAR_NONE, ToolBarLocation::TOOLBAR_BOTTOM); + if (event["toolbar"] == "left") + { + toolbar = ToolBarLocation::TOOLBAR_LEFT; + } + else if (event["toolbar"] == "right") + { + toolbar = ToolBarLocation::TOOLBAR_RIGHT; + } + else if (event["toolbar"] != "bottom") + { + return response.error(stringize("Toolbar name ", std::quoted(event["toolbar"].asString()), " is not correct. Toolbar names are: left, right, bottom")); + } } - S32 rank = event.has("rank") ? event["rank"].asInteger() : - 1; + S32 rank = event.has("rank") ? event["rank"].asInteger() : LLToolBar::RANK_NONE; if(!gToolBarView->addCommand(event["btn_name"].asString(), toolbar, rank)) { response.error(stringize("Toolbar button ", std::quoted(event["btn_name"].asString()), " was not found")); diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index df76b1501c..9bc9a3685d 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -177,8 +177,8 @@ end -- Toolbar buttons -- *************************************************************************** -- Clears all buttons off the toolbars -function UI.clearToolbars() - leap.send('UI', {op='clearToolbars'}) +function UI.clearAllToolbars() + leap.send('UI', {op='clearAllToolbars'}) end function UI.defaultToolbars() @@ -186,8 +186,8 @@ function UI.defaultToolbars() end -- UI.addToolbarBtn{btn_name=btn_name --- [, toolbar= 3] -- 1 [TOOLBAR_LEFT], 2 [TOOLBAR_RIGHT], 3 [TOOLBAR_BOTTOM] --- [, rank=1]} -- position on the toolbar +-- [, toolbar= bottom] -- left, right, bottom -- default is bottom +-- [, rank=1]} -- position on the toolbar, starts at 0 (0 - first position, 1 - second position etc.) function UI.addToolbarBtn(...) local args = mapargs('btn_name,toolbar,rank', ...) args.op = 'addToolbarBtn' diff --git a/indra/newview/scripts/lua/test_toolbars.lua b/indra/newview/scripts/lua/test_toolbars.lua index 70035db775..9a832c5644 100644 --- a/indra/newview/scripts/lua/test_toolbars.lua +++ b/indra/newview/scripts/lua/test_toolbars.lua @@ -3,16 +3,17 @@ UI = require 'UI' local OK = 'OK_okcancelbuttons' local BUTTONS = UI.getToolbarBtnNames() +local TOOLBARS = {'left','right','bottom'} -- Clear the toolbars and then add the toolbar buttons to the random toolbar response = popup:alertYesCancel('Toolbars will be randomly reshuffled. Proceed?') if next(response) == OK then - UI.clearToolbars() + UI.clearAllToolbars() math.randomseed(os.time()) -- add the buttons to the random toolbar for i = 1, #BUTTONS do - UI.addToolbarBtn(BUTTONS[i], math.random(3)) + UI.addToolbarBtn(BUTTONS[i], TOOLBARS[math.random(3)]) end -- remove some of the added buttons from the toolbars -- cgit v1.2.3 From d3b1859ca3d6c2c2bcc92edba994b522cf9d4e99 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 6 Aug 2024 15:55:58 -0400 Subject: Introduce a custom coroutine/fiber scheduler to prioritize UI. The viewer's main thread's main fiber is responsible for coordinating just about everything. With the default round_robin fiber scheduling algorithm, launching too many additional fibers could starve the main fiber, resulting in visible lag. This custom scheduler tracks when it switches to and from the main fiber, and at each context switch, how long it's been since the last time the main fiber ran. If that exceeds a certain timeslice, it jumps the main fiber to the head of the queue and resumes that instead of any other ready fiber. --- indra/newview/llstartup.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 3cf0def66e..c7fb734440 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -48,6 +48,7 @@ #include "llaudioengine_openal.h" #endif +#include "coro_scheduler.h" #include "llavatarnamecache.h" #include "llexperiencecache.h" #include "lllandmark.h" @@ -400,10 +401,12 @@ bool idle_startup() static bool first_call = true; if (first_call) { + first_call = false; // Other phases get handled when startup state changes, // need to capture the initial state as well. LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); - first_call = false; + // Use our custom scheduler for coroutine scheduling. + llcoro::scheduler::use(); } gViewerWindow->showCursor(); -- cgit v1.2.3 From 5fde031b876e3b8ce794286e5796ffb8f0614cd3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Aug 2024 10:39:30 -0400 Subject: Rename 'UI' 'getParents' op to 'getTopMenus', add UI.lua function. Also update the 'UI' help text to reflect its more general nature. Mention 0-relative rank in the xxToolbarBtn operation help text. --- indra/newview/lluilistener.cpp | 23 ++++++++++++----------- indra/newview/lluilistener.h | 2 +- indra/newview/scripts/lua/require/UI.lua | 4 ++++ 3 files changed, 17 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 3e67531388..0280836075 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -48,8 +48,7 @@ extern LLMenuBarGL* gMenuBarView; LLUIListener::LLUIListener(): LLEventAPI("UI", - "LLUICtrl::CommitCallbackRegistry listener.\n" - "Capable of invoking any function (with parameter) you can specify in XUI.") + "Operations to manipulate the viewer's user interface.") { add("call", "Invoke the operation named by [\"function\"], passing [\"parameter\"],\n" @@ -70,9 +69,9 @@ LLUIListener::LLUIListener(): &LLUIListener::getValue, llsd::map("path", LLSD(), "reply", LLSD())); - add("getParents", + add("getTopMenus", "List names of Top menus suitable for passing as \"parent_menu\"", - &LLUIListener::getParents, + &LLUIListener::getTopMenus, llsd::map("reply", LLSD::String())); LLSD required_args = llsd::map("name", LLSD(), "label", LLSD(), "reply", LLSD()); @@ -116,13 +115,15 @@ LLUIListener::LLUIListener(): add("addToolbarBtn", "Add [\"btn_name\"] toolbar button to the [\"toolbar\"]:\n" "\"left\", \"right\", \"bottom\" (default is \"bottom\")\n" - "Position of the command in the original list can be specified as [\"rank\"]", + "Position of the command in the original list can be specified as [\"rank\"],\n" + "where 0 means the first item", &LLUIListener::addToolbarBtn, llsd::map("btn_name", LLSD(), "reply", LLSD())); add("removeToolbarBtn", "Remove [\"btn_name\"] toolbar button off the toolbar,\n" "return [\"rank\"] (old position) of the command in the original list,\n" + "rank 0 is the first position,\n" "rank -1 means that [\"btn_name\"] was not found", &LLUIListener::removeToolbarBtn, llsd::map("btn_name", LLSD(), "reply", LLSD())); @@ -141,7 +142,7 @@ typedef LLUICtrl::CommitCallbackInfo cb_info; void LLUIListener::call(const LLSD& event) { Response response(LLSD(), event); - LLUICtrl::CommitCallbackInfo *info = LLUICtrl::CommitCallbackRegistry::getValue(event["function"]); + cb_info *info = LLUICtrl::CommitCallbackRegistry::getValue(event["function"]); if (!info || !info->callback_func) { return response.error(stringize("Function ", std::quoted(event["function"].asString()), " was not found")); @@ -201,13 +202,13 @@ void LLUIListener::callables(const LLSD& event) const LLSD entry{ llsd::map("name", it->first) }; switch (it->second.handle_untrusted) { - case LLUICtrl::CommitCallbackInfo::UNTRUSTED_ALLOW: + case cb_info::UNTRUSTED_ALLOW: entry["access"] = "allow"; break; - case LLUICtrl::CommitCallbackInfo::UNTRUSTED_BLOCK: + case cb_info::UNTRUSTED_BLOCK: entry["access"] = "block"; break; - case LLUICtrl::CommitCallbackInfo::UNTRUSTED_THROTTLE: + case cb_info::UNTRUSTED_THROTTLE: entry["access"] = "throttle"; break; } @@ -235,10 +236,10 @@ void LLUIListener::getValue(const LLSD& event) const } } -void LLUIListener::getParents(const LLSD& event) const +void LLUIListener::getTopMenus(const LLSD& event) const { Response response(LLSD(), event); - response["parents"] = llsd::toArray( + response["menus"] = llsd::toArray( *gMenuBarView->getChildList(), [](auto childp) {return childp->getName(); }); } diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index 98e4754306..c839c03a57 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -43,7 +43,7 @@ private: void call(const LLSD& event); void callables(const LLSD& event) const; void getValue(const LLSD& event) const; - void getParents(const LLSD& event) const; + void getTopMenus(const LLSD& event) const; void addMenu(const LLSD&event) const; void addMenuBranch(const LLSD&event) const; diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 9bc9a3685d..464e6547ea 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -144,6 +144,10 @@ end -- Top menu -- *************************************************************************** +function UI.getTopMenus() + return leap.request('UI', {op='getTopMenus'}).menus +end + function UI.addMenu(...) local args = mapargs('name,label', ...) args.op = 'addMenu' -- cgit v1.2.3 From 2df6ee631507bd3c9bff783d57b96d4546405a8a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Aug 2024 12:51:47 -0400 Subject: Fix omission in login.savedLogins(). Also add Region.lua. --- indra/newview/scripts/lua/require/Region.lua | 17 +++++++++++++++++ indra/newview/scripts/lua/require/login.lua | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 indra/newview/scripts/lua/require/Region.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/Region.lua b/indra/newview/scripts/lua/require/Region.lua new file mode 100644 index 0000000000..e4eefece33 --- /dev/null +++ b/indra/newview/scripts/lua/require/Region.lua @@ -0,0 +1,17 @@ +LLFloaterAbout = require 'LLFloaterAbout' + +local Region = {} + +function Region.getInfo() + info = LLFloaterAbout.getInfo() + return { + HOSTNAME=info.HOSTNAME, + POSITION=info.POSITION, + POSITION_LOCAL=info.POSITION_LOCAL, + REGION=info.REGION, + SERVER_VERSION=info.SERVER_VERSION, + SLURL=info.SLURL, + } +end + +return Region diff --git a/indra/newview/scripts/lua/require/login.lua b/indra/newview/scripts/lua/require/login.lua index 50fc9e3793..919434f3a5 100644 --- a/indra/newview/scripts/lua/require/login.lua +++ b/indra/newview/scripts/lua/require/login.lua @@ -27,7 +27,7 @@ end function login.savedLogins(grid) ensure_login_state('savedLogins') - return leap.request('LLPanelLogin', {op='savedLogins'})['logins'] + return leap.request('LLPanelLogin', {op='savedLogins', grid=grid})['logins'] end return login -- cgit v1.2.3 From 08def53d8bf07beaa56db80e95aa76f3682c557c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Aug 2024 16:01:45 -0400 Subject: Move llcoro::scheduler::use() call from llstartup to llappviewer. Thanks, Maxim. --- indra/newview/llappviewer.cpp | 3 ++- indra/newview/llstartup.cpp | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ff29f64aeb..3d53200eda 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -765,7 +765,8 @@ bool LLAppViewer::init() //set the max heap size. initMaxHeapSize() ; LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); - + // Use our custom scheduler for coroutine scheduling. + llcoro::scheduler::use(); // Although initLoggingAndGetLastDuration() is the right place to mess with // setFatalFunction(), we can't query gSavedSettings until after diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c7fb734440..82eb59c002 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -405,8 +405,6 @@ bool idle_startup() // Other phases get handled when startup state changes, // need to capture the initial state as well. LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); - // Use our custom scheduler for coroutine scheduling. - llcoro::scheduler::use(); } gViewerWindow->showCursor(); -- cgit v1.2.3 From 3102dc0db472acac7c4007e7423e405a889d665a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Aug 2024 16:12:23 -0400 Subject: Allow smaller minimum timer intervals. Add test_flycam.lua to exercise the smaller intervals. --- indra/newview/scripts/lua/test_flycam.lua | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 indra/newview/scripts/lua/test_flycam.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_flycam.lua b/indra/newview/scripts/lua/test_flycam.lua new file mode 100644 index 0000000000..4fb5608b33 --- /dev/null +++ b/indra/newview/scripts/lua/test_flycam.lua @@ -0,0 +1,38 @@ +-- Make camera fly around the subject avatar for a few seconds. + +local LLAgent = require 'LLAgent' +local startup = require 'startup' +local timers = require 'timers' + +local initial = LLAgent.getRegionPosition() +local height = 2.0 -- meters +local radius = 4.0 -- meters +local speed = 1.0 -- meters/second along circle +local start = os.clock() +local stop = os.clock() + 30 -- seconds + +local function cameraPos(t) + local radians = speed * t + return { + initial[1] + radius * math.cos(radians), + initial[2] + radius * math.sin(radians), + initial[3] + height + } +end + +local function moveCamera() + if os.clock() < stop then + -- usual case + LLAgent.setCamera{ camera_pos=cameraPos(os.clock() - start), camera_locked=true } + return nil + else + -- last time + LLAgent.removeCamParams() + LLAgent.setFollowCamActive(false) + return true + end +end + +startup.wait('STATE_STARTED') +-- call moveCamera() repeatedly until it returns true +local timer = timers.Timer(0.1, moveCamera, true) -- cgit v1.2.3 From cdc4f5dbd69526906724dc298594906826f6b8b0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 7 Aug 2024 16:34:14 -0400 Subject: Move #include "coro_scheduler.h" from llstartup to llappviewer. --- indra/newview/llappviewer.cpp | 1 + indra/newview/llstartup.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3d53200eda..c259275d8f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -29,6 +29,7 @@ #include "llappviewer.h" // Viewer includes +#include "coro_scheduler.h" #include "llversioninfo.h" #include "llfeaturemanager.h" #include "lluictrlfactory.h" diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 82eb59c002..d49e0d9ba2 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -48,7 +48,6 @@ #include "llaudioengine_openal.h" #endif -#include "coro_scheduler.h" #include "llavatarnamecache.h" #include "llexperiencecache.h" #include "lllandmark.h" -- cgit v1.2.3 From b4fe47a5c0abac02d161640e04a9a78afb1c5987 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 8 Aug 2024 09:07:56 -0400 Subject: Ensure that the flycam stays near moving avatar. --- indra/newview/scripts/lua/test_flycam.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_flycam.lua b/indra/newview/scripts/lua/test_flycam.lua index 4fb5608b33..05c3c37b93 100644 --- a/indra/newview/scripts/lua/test_flycam.lua +++ b/indra/newview/scripts/lua/test_flycam.lua @@ -4,7 +4,6 @@ local LLAgent = require 'LLAgent' local startup = require 'startup' local timers = require 'timers' -local initial = LLAgent.getRegionPosition() local height = 2.0 -- meters local radius = 4.0 -- meters local speed = 1.0 -- meters/second along circle @@ -12,11 +11,12 @@ local start = os.clock() local stop = os.clock() + 30 -- seconds local function cameraPos(t) + local agent = LLAgent.getRegionPosition() local radians = speed * t return { - initial[1] + radius * math.cos(radians), - initial[2] + radius * math.sin(radians), - initial[3] + height + agent[1] + radius * math.cos(radians), + agent[2] + radius * math.sin(radians), + agent[3] + height } end -- cgit v1.2.3 From 087cbe553e5bac6fe702200c33acc42baf4eef4f Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 9 Aug 2024 15:00:04 +0300 Subject: Lua api for sending group messages --- indra/newview/groupchatlistener.cpp | 100 +++++++++++++++++++-------- indra/newview/groupchatlistener.h | 21 ++++-- indra/newview/llgroupactions.cpp | 8 ++- indra/newview/lltoastimpanel.cpp | 4 +- indra/newview/scripts/lua/require/LLChat.lua | 25 +++++++ 5 files changed, 119 insertions(+), 39 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index 43507f13e9..ab367d9fa1 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -2,11 +2,11 @@ * @file groupchatlistener.cpp * @author Nat Goodspeed * @date 2011-04-11 - * @brief Implementation for groupchatlistener. + * @brief Implementation for LLGroupChatListener. * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. + * Copyright (C) 2024, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -34,43 +34,85 @@ // std headers // external library headers // other Linden headers +#include "llchat.h" #include "llgroupactions.h" #include "llimview.h" +static const F32 GROUP_CHAT_THROTTLE_PERIOD = 1.f; -namespace { - void startIm_wrapper(LLSD const & event) +LLGroupChatListener::LLGroupChatListener(): + LLEventAPI("GroupChat", + "API to enter, leave, send and intercept group chat messages"), + mLastThrottleTime(0) +{ + add("startGroupChat", + "Enter a group chat in group with UUID [\"group_id\"]\n" + "Assumes the logged-in agent is already a member of this group.", + &LLGroupChatListener::startGroupChat, + llsd::map("group_id", LLSD())); + add("leaveGroupChat", + "Leave a group chat in group with UUID [\"group_id\"]\n" + "Assumes a prior successful startIM request.", + &LLGroupChatListener::leaveGroupChat, + llsd::map("group_id", LLSD())); + add("sendGroupIM", + "send a groupchat IM", + &LLGroupChatListener::sendGroupIM, + llsd::map("message", LLSD(), "group_id", LLSD())); +} + +bool is_in_group(LLEventAPI::Response &response, const LLSD &data) +{ + if (!LLGroupActions::isInGroup(data["group_id"])) { - LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID()); - sendReply(LLSDMap("session_id", LLSD(session_id)), event); + response.error(stringize("You are not the member of the group:", std::quoted(data["group_id"].asString()))); + return false; } + return true; +} - void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id) +void LLGroupChatListener::startGroupChat(LLSD const &data) +{ + Response response(LLSD(), data); + if (!is_in_group(response, data)) { - LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START); + return; + } + if (LLGroupActions::startIM(data["group_id"]).isNull()) + { + return response.error(stringize("Failed to start group chat session ", std::quoted(data["group_id"].asString()))); } } +void LLGroupChatListener::leaveGroupChat(LLSD const &data) +{ + Response response(LLSD(), data); + if (is_in_group(response, data)) + { + LLGroupActions::endIM(data["group_id"].asUUID()); + } +} -GroupChatListener::GroupChatListener(): - LLEventAPI("GroupChat", - "API to enter, leave, send and intercept group chat messages") +void LLGroupChatListener::sendGroupIM(LLSD const &data) { - add("startIM", - "Enter a group chat in group with UUID [\"id\"]\n" - "Assumes the logged-in agent is already a member of this group.", - &startIm_wrapper); - add("endIM", - "Leave a group chat in group with UUID [\"id\"]\n" - "Assumes a prior successful startIM request.", - &LLGroupActions::endIM, - llsd::array("id")); - add("sendIM", - "send a groupchat IM", - &send_message_wrapper, - llsd::array("text", "session_id", "group_id")); + Response response(LLSD(), data); + if (!is_in_group(response, data)) + { + return; + } + + F64 cur_time = LLTimer::getElapsedSeconds(); + + if (cur_time < mLastThrottleTime + GROUP_CHAT_THROTTLE_PERIOD) + { + LL_DEBUGS("LLGroupChatListener") << "'sendGroupIM' was throttled" << LL_ENDL; + return; + } + mLastThrottleTime = cur_time; + + LLUUID group_id(data["group_id"]); + LLIMModel::sendMessage(LUA_PREFIX + data["message"].asString(), + gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), + group_id, + IM_SESSION_GROUP_START); } -/* - static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, - const LLUUID& other_participant_id, EInstantMessage dialog); -*/ diff --git a/indra/newview/groupchatlistener.h b/indra/newview/groupchatlistener.h index 3819ac59b7..35afc5766c 100644 --- a/indra/newview/groupchatlistener.h +++ b/indra/newview/groupchatlistener.h @@ -4,9 +4,9 @@ * @date 2011-04-11 * @brief * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. + * Copyright (C) 2024, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,15 +26,22 @@ * $/LicenseInfo$ */ -#if ! defined(LL_GROUPCHATLISTENER_H) -#define LL_GROUPCHATLISTENER_H +#if ! defined(LL_LLGROUPCHATLISTENER_H) +#define LL_LLGROUPCHATLISTENER_H #include "lleventapi.h" -class GroupChatListener: public LLEventAPI +class LLGroupChatListener: public LLEventAPI { public: - GroupChatListener(); + LLGroupChatListener(); + +private: + void startGroupChat(LLSD const &data); + void leaveGroupChat(LLSD const &data); + void sendGroupIM(LLSD const &data); + + F64 mLastThrottleTime {0.0}; }; -#endif /* ! defined(LL_GROUPCHATLISTENER_H) */ +#endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */ diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 24ae90e3ae..e901631d94 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -37,6 +37,7 @@ #include "llfloatersidepanelcontainer.h" #include "llgroupmgr.h" #include "llfloaterimcontainer.h" +#include "llfloaterimsession.h" #include "llimview.h" // for gIMMgr #include "llnotificationsutil.h" #include "llstartup.h" @@ -46,7 +47,7 @@ // // Globals // -static GroupChatListener sGroupChatListener; +static LLGroupChatListener sGroupChatListener; class LLGroupHandler : public LLCommandHandler { @@ -519,7 +520,10 @@ void LLGroupActions::endIM(const LLUUID& group_id) LLUUID session_id = gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id); if (session_id != LLUUID::null) { - gIMMgr->leaveSession(session_id); + if (LLFloaterIMSession *conversationFloater = LLFloaterIMSession::findInstance(session_id)) + { + LLFloater::onClickClose(conversationFloater); + } } } diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index f7e2d49e13..7fadd8773b 100644 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -87,7 +87,9 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif { LLAvatarName avatar_name; LLAvatarNameCache::get(p.avatar_id, &avatar_name); - p.message = "[From " + avatar_name.getDisplayName() + "]\n" + p.message; + auto [message, is_lua] = LLStringUtil::withoutPrefix(p.message, LUA_PREFIX); + std::string prefix = is_lua ? "LUA - " : ""; + p.message = "[From " + prefix + avatar_name.getDisplayName() + "]\n" + message; } style_params.font.style = "NORMAL"; mMessage->setText(p.message, style_params); diff --git a/indra/newview/scripts/lua/require/LLChat.lua b/indra/newview/scripts/lua/require/LLChat.lua index 78dca765e8..ea6329d574 100644 --- a/indra/newview/scripts/lua/require/LLChat.lua +++ b/indra/newview/scripts/lua/require/LLChat.lua @@ -2,6 +2,10 @@ local leap = require 'leap' local LLChat = {} +-- *************************************************************************** +-- Nearby chat +-- *************************************************************************** + function LLChat.sendNearby(msg) leap.send('LLChatBar', {op='sendChat', message=msg}) end @@ -14,4 +18,25 @@ function LLChat.sendShout(msg) leap.send('LLChatBar', {op='sendChat', type='shout', message=msg}) end +-- 0 is public nearby channel, other channels are used to communicate with LSL scripts +function LLChat.sendChannel(msg, channel) + leap.send('LLChatBar', {op='sendChat', channel=channel, message=msg}) +end + +-- *************************************************************************** +-- Group chat +-- *************************************************************************** + +function LLChat.startGroupChat(group_id) + return leap.request('GroupChat', {op='startGroupChat', group_id=group_id}) +end + +function LLChat.leaveGroupChat(group_id) + leap.send('GroupChat', {op='leaveGroupChat', group_id=group_id}) +end + +function LLChat.sendGroupIM(msg, group_id) + leap.send('GroupChat', {op='sendGroupIM', message=msg, group_id=group_id}) +end + return LLChat -- cgit v1.2.3 From 926a32aa0a9518fe7f19d0c63b30b12a66469f2d Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 9 Aug 2024 18:24:25 +0300 Subject: add demo script for sending group chat messages --- indra/newview/groupchatlistener.cpp | 4 ++-- indra/newview/scripts/lua/require/LLAgent.lua | 11 +++++++++++ indra/newview/scripts/lua/test_group_chat.lua | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 indra/newview/scripts/lua/test_group_chat.lua (limited to 'indra/newview') diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index ab367d9fa1..09951ba1cc 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -56,7 +56,7 @@ LLGroupChatListener::LLGroupChatListener(): &LLGroupChatListener::leaveGroupChat, llsd::map("group_id", LLSD())); add("sendGroupIM", - "send a groupchat IM", + "send a [\"message\"] to group with UUID [\"group_id\"]", &LLGroupChatListener::sendGroupIM, llsd::map("message", LLSD(), "group_id", LLSD())); } @@ -114,5 +114,5 @@ void LLGroupChatListener::sendGroupIM(LLSD const &data) LLIMModel::sendMessage(LUA_PREFIX + data["message"].asString(), gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), group_id, - IM_SESSION_GROUP_START); + IM_SESSION_SEND); } diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index bc9a6b23a0..5ee092f2f6 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -11,6 +11,17 @@ function LLAgent.getGlobalPosition() return leap.request('LLAgent', {op = 'getPosition'}).global end +-- Return array information about the agent's groups +-- id: group id\n" +-- name: group name\n" +-- insignia: group insignia texture id +-- notices: bool indicating if this user accepts notices from this group +-- display: bool indicating if this group is listed in the user's profile +-- contrib: user's land contribution to this group +function LLAgent.getGroups() + return leap.request('LLAgent', {op = 'getGroups'}).groups +end + -- Use LL.leaphelp('LLAgent') and see 'setCameraParams' to get more info about params -- -- TYPE -- DEFAULT -- RANGE -- LLAgent.setCamera{ [, camera_pos] -- vector3 diff --git a/indra/newview/scripts/lua/test_group_chat.lua b/indra/newview/scripts/lua/test_group_chat.lua new file mode 100644 index 0000000000..6299ba535f --- /dev/null +++ b/indra/newview/scripts/lua/test_group_chat.lua @@ -0,0 +1,16 @@ +LLChat = require 'LLChat' +inspect = require 'inspect' +LLAgent = require 'LLAgent' +popup = require 'popup' + +local OK = 'OK_okcancelbuttons' +local GROUPS = LLAgent.getGroups() + +-- Choose one of the groups randomly and send group message +math.randomseed(os.time()) +group_info = GROUPS[math.random(#GROUPS)] +LLChat.startGroupChat(group_info.id) +response = popup:alertYesCancel('Started group chat with ' .. group_info.name .. ' group. Send greetings?') +if next(response) == OK then + LLChat.sendGroupIM('Greetings', group_info.id) +end -- cgit v1.2.3 From a596c1ad2864d639bbab13e7f13fd9f029cf5d93 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 12 Aug 2024 15:58:03 -0400 Subject: Add Throttle and LogThrottle classes to manage throttled APIs. --- indra/newview/groupchatlistener.cpp | 19 ++++++++----------- indra/newview/groupchatlistener.h | 4 +++- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index 09951ba1cc..298f41ff8c 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -43,7 +43,8 @@ static const F32 GROUP_CHAT_THROTTLE_PERIOD = 1.f; LLGroupChatListener::LLGroupChatListener(): LLEventAPI("GroupChat", "API to enter, leave, send and intercept group chat messages"), - mLastThrottleTime(0) + mIMThrottle("sendGroupIM", &LLGroupChatListener::sendGroupIM_, this, + GROUP_CHAT_THROTTLE_PERIOD) { add("startGroupChat", "Enter a group chat in group with UUID [\"group_id\"]\n" @@ -101,18 +102,14 @@ void LLGroupChatListener::sendGroupIM(LLSD const &data) return; } - F64 cur_time = LLTimer::getElapsedSeconds(); - - if (cur_time < mLastThrottleTime + GROUP_CHAT_THROTTLE_PERIOD) - { - LL_DEBUGS("LLGroupChatListener") << "'sendGroupIM' was throttled" << LL_ENDL; - return; - } - mLastThrottleTime = cur_time; + mIMThrottle(data["group_id"], data["message"]); +} - LLUUID group_id(data["group_id"]); - LLIMModel::sendMessage(LUA_PREFIX + data["message"].asString(), +void LLGroupChatListener::sendGroupIM_(const LLUUID& group_id, const std::string& message) +{ + LLIMModel::sendMessage(LUA_PREFIX + message, gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), group_id, IM_SESSION_SEND); } + diff --git a/indra/newview/groupchatlistener.h b/indra/newview/groupchatlistener.h index 35afc5766c..a75fecb254 100644 --- a/indra/newview/groupchatlistener.h +++ b/indra/newview/groupchatlistener.h @@ -30,6 +30,7 @@ #define LL_LLGROUPCHATLISTENER_H #include "lleventapi.h" +#include "throttle.h" class LLGroupChatListener: public LLEventAPI { @@ -40,8 +41,9 @@ private: void startGroupChat(LLSD const &data); void leaveGroupChat(LLSD const &data); void sendGroupIM(LLSD const &data); + void sendGroupIM_(const LLUUID& group_id, const std::string& message); - F64 mLastThrottleTime {0.0}; + LogThrottle<LLError::LEVEL_DEBUG, void(const LLUUID&, const std::string&)> mIMThrottle; }; #endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */ -- cgit v1.2.3 From 9f2e322c7eea6830d372943d74f986d299cd314a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 13 Aug 2024 14:50:04 +0300 Subject: clean up and add comment --- indra/newview/groupchatlistener.cpp | 2 +- indra/newview/lltoastimpanel.cpp | 1 + indra/newview/scripts/lua/require/LLChat.lua | 10 +++------- indra/newview/scripts/lua/test_group_chat.lua | 1 - 4 files changed, 5 insertions(+), 9 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index 298f41ff8c..e48cbe824a 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -38,7 +38,7 @@ #include "llgroupactions.h" #include "llimview.h" -static const F32 GROUP_CHAT_THROTTLE_PERIOD = 1.f; +static const F64 GROUP_CHAT_THROTTLE_PERIOD = 1.f; LLGroupChatListener::LLGroupChatListener(): LLEventAPI("GroupChat", diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index 7fadd8773b..b7353d6960 100644 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -87,6 +87,7 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif { LLAvatarName avatar_name; LLAvatarNameCache::get(p.avatar_id, &avatar_name); + // move Lua prefix from the message field to the [From] field auto [message, is_lua] = LLStringUtil::withoutPrefix(p.message, LUA_PREFIX); std::string prefix = is_lua ? "LUA - " : ""; p.message = "[From " + prefix + avatar_name.getDisplayName() + "]\n" + message; diff --git a/indra/newview/scripts/lua/require/LLChat.lua b/indra/newview/scripts/lua/require/LLChat.lua index ea6329d574..bc0fc86d22 100644 --- a/indra/newview/scripts/lua/require/LLChat.lua +++ b/indra/newview/scripts/lua/require/LLChat.lua @@ -6,8 +6,9 @@ local LLChat = {} -- Nearby chat -- *************************************************************************** -function LLChat.sendNearby(msg) - leap.send('LLChatBar', {op='sendChat', message=msg}) +-- 0 is public nearby channel, other channels are used to communicate with LSL scripts +function LLChat.sendNearby(msg, channel) + leap.send('LLChatBar', {op='sendChat', message=msg, channel=channel}) end function LLChat.sendWhisper(msg) @@ -18,11 +19,6 @@ function LLChat.sendShout(msg) leap.send('LLChatBar', {op='sendChat', type='shout', message=msg}) end --- 0 is public nearby channel, other channels are used to communicate with LSL scripts -function LLChat.sendChannel(msg, channel) - leap.send('LLChatBar', {op='sendChat', channel=channel, message=msg}) -end - -- *************************************************************************** -- Group chat -- *************************************************************************** diff --git a/indra/newview/scripts/lua/test_group_chat.lua b/indra/newview/scripts/lua/test_group_chat.lua index 6299ba535f..eaff07ed14 100644 --- a/indra/newview/scripts/lua/test_group_chat.lua +++ b/indra/newview/scripts/lua/test_group_chat.lua @@ -1,5 +1,4 @@ LLChat = require 'LLChat' -inspect = require 'inspect' LLAgent = require 'LLAgent' popup = require 'popup' -- cgit v1.2.3 From b3fb23ee0c6d33f5eba3502328ffb0011b5f25fb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 15 Aug 2024 09:49:34 -0400 Subject: Introduce lluau_checkstack(L, n); use instead of luaL_checkstack(). luaL_checkstack() accepts a third parameter which is included in the stack overflow error message. We've been passing nullptr, leading to messages of the form "stack overflow ((null))". lluau_checkstack() implicitly passes __FUNCTION__, so we can distinguish which underlying luaL_checkstack() call encountered the stack overflow condition. Also, when calling each atexit() function, pass Luau's debug.traceback() function as the lua_pcall() error handler. This should help diagnose errors in atexit() functions. --- indra/newview/llluamanager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 7014c59e4e..0b1a73f4e9 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -66,7 +66,7 @@ std::string lua_print_msg(lua_State* L, const std::string_view& level) { // On top of existing Lua arguments, we're going to push tostring() and // duplicate each existing stack entry so we can stringize each one. - luaL_checkstack(L, 2, nullptr); + lluau_checkstack(L, 2); luaL_where(L, 1); // start with the 'where' info at the top of the stack std::ostringstream out; @@ -139,7 +139,7 @@ lua_function(get_event_pumps, "Events posted to replypump are queued for get_event_next().\n" "post_on(commandpump, ...) to engage LLEventAPI operations (see helpleap()).") { - luaL_checkstack(L, 2, nullptr); + lluau_checkstack(L, 2); auto& listener{ LuaState::obtainListener(L) }; // return the reply pump name and the command pump name on caller's lua_State lua_pushstdstring(L, listener.getReplyName()); @@ -153,7 +153,7 @@ lua_function(get_event_next, "is returned by get_event_pumps(). Blocks the calling chunk until an\n" "event becomes available.") { - luaL_checkstack(L, 2, nullptr); + lluau_checkstack(L, 2); auto& listener{ LuaState::obtainListener(L) }; const auto& [pump, data]{ listener.getNext() }; lua_pushstdstring(L, pump); -- cgit v1.2.3 From ab0f7ff14cd80b89524ba95eb5a39e2d6df55b26 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 15 Aug 2024 23:29:54 +0300 Subject: First batch of Inventory api; raise interrupts limit --- indra/newview/CMakeLists.txt | 2 + indra/newview/llinventorylistener.cpp | 130 ++++++++++++++++++++++ indra/newview/llinventorylistener.h | 45 ++++++++ indra/newview/llviewerinventory.cpp | 3 + indra/newview/scripts/lua/require/LLInventory.lua | 28 +++++ 5 files changed, 208 insertions(+) create mode 100644 indra/newview/llinventorylistener.cpp create mode 100644 indra/newview/llinventorylistener.h create mode 100644 indra/newview/scripts/lua/require/LLInventory.lua (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4e7e072289..04eb2c1d6d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -360,6 +360,7 @@ set(viewer_SOURCE_FILES llinventorygallerymenu.cpp llinventoryicon.cpp llinventoryitemslist.cpp + llinventorylistener.cpp llinventorylistitem.cpp llinventorymodel.cpp llinventorymodelbackgroundfetch.cpp @@ -1027,6 +1028,7 @@ set(viewer_HEADER_FILES llinventorygallerymenu.h llinventoryicon.h llinventoryitemslist.h + llinventorylistener.h llinventorylistitem.h llinventorymodel.h llinventorymodelbackgroundfetch.h diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp new file mode 100644 index 0000000000..a8269bb80d --- /dev/null +++ b/indra/newview/llinventorylistener.cpp @@ -0,0 +1,130 @@ +/** + * @file llinventorylistener.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llinventorylistener.h" + +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "lltransutil.h" +#include "llwearableitemslist.h" +#include "stringize.h" + +LLInventoryListener::LLInventoryListener() + : LLEventAPI("LLInventory", + "API for interactions with viewer Inventory items") +{ + add("getItemsInfo", + "Return information about items or folders defined in [\"items_id\"]:\n" + "reply will contain [\"items\"] and [\"categories\"] tables accordingly", + &LLInventoryListener::getItemsInfo, + llsd::map("items_id", LLSD(), "reply", LLSD())); + + add("getFolderTypeNames", + "Return the table of folder type names, contained in [\"type_names\"]\n", + &LLInventoryListener::getFolderTypeNames, + llsd::map("reply", LLSD())); + + add("getBasicFolderID", + "Return the UUID of the folder by specified folder type name, for example:\n" + "\"Textures\", \"My outfits\", \"Sounds\" and other basic folders which have associated type", + &LLInventoryListener::getBasicFolderID, + llsd::map("ft_name", LLSD(), "reply", LLSD())); + + add("getDirectDescendents", + "Return the direct descendents(both items and folders) of the [\"folder_id\"]", + &LLInventoryListener::getDirectDescendents, + llsd::map("folder_id", LLSD(), "reply", LLSD())); + } + + +void add_item_info(LLEventAPI::Response& response, LLViewerInventoryItem* item) +{ + response["items"].insert(item->getUUID().asString(), + llsd::map("name", item->getName(), "parent_id", item->getParentUUID(), "desc", item->getDescription(), + "inv_type", LLInventoryType::lookup(item->getInventoryType()), "creation_date", + (S32) item->getCreationDate(), "asset_id", item->getAssetUUID(), "is_link", item->getIsLinkType(), + "linked_id", item->getLinkedUUID())); +} + +void add_cat_info(LLEventAPI::Response &response, LLViewerInventoryCategory *cat) +{ + response["categories"].insert(cat->getUUID().asString(), + llsd::map("name", cat->getName(), "parent_id", cat->getParentUUID(), "type", + LLFolderType::lookup(cat->getPreferredType()), "creation_date", (S32) cat->getCreationDate(), + "is_link", cat->getIsLinkType(), "linked_id", cat->getLinkedUUID())); +} + +void LLInventoryListener::getItemsInfo(LLSD const &data) +{ + Response response(LLSD(), data); + + uuid_vec_t ids = LLSDParam<uuid_vec_t>(data["items_id"]); + for (auto &it : ids) + { + LLViewerInventoryItem* item = gInventory.getItem(it); + if (item) + { + add_item_info(response, item); + } + LLViewerInventoryCategory* cat = gInventory.getCategory(it); + if (cat) + { + add_cat_info(response, cat); + } + } +} + +void LLInventoryListener::getFolderTypeNames(LLSD const &data) +{ + Response response(llsd::map("type_names", LLFolderType::getTypeNames()), data); +} + +void LLInventoryListener::getBasicFolderID(LLSD const &data) +{ + Response response(llsd::map("id", gInventory.findCategoryUUIDForType(LLFolderType::lookup(data["ft_name"].asString()))), data); +} + + +void LLInventoryListener::getDirectDescendents(LLSD const &data) +{ + Response response(LLSD(), data); + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(data["folder_id"], cats, items); + + LLInventoryModel::item_array_t items_copy = *items; + for (LLInventoryModel::item_array_t::iterator iter = items_copy.begin(); iter != items_copy.end(); iter++) + { + add_item_info(response, *iter); + } + LLInventoryModel::cat_array_t cats_copy = *cats; + for (LLInventoryModel::cat_array_t::iterator iter = cats_copy.begin(); iter != cats_copy.end(); iter++) + { + add_cat_info(response, *iter); + } +} + diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h new file mode 100644 index 0000000000..e148df48fe --- /dev/null +++ b/indra/newview/llinventorylistener.h @@ -0,0 +1,45 @@ +/** + * @file llinventorylistener.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLINVENTORYLISTENER_H +#define LL_LLINVENTORYLISTENER_H + +#include "lleventapi.h" + +class LLInventoryListener : public LLEventAPI +{ +public: + LLInventoryListener(); + +private: + void getItemsInfo(LLSD const &data); + void getFolderTypeNames(LLSD const &data); + void getBasicFolderID(LLSD const &data); + void getDirectDescendents(LLSD const &data); +}; + +#endif // LL_LLINVENTORYLISTENER_H + diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 16810efa01..7030426e21 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -71,6 +71,9 @@ #include "llclipboard.h" #include "llhttpretrypolicy.h" #include "llsettingsvo.h" +#include "llinventorylistener.h" + +LLInventoryListener sInventoryListener; // do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua new file mode 100644 index 0000000000..880a2516f1 --- /dev/null +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -0,0 +1,28 @@ +local leap = require 'leap' +local mapargs = require 'mapargs' + +local LLInventory = {} + +-- Get the items/folders info by provided IDs, +-- reply will contain "items" and "categories" tables accordingly +function LLInventory.getItemsInfo(items_id) + return leap.request('LLInventory', {op = 'getItemsInfo', items_id=items_id}) +end + +-- Get the table of folder type names, which can be later used to get the ID of the basic folders +function LLInventory.getFolderTypeNames() + return leap.request('LLInventory', {op = 'getFolderTypeNames'}).type_names +end + +-- Get the UUID of the basic folder("Textures", "My outfits", "Sounds" etc.) by specified folder type name +function LLInventory.getBasicFolderID(ft_name) + return leap.request('LLInventory', {op = 'getBasicFolderID', ft_name=ft_name}).id +end + +-- Get the direct descendents of the 'folder_id' provided, +-- reply will contain "items" and "categories" tables accordingly +function LLInventory.getDirectDescendents(folder_id) + return leap.request('LLInventory', {op = 'getDirectDescendents', folder_id=folder_id}) +end + +return LLInventory -- cgit v1.2.3 From 3cef79d979f2d21c29d17d123d6c166b9f7e7e0e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 20 Aug 2024 23:09:14 +0300 Subject: Add collectDescendentsIf api for Lua --- indra/newview/llinventorylistener.cpp | 140 +++++++++++++++++++++- indra/newview/llinventorylistener.h | 27 +++++ indra/newview/scripts/lua/require/LLInventory.lua | 19 +++ 3 files changed, 180 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index a8269bb80d..4beb59c58e 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -48,6 +48,11 @@ LLInventoryListener::LLInventoryListener() &LLInventoryListener::getFolderTypeNames, llsd::map("reply", LLSD())); + add("getAssetTypeNames", + "Return the table of asset type names, contained in [\"type_names\"]\n", + &LLInventoryListener::getAssetTypeNames, + llsd::map("reply", LLSD())); + add("getBasicFolderID", "Return the UUID of the folder by specified folder type name, for example:\n" "\"Textures\", \"My outfits\", \"Sounds\" and other basic folders which have associated type", @@ -58,6 +63,15 @@ LLInventoryListener::LLInventoryListener() "Return the direct descendents(both items and folders) of the [\"folder_id\"]", &LLInventoryListener::getDirectDescendents, llsd::map("folder_id", LLSD(), "reply", LLSD())); + + add("collectDescendentsIf", + "Return the descendents(both items and folders) of the [\"folder_id\"], if it passes specified filters:\n" + "[\"name\"] is a substring of object's name,\n" + "[\"desc\"] is a substring of object's description,\n" + "asset [\"type\"] corresponds to the object's asset type\n" + "[\"filter_links\"]: EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)", + &LLInventoryListener::collectDescendentsIf, + llsd::map("folder_id", LLSD(), "reply", LLSD())); } @@ -65,17 +79,15 @@ void add_item_info(LLEventAPI::Response& response, LLViewerInventoryItem* item) { response["items"].insert(item->getUUID().asString(), llsd::map("name", item->getName(), "parent_id", item->getParentUUID(), "desc", item->getDescription(), - "inv_type", LLInventoryType::lookup(item->getInventoryType()), "creation_date", - (S32) item->getCreationDate(), "asset_id", item->getAssetUUID(), "is_link", item->getIsLinkType(), - "linked_id", item->getLinkedUUID())); + "inv_type", LLInventoryType::lookup(item->getInventoryType()), "asset_type", LLAssetType::lookup(item->getType()), + "creation_date", (S32) item->getCreationDate(), "asset_id", item->getAssetUUID(), + "is_link", item->getIsLinkType(), "linked_id", item->getLinkedUUID())); } void add_cat_info(LLEventAPI::Response &response, LLViewerInventoryCategory *cat) { response["categories"].insert(cat->getUUID().asString(), - llsd::map("name", cat->getName(), "parent_id", cat->getParentUUID(), "type", - LLFolderType::lookup(cat->getPreferredType()), "creation_date", (S32) cat->getCreationDate(), - "is_link", cat->getIsLinkType(), "linked_id", cat->getLinkedUUID())); + llsd::map("name", cat->getName(), "parent_id", cat->getParentUUID(), "type", LLFolderType::lookup(cat->getPreferredType()))); } void LLInventoryListener::getItemsInfo(LLSD const &data) @@ -103,6 +115,11 @@ void LLInventoryListener::getFolderTypeNames(LLSD const &data) Response response(llsd::map("type_names", LLFolderType::getTypeNames()), data); } +void LLInventoryListener::getAssetTypeNames(LLSD const &data) +{ + Response response(llsd::map("type_names", LLAssetType::getTypeNames()), data); +} + void LLInventoryListener::getBasicFolderID(LLSD const &data) { Response response(llsd::map("id", gInventory.findCategoryUUIDForType(LLFolderType::lookup(data["ft_name"].asString()))), data); @@ -128,3 +145,114 @@ void LLInventoryListener::getDirectDescendents(LLSD const &data) } } +void LLInventoryListener::collectDescendentsIf(LLSD const &data) +{ + Response response(LLSD(), data); + LLUUID folder_id(data["folder_id"].asUUID()); + LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); + if (!cat) + { + return response.error(stringize("Folder ", std::quoted(data["folder_id"].asString()), " was not found")); + } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLFilteredCollector collector = LLFilteredCollector(data); + + gInventory.collectDescendentsIf(folder_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); + + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); iter != item_array.end(); iter++) + { + add_item_info(response, *iter); + } + for (LLInventoryModel::cat_array_t::iterator iter = cat_array.begin(); iter != cat_array.end(); iter++) + { + add_cat_info(response, *iter); + } +} + +LLFilteredCollector::LLFilteredCollector(LLSD const &data) + : mType(LLAssetType::EType::AT_UNKNOWN), + mLinkFilter(INCLUDE_LINKS) +{ + if (data.has("name")) + { + mName = data["name"]; + } + if (data.has("desc")) + { + mDesc = data["desc"]; + } + if (data.has("type")) + { + mType = LLAssetType::lookup(data["type"]); + } + if (data.has("filter_links")) + { + if (data["filter_links"] == "EXCLUDE_LINKS") + { + mLinkFilter = EXCLUDE_LINKS; + } + else if (data["filter_links"] == "ONLY_LINKS") + { + mLinkFilter = ONLY_LINKS; + } + } +} + +bool LLFilteredCollector::operator()(LLInventoryCategory *cat, LLInventoryItem *item) +{ + bool passed = checkagainstType(cat, item); + passed = passed && checkagainstNameDesc(cat, item); + passed = passed && checkagainstLinks(cat, item); + + return passed; +} + +bool LLFilteredCollector::checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item) +{ + std::string name, desc; + bool passed(true); + if (cat) + { + if (!mDesc.empty()) return false; + name = cat->getName(); + } + if (item) + { + name = item->getName(); + passed = (mDesc.size() ? item->getDescription().find(mDesc) != std::string::npos : true); + } + + return passed && (mName.size() ? name.find(mName) != std::string::npos : true); +} + +bool LLFilteredCollector::checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item) +{ + if (mType == LLAssetType::AT_UNKNOWN) + { + return true; + } + if (mType == LLAssetType::AT_CATEGORY) + { + if (cat) + { + return true; + } + } + if (item && item->getType() == mType) + { + return true; + } + return false; +} + +bool LLFilteredCollector::checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item) +{ + bool is_link = cat ? cat->getIsLinkType() : item->getIsLinkType(); + if (is_link && (mLinkFilter == EXCLUDE_LINKS)) + return false; + if (!is_link && (mLinkFilter == ONLY_LINKS)) + return false; + return true; +} diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h index e148df48fe..83e1751e1b 100644 --- a/indra/newview/llinventorylistener.h +++ b/indra/newview/llinventorylistener.h @@ -28,6 +28,7 @@ #define LL_LLINVENTORYLISTENER_H #include "lleventapi.h" +#include "llinventoryfunctions.h" class LLInventoryListener : public LLEventAPI { @@ -37,8 +38,34 @@ public: private: void getItemsInfo(LLSD const &data); void getFolderTypeNames(LLSD const &data); + void getAssetTypeNames(LLSD const &data); void getBasicFolderID(LLSD const &data); void getDirectDescendents(LLSD const &data); + void collectDescendentsIf(LLSD const &data); +}; + +struct LLFilteredCollector : public LLInventoryCollectFunctor +{ + enum EFilterLink + { + INCLUDE_LINKS, // show links too + EXCLUDE_LINKS, // don't show links + ONLY_LINKS // only show links + }; + + LLFilteredCollector(LLSD const &data); + virtual ~LLFilteredCollector() {} + virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); + + protected: + bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item); + bool checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item); + bool checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item); + + LLAssetType::EType mType; + std::string mName; + std::string mDesc; + EFilterLink mLinkFilter; }; #endif // LL_LLINVENTORYLISTENER_H diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index 880a2516f1..e6a347532b 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -19,10 +19,29 @@ function LLInventory.getBasicFolderID(ft_name) return leap.request('LLInventory', {op = 'getBasicFolderID', ft_name=ft_name}).id end +-- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendentsIf(...) +function LLInventory.getAssetTypeNames() + return leap.request('LLInventory', {op = 'getAssetTypeNames'}).type_names +end + -- Get the direct descendents of the 'folder_id' provided, -- reply will contain "items" and "categories" tables accordingly function LLInventory.getDirectDescendents(folder_id) return leap.request('LLInventory', {op = 'getDirectDescendents', folder_id=folder_id}) end +-- Get the descendents of the 'folder_id' provided, which pass specified filters +-- reply will contain "items" and "categories" tables accordingly +-- LLInventory.collectDescendentsIf{ folder_id -- parent folder ID +-- [, name] -- name (substring) +-- [, desc] -- description (substring) +-- [, type] -- asset type +-- [, filter_links]} -- EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default) +function LLInventory.collectDescendentsIf(...) + local args = mapargs('folder_id,name,desc,type,filter_links', ...) + args.op = 'collectDescendentsIf' + return leap.request('LLInventory', args) +end + + return LLInventory -- cgit v1.2.3 From 376c890c095fbc59b83402255cc1036c411150b9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 20 Aug 2024 21:12:25 -0400 Subject: Fix for #2237: intermittent Lua data stack overflow. Use a static unordered_map to allow a function receiving (lua_State* L) to look up the LuaState instance managing that lua_State. We've thought about this from time to time already. LuaState's constructor creates the map entry; its destructor removes it; the new static getParent(lua_State* L) method performs the lookup. Migrate lluau::set_interrupts_counter() and check_interrupts_counter() into LuaState member functions. Add a new mInterrupts counter for them. Importantly, LuaState::check_interrupts_counter(), which is indirectly called by a lua_callbacks().interrupt function, no longer performs any Lua stack operations. Empirically, it seems the Lua engine is capable of interrupting itself at a moment when re-entry confuses it. Change previous lluau::set_interrupts_counter(L, 0) calls to LuaState::getParent(L).set_interrupts_counter(0). Also add LuaStackDelta class, and a lua_checkdelta() helper macro, to verify that the Lua data stack depth on exit from a block differs from the depth on entry by exactly the expected amount. Sprinkle lua_checkdelta() macros in likely places. --- indra/newview/llluamanager.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 0b1a73f4e9..6de8829308 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -53,6 +53,7 @@ std::map<std::string, std::string> LLLUAmanager::sScriptNames; lua_function(sleep, "sleep(seconds): pause the running coroutine") { + lua_checkdelta(L, -1); F32 seconds = lua_tonumber(L, -1); lua_pop(L, 1); llcoro::suspendUntilTimeout(seconds); @@ -125,6 +126,7 @@ lua_function(print_warning, "print_warning(args...): WARNING level logging") lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLEventPump") { + lua_checkdelta(L, -2); std::string pumpname{ lua_tostdstring(L, 1) }; LLSD data{ lua_tollsd(L, 2) }; lua_pop(L, 2); @@ -139,6 +141,7 @@ lua_function(get_event_pumps, "Events posted to replypump are queued for get_event_next().\n" "post_on(commandpump, ...) to engage LLEventAPI operations (see helpleap()).") { + lua_checkdelta(L, 2); lluau_checkstack(L, 2); auto& listener{ LuaState::obtainListener(L) }; // return the reply pump name and the command pump name on caller's lua_State @@ -153,6 +156,7 @@ lua_function(get_event_next, "is returned by get_event_pumps(). Blocks the calling chunk until an\n" "event becomes available.") { + lua_checkdelta(L, 2); lluau_checkstack(L, 2); auto& listener{ LuaState::obtainListener(L) }; const auto& [pump, data]{ listener.getNext() }; @@ -271,6 +275,7 @@ std::string read_file(const std::string &name) lua_function(require, "require(module_name) : load module_name.lua from known places") { + lua_checkdelta(L); std::string name = lua_tostdstring(L, 1); lua_pop(L, 1); -- cgit v1.2.3 From d37aa5c1823fcb202e87b1457842e49655c72b95 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 20 Aug 2024 21:22:46 -0400 Subject: Defend timers.Timer(iterate=True) against long callbacks. Specifically, defend against a callback that runs so long it suspends at a point after the next timer tick. --- indra/newview/scripts/lua/require/timers.lua | 34 +++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/timers.lua b/indra/newview/scripts/lua/require/timers.lua index e4938078dc..ab1615ffbf 100644 --- a/indra/newview/scripts/lua/require/timers.lua +++ b/indra/newview/scripts/lua/require/timers.lua @@ -34,35 +34,53 @@ function timers.Timer:new(delay, callback, iterate) callback = callback or function() obj:tick() end - local first = true + local calls = 0 if iterate then + -- With iterative timers, beware of running a timer callback which + -- performs async actions lasting longer than the timer interval. The + -- lengthy callback suspends, allowing leap to retrieve the next + -- event, which is a timer tick. leap calls a new instance of the + -- callback, even though the previous callback call is still + -- suspended... etc. 'in_callback' defends against that recursive + -- case. Rather than re-enter the suspended callback, drop the + -- too-soon timer event. (We could count the too-soon timer events and + -- iterate calling the callback, but it's a bathtub problem: the + -- callback could end up getting farther and farther behind.) + local in_callback = false obj.id = leap.eventstream( 'Timers', {op='scheduleEvery', every=delay}, function (event) local reqid = event.reqid - if first then - first = false + calls += 1 + if calls == 1 then dbg('timer(%s) first callback', reqid) -- discard the first (immediate) response: don't call callback return nil else - dbg('timer(%s) nth callback', reqid) - return callback(event) + if in_callback then + dbg('dropping timer(%s) callback %d', reqid, calls) + else + dbg('timer(%s) callback %d', reqid, calls) + in_callback = true + local ret = callback(event) + in_callback = false + return ret + end end end ).reqid - else + else -- (not iterate) obj.id = leap.eventstream( 'Timers', {op='scheduleAfter', after=delay}, function (event) + calls += 1 -- Arrange to return nil the first time, true the second. This -- callback is called immediately with the response to -- 'scheduleAfter', and if we immediately returned true, we'd -- be done, and the subsequent timer event would be discarded. - if first then - first = false + if calls == 1 then -- Caller doesn't expect an immediate callback. return nil else -- cgit v1.2.3 From 409745eb370d7609df70da81584142dffbfe9d3f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 20 Aug 2024 21:41:26 -0400 Subject: Fix a couple more set_interrupts_counter() calls. --- indra/newview/llluamanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 6de8829308..22b51d7b72 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -57,7 +57,7 @@ lua_function(sleep, "sleep(seconds): pause the running coroutine") F32 seconds = lua_tonumber(L, -1); lua_pop(L, 1); llcoro::suspendUntilTimeout(seconds); - lluau::set_interrupts_counter(L, 0); + LuaState::getParent(L).set_interrupts_counter(0); return 0; }; @@ -162,7 +162,7 @@ lua_function(get_event_next, const auto& [pump, data]{ listener.getNext() }; lua_pushstdstring(L, pump); lua_pushllsd(L, data); - lluau::set_interrupts_counter(L, 0); + LuaState::getParent(L).set_interrupts_counter(0); return 2; } -- cgit v1.2.3 From 3ab6f187737de7d459efb33d887dc42b1263f087 Mon Sep 17 00:00:00 2001 From: Nicky <nicky.dasmijn@posteo.nl> Date: Wed, 21 Aug 2024 12:27:43 +0200 Subject: Remove packaging of libexpat.so*, this library is no statically linked. --- indra/newview/viewer_manifest.py | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 15cec11330..0428c6e3d5 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1409,7 +1409,6 @@ class Linux_x86_64_Manifest(LinuxManifest): with self.prefix(src=relpkgdir, dst="lib"): self.path("libapr-1.so*") self.path("libaprutil-1.so*") - self.path("libexpat.so.*") self.path_optional("libSDL*.so.*") self.path_optional("libjemalloc*.so") -- cgit v1.2.3 From 0e0e1accb62ccd3c703ab031ae9cfe0260fcfa01 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Wed, 21 Aug 2024 20:23:27 +0300 Subject: Fix implicit conversion error in llvoicewebrtc.cpp --- indra/newview/llvoicewebrtc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 4d4f5dc9e9..af93bdcaf0 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2750,7 +2750,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() case VOICE_STATE_SESSION_UP: { mRetryWaitPeriod = 0; - mRetryWaitSecs = (F32)((F32) rand() / (RAND_MAX)) + 0.5f; + mRetryWaitSecs = (F32)((F32)rand() / (F32)RAND_MAX) + 0.5f; LLUUID agentRegionID; if (isSpatial() && gAgent.getRegion()) { -- cgit v1.2.3 From 86eec90d97c03ac0f6be8897041185c6b5601968 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 21 Aug 2024 20:43:38 +0300 Subject: Add item limit for collectDescendentsIf func; add demo script --- indra/newview/llinventoryfunctions.h | 2 ++ indra/newview/llinventorylistener.cpp | 26 +++++++++++++++++++---- indra/newview/llinventorylistener.h | 4 ++++ indra/newview/llinventorymodel.cpp | 8 +++++++ indra/newview/scripts/lua/require/LLInventory.lua | 3 ++- indra/newview/scripts/lua/test_LLInventory.lua | 21 ++++++++++++++++++ 6 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 indra/newview/scripts/lua/test_LLInventory.lua (limited to 'indra/newview') diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 78077d2007..f6d910820d 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -189,6 +189,8 @@ public: virtual ~LLInventoryCollectFunctor(){}; virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; + virtual bool exceedsLimit() { return false; } + static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); }; diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index 4beb59c58e..4ff25f7f5c 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -33,6 +33,8 @@ #include "llwearableitemslist.h" #include "stringize.h" +static const F32 MAX_ITEM_LIMIT = 100; + LLInventoryListener::LLInventoryListener() : LLEventAPI("LLInventory", "API for interactions with viewer Inventory items") @@ -68,7 +70,8 @@ LLInventoryListener::LLInventoryListener() "Return the descendents(both items and folders) of the [\"folder_id\"], if it passes specified filters:\n" "[\"name\"] is a substring of object's name,\n" "[\"desc\"] is a substring of object's description,\n" - "asset [\"type\"] corresponds to the object's asset type\n" + "asset [\"type\"] corresponds to the object's asset type\n" + "[\"item_limit\"] sets item count limit in reply, maximum and default is 100\n" "[\"filter_links\"]: EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)", &LLInventoryListener::collectDescendentsIf, llsd::map("folder_id", LLSD(), "reply", LLSD())); @@ -171,9 +174,11 @@ void LLInventoryListener::collectDescendentsIf(LLSD const &data) } } -LLFilteredCollector::LLFilteredCollector(LLSD const &data) - : mType(LLAssetType::EType::AT_UNKNOWN), - mLinkFilter(INCLUDE_LINKS) +LLFilteredCollector::LLFilteredCollector(LLSD const &data) : + mType(LLAssetType::EType::AT_UNKNOWN), + mLinkFilter(INCLUDE_LINKS), + mItemLimit(MAX_ITEM_LIMIT), + mItemCount(0) { if (data.has("name")) { @@ -198,6 +203,10 @@ LLFilteredCollector::LLFilteredCollector(LLSD const &data) mLinkFilter = ONLY_LINKS; } } + if (data.has("item_limit")) + { + mItemLimit = llclamp(data["item_limit"].asInteger(), 1, MAX_ITEM_LIMIT); + } } bool LLFilteredCollector::operator()(LLInventoryCategory *cat, LLInventoryItem *item) @@ -206,9 +215,18 @@ bool LLFilteredCollector::operator()(LLInventoryCategory *cat, LLInventoryItem * passed = passed && checkagainstNameDesc(cat, item); passed = passed && checkagainstLinks(cat, item); + if (passed) + { + ++mItemCount; + } return passed; } +bool LLFilteredCollector::exceedsLimit() +{ + return (mItemLimit <= mItemCount); +} + bool LLFilteredCollector::checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item) { std::string name, desc; diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h index 83e1751e1b..2c1eb2cb6d 100644 --- a/indra/newview/llinventorylistener.h +++ b/indra/newview/llinventorylistener.h @@ -56,6 +56,7 @@ struct LLFilteredCollector : public LLInventoryCollectFunctor LLFilteredCollector(LLSD const &data); virtual ~LLFilteredCollector() {} virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); + virtual bool exceedsLimit(); protected: bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item); @@ -66,6 +67,9 @@ struct LLFilteredCollector : public LLInventoryCollectFunctor std::string mName; std::string mDesc; EFilterLink mLinkFilter; + + S32 mItemLimit; + S32 mItemCount; }; #endif // LL_LLINVENTORYLISTENER_H diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 5325c28abf..c98c3482d0 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1289,6 +1289,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, S32 count = cat_array->size(); for(S32 i = 0; i < count; ++i) { + if (add.exceedsLimit()) + { + break; + } LLViewerInventoryCategory* cat = cat_array->at(i); if(add(cat,NULL)) { @@ -1307,6 +1311,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, S32 count = item_array->size(); for(S32 i = 0; i < count; ++i) { + if (add.exceedsLimit()) + { + break; + } item = item_array->at(i); if(add(NULL, item)) { diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index e6a347532b..b3f817da94 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -36,9 +36,10 @@ end -- [, name] -- name (substring) -- [, desc] -- description (substring) -- [, type] -- asset type +-- [, item_limit] -- item count limit in reply, maximum and default is 100 -- [, filter_links]} -- EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default) function LLInventory.collectDescendentsIf(...) - local args = mapargs('folder_id,name,desc,type,filter_links', ...) + local args = mapargs('folder_id,name,desc,type,filter_links,item_limit', ...) args.op = 'collectDescendentsIf' return leap.request('LLInventory', args) end diff --git a/indra/newview/scripts/lua/test_LLInventory.lua b/indra/newview/scripts/lua/test_LLInventory.lua new file mode 100644 index 0000000000..dc6eb243ad --- /dev/null +++ b/indra/newview/scripts/lua/test_LLInventory.lua @@ -0,0 +1,21 @@ +inspect = require 'inspect' +LLInventory = require 'LLInventory' + +-- Get 'My Landmarks' folder id (you can see all folder types via LLInventory.getFolderTypeNames()) +my_landmarks_id = LLInventory.getBasicFolderID('landmark') +-- Get 3 landmarks from the 'My Landmarks' folder (you can see all folder types via LLInventory.getAssetTypeNames()) +landmarks = LLInventory.collectDescendentsIf{folder_id=my_landmarks_id, type="landmark", item_limit=3} +print(inspect(landmarks)) + +-- Get 'Calling Cards' folder id +calling_cards_id = LLInventory.getBasicFolderID('callcard') +-- Get all items located directly in 'Calling Cards' folder +calling_cards = LLInventory.getDirectDescendents(calling_cards_id).items + +-- Print a random calling card name from 'Calling Cards' folder +local card_names = {} +for _, value in pairs(calling_cards) do + table.insert(card_names, value.name) +end +math.randomseed(os.time()) +print("Random calling card: " .. inspect(card_names[math.random(#card_names)])) -- cgit v1.2.3 From 8887711019f3b37bc830a51609a4940fe10d7cec Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 21 Aug 2024 23:12:21 +0300 Subject: mac build fix --- indra/newview/llinventorylistener.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index 4ff25f7f5c..0aa1208d83 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -182,11 +182,11 @@ LLFilteredCollector::LLFilteredCollector(LLSD const &data) : { if (data.has("name")) { - mName = data["name"]; + mName = data["name"].asString(); } if (data.has("desc")) { - mDesc = data["desc"]; + mDesc = data["desc"].asString(); } if (data.has("type")) { -- cgit v1.2.3 From 073d3d0e04a2ebe35a201eae9c6dad4b7ae5dc88 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 22 Aug 2024 23:29:28 +0300 Subject: Fix for #2385: say, shout and whisper messages from the script should be displayed consistently --- indra/newview/llviewermessage.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 26b088e390..4922e3c9f9 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2646,19 +2646,21 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) else { chat.mText = ""; + std::string chat_text(mesg); + auto [msg_without_prefix, is_lua] = LLStringUtil::withoutPrefix(mesg, LUA_PREFIX); switch(chat.mChatType) { case CHAT_TYPE_WHISPER: - chat.mText = LLTrans::getString("whisper") + " "; + case CHAT_TYPE_SHOUT: + chat_text = LLTrans::getString(chat.mChatType == CHAT_TYPE_WHISPER ? "whisper" : "shout") + " " + msg_without_prefix; + if(is_lua) + chat_text = LUA_PREFIX + chat_text; break; case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: case CHAT_TYPE_NORMAL: case CHAT_TYPE_DIRECT: break; - case CHAT_TYPE_SHOUT: - chat.mText = LLTrans::getString("shout") + " "; - break; case CHAT_TYPE_START: case CHAT_TYPE_STOP: LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL; @@ -2668,7 +2670,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) break; } - chat.mText += mesg; + chat.mText += chat_text; } // We have a real utterance now, so can stop showing "..." and proceed. -- cgit v1.2.3 From a80b9487dc7c893f5e96f48f15140a5f82b99e30 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 23 Aug 2024 17:18:14 -0400 Subject: Allow UI to have lazily-loaded submodules. Equip UI with an __index metamethod. When someone references an unknown key/field in UI, require() that module and cache it for future reference. Add util.setmetamethods() as a way to find or create a metatable on a specified table containing specified metamethods. Exercise the new functionality by referencing UI.popup in test_popup.lua. --- indra/newview/scripts/lua/require/UI.lua | 22 ++++++++++++-- indra/newview/scripts/lua/require/util.lua | 46 +++++++++++++++++++++++------- indra/newview/scripts/lua/test_popup.lua | 3 +- 3 files changed, 57 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 464e6547ea..969a2cbded 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -1,10 +1,26 @@ -- Engage the viewer's UI local leap = require 'leap' -local Timer = (require 'timers').Timer local mapargs = require 'mapargs' - -local UI = {} +local Timer = (require 'timers').Timer +local util = require 'util' + +-- Allow lazily accessing certain other modules on demand, e.g. a reference to +-- UI.Floater lazily loads the Floater module. Use of UI's __index metamethod +-- theoretically permits any other module you can require() to appear as a +-- submodule of UI, but it doesn't make sense to support (e.g.) UI.Queue. +local submods = { 'Floater', 'popup' } +local UI = util.setmetamethods{ + __index=function(t, key) + if not table.find(submods, key) then + error(`Invalid UI submodule {key}`, 2) + end + local mod = require(key) + -- cache the submodule + t[key] = mod + return mod + end +} -- *************************************************************************** -- registered menu actions diff --git a/indra/newview/scripts/lua/require/util.lua b/indra/newview/scripts/lua/require/util.lua index bfbfc8637c..a000359226 100644 --- a/indra/newview/scripts/lua/require/util.lua +++ b/indra/newview/scripts/lua/require/util.lua @@ -15,16 +15,9 @@ local util = {} -- util.classctor(MyClass, MyClass.construct) -- return MyClass function util.classctor(class, ctor) - -- get the metatable for the passed class - local mt = getmetatable(class) - if mt == nil then - -- if it doesn't already have a metatable, then create one - mt = {} - setmetatable(class, mt) - end - -- now that class has a metatable, set its __call method to the specified - -- constructor method (class.new if not specified) - mt.__call = ctor or class.new + -- set class's __call metamethod to the specified constructor function + -- (class.new if not specified) + util.setmetamethods{class, __call=(ctor or class.new)} end -- check if array-like table contains certain value @@ -66,4 +59,37 @@ function util.equal(t1, t2) return util.empty(temp) end +-- Find or create the metatable for a specified table (a new empty table if +-- omitted), and to that metatable assign the specified keys. +-- Setting multiple keys at once is more efficient than a function to set only +-- one at a time, e.g. setametamethod(). +-- t = util.setmetamethods{__index=readfunc, __len=lenfunc} +-- returns a new table with specified metamethods __index, __len +-- util.setmetamethods{t, __call=action} +-- finds or creates the metatable for existing table t and sets __call +-- util.setmetamethods{table=t, __call=action} +-- same as util.setmetamethods{t, __call=action} +function util.setmetamethods(specs) + -- first determine the target table + assert(not (specs.table and specs[1]), + "Pass setmetamethods table either as positional or table=, not both") + local t = specs.table or specs[1] or {} + -- remove both ways of specifying table, leaving only the metamethods + specs.table = nil + specs[1] = nil + local mt = getmetatable(t) + if not mt then + -- t doesn't already have a metatable: just set specs + setmetatable(t, specs) + else + -- t already has a metatable: copy specs into it + local key, value + for key, value in pairs(specs) do + mt[key] = value + end + end + -- having set or enriched t's metatable, return t + return t +end + return util diff --git a/indra/newview/scripts/lua/test_popup.lua b/indra/newview/scripts/lua/test_popup.lua index e48f89c3a7..156c09c78f 100644 --- a/indra/newview/scripts/lua/test_popup.lua +++ b/indra/newview/scripts/lua/test_popup.lua @@ -1,4 +1,5 @@ -popup = require 'popup' +UI = require 'UI' +popup = UI.popup response = popup:alert('This just has a Close button') response = popup:alertOK(string.format('You said "%s", is that OK?', next(response))) -- cgit v1.2.3 From e4a710296943674573be800f5233b24214440929 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 23 Aug 2024 20:55:22 -0400 Subject: Look for lazy UI submodules in a require/UI subdirectory. This way encourages "UI = require 'UI'; UI.Floater" instead of just "Floater = require 'Floater'". Moreover, now we don't need UI to maintain a list of allowed submodules; that's effected by membership in the subdirectory. --- indra/newview/scripts/lua/require/Floater.lua | 146 ----------------------- indra/newview/scripts/lua/require/UI.lua | 12 +- indra/newview/scripts/lua/require/UI/Floater.lua | 146 +++++++++++++++++++++++ indra/newview/scripts/lua/require/UI/popup.lua | 53 ++++++++ indra/newview/scripts/lua/require/popup.lua | 53 -------- 5 files changed, 202 insertions(+), 208 deletions(-) delete mode 100644 indra/newview/scripts/lua/require/Floater.lua create mode 100644 indra/newview/scripts/lua/require/UI/Floater.lua create mode 100644 indra/newview/scripts/lua/require/UI/popup.lua delete mode 100644 indra/newview/scripts/lua/require/popup.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/Floater.lua b/indra/newview/scripts/lua/require/Floater.lua deleted file mode 100644 index d057a74386..0000000000 --- a/indra/newview/scripts/lua/require/Floater.lua +++ /dev/null @@ -1,146 +0,0 @@ --- Floater base class - -local leap = require 'leap' -local fiber = require 'fiber' -local util = require 'util' - --- list of all the events that a LLLuaFloater might send -local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events -local event_set = {} -for _, event in pairs(event_list) do - event_set[event] = true -end - -local function _event(event_name) - if not event_set[event_name] then - error("Incorrect event name: " .. event_name, 3) - end - return event_name -end - --- --------------------------------------------------------------------------- -local Floater = {} - --- Pass: --- relative file path to floater's XUI definition file --- optional: sign up for additional events for defined control --- {<control_name>={action1, action2, ...}} -function Floater:new(path, extra) - local obj = setmetatable({}, self) - self.__index = self - - local path_parts = string.split(path, '/') - obj.name = 'Floater ' .. path_parts[#path_parts] - - obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)} - if extra then - -- validate each of the actions for each specified control - for control, actions in pairs(extra) do - for _, action in pairs(actions) do - _event(action) - end - end - obj._command.extra_events = extra - end - - return obj -end - -util.classctor(Floater) - -function Floater:show() - -- leap.eventstream() returns the first response, and launches a - -- background fiber to call the passed callback with all subsequent - -- responses. - local event = leap.eventstream( - 'LLFloaterReg', - self._command, - -- handleEvents() returns false when done. - -- eventstream() expects a true return when done. - function(event) return not self:handleEvents(event) end) - self._pump = event.command_name - -- we might need the returned reqid to cancel the eventstream() fiber - self.reqid = event.reqid - - -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if - -- subclass has a post_build() method. Honor the convention that if - -- handleEvents() returns false, we're done. - if not self:handleEvents(event) then - return - end -end - -function Floater:post(action) - leap.send(self._pump, action) -end - -function Floater:request(action) - return leap.request(self._pump, action) -end - --- local inspect = require 'inspect' - -function Floater:handleEvents(event_data) - local event = event_data.event - if event_set[event] == nil then - LL.print_warning(string.format('%s received unknown event %q', self.name, event)) - end - - -- Before checking for a general (e.g.) commit() method, first look for - -- commit_ctrl_name(): in other words, concatenate the event name with the - -- ctrl_name, with an underscore between. If there exists such a specific - -- method, call that. - local handler, ret - if event_data.ctrl_name then - local specific = event .. '_' .. event_data.ctrl_name - handler = self[specific] - if handler then - ret = handler(self, event_data) - -- Avoid 'return ret or true' because we explicitly want to allow - -- the handler to return false. - if ret ~= nil then - return ret - else - return true - end - end - end - - -- No specific "event_on_ctrl()" method found; try just "event()" - handler = self[event] - if handler then - ret = handler(self, event_data) - if ret ~= nil then - return ret - end --- else --- print(string.format('%s ignoring event %s', self.name, inspect(event_data))) - end - - -- We check for event() method before recognizing floater_close in case - -- the consumer needs to react specially to closing the floater. Now that - -- we've checked, recognize it ourselves. Returning false terminates the - -- anonymous fiber function launched by leap.eventstream(). - if event == _event('floater_close') then - LL.print_warning(self.name .. ' closed') - return false - end - return true -end - --- onCtrl() permits a different dispatch style in which the general event() --- method explicitly calls (e.g.) --- self:onCtrl(event_data, { --- ctrl_name=function() --- self:post(...) --- end, --- ... --- }) -function Floater:onCtrl(event_data, ctrl_map) - local handler = ctrl_map[event_data.ctrl_name] - if handler then - handler() - end -end - -return Floater diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 969a2cbded..2df70fd453 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -5,17 +5,11 @@ local mapargs = require 'mapargs' local Timer = (require 'timers').Timer local util = require 'util' --- Allow lazily accessing certain other modules on demand, e.g. a reference to --- UI.Floater lazily loads the Floater module. Use of UI's __index metamethod --- theoretically permits any other module you can require() to appear as a --- submodule of UI, but it doesn't make sense to support (e.g.) UI.Queue. -local submods = { 'Floater', 'popup' } +-- Allow lazily accessing UI submodules on demand, e.g. a reference to +-- UI.Floater lazily loads the UI/Floater module. local UI = util.setmetamethods{ __index=function(t, key) - if not table.find(submods, key) then - error(`Invalid UI submodule {key}`, 2) - end - local mod = require(key) + local mod = require('UI/' .. key) -- cache the submodule t[key] = mod return mod diff --git a/indra/newview/scripts/lua/require/UI/Floater.lua b/indra/newview/scripts/lua/require/UI/Floater.lua new file mode 100644 index 0000000000..d057a74386 --- /dev/null +++ b/indra/newview/scripts/lua/require/UI/Floater.lua @@ -0,0 +1,146 @@ +-- Floater base class + +local leap = require 'leap' +local fiber = require 'fiber' +local util = require 'util' + +-- list of all the events that a LLLuaFloater might send +local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events +local event_set = {} +for _, event in pairs(event_list) do + event_set[event] = true +end + +local function _event(event_name) + if not event_set[event_name] then + error("Incorrect event name: " .. event_name, 3) + end + return event_name +end + +-- --------------------------------------------------------------------------- +local Floater = {} + +-- Pass: +-- relative file path to floater's XUI definition file +-- optional: sign up for additional events for defined control +-- {<control_name>={action1, action2, ...}} +function Floater:new(path, extra) + local obj = setmetatable({}, self) + self.__index = self + + local path_parts = string.split(path, '/') + obj.name = 'Floater ' .. path_parts[#path_parts] + + obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)} + if extra then + -- validate each of the actions for each specified control + for control, actions in pairs(extra) do + for _, action in pairs(actions) do + _event(action) + end + end + obj._command.extra_events = extra + end + + return obj +end + +util.classctor(Floater) + +function Floater:show() + -- leap.eventstream() returns the first response, and launches a + -- background fiber to call the passed callback with all subsequent + -- responses. + local event = leap.eventstream( + 'LLFloaterReg', + self._command, + -- handleEvents() returns false when done. + -- eventstream() expects a true return when done. + function(event) return not self:handleEvents(event) end) + self._pump = event.command_name + -- we might need the returned reqid to cancel the eventstream() fiber + self.reqid = event.reqid + + -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if + -- subclass has a post_build() method. Honor the convention that if + -- handleEvents() returns false, we're done. + if not self:handleEvents(event) then + return + end +end + +function Floater:post(action) + leap.send(self._pump, action) +end + +function Floater:request(action) + return leap.request(self._pump, action) +end + +-- local inspect = require 'inspect' + +function Floater:handleEvents(event_data) + local event = event_data.event + if event_set[event] == nil then + LL.print_warning(string.format('%s received unknown event %q', self.name, event)) + end + + -- Before checking for a general (e.g.) commit() method, first look for + -- commit_ctrl_name(): in other words, concatenate the event name with the + -- ctrl_name, with an underscore between. If there exists such a specific + -- method, call that. + local handler, ret + if event_data.ctrl_name then + local specific = event .. '_' .. event_data.ctrl_name + handler = self[specific] + if handler then + ret = handler(self, event_data) + -- Avoid 'return ret or true' because we explicitly want to allow + -- the handler to return false. + if ret ~= nil then + return ret + else + return true + end + end + end + + -- No specific "event_on_ctrl()" method found; try just "event()" + handler = self[event] + if handler then + ret = handler(self, event_data) + if ret ~= nil then + return ret + end +-- else +-- print(string.format('%s ignoring event %s', self.name, inspect(event_data))) + end + + -- We check for event() method before recognizing floater_close in case + -- the consumer needs to react specially to closing the floater. Now that + -- we've checked, recognize it ourselves. Returning false terminates the + -- anonymous fiber function launched by leap.eventstream(). + if event == _event('floater_close') then + LL.print_warning(self.name .. ' closed') + return false + end + return true +end + +-- onCtrl() permits a different dispatch style in which the general event() +-- method explicitly calls (e.g.) +-- self:onCtrl(event_data, { +-- ctrl_name=function() +-- self:post(...) +-- end, +-- ... +-- }) +function Floater:onCtrl(event_data, ctrl_map) + local handler = ctrl_map[event_data.ctrl_name] + if handler then + handler() + end +end + +return Floater diff --git a/indra/newview/scripts/lua/require/UI/popup.lua b/indra/newview/scripts/lua/require/UI/popup.lua new file mode 100644 index 0000000000..3aaadf85ba --- /dev/null +++ b/indra/newview/scripts/lua/require/UI/popup.lua @@ -0,0 +1,53 @@ +local leap = require 'leap' +local mapargs = require 'mapargs' + +-- notification is any name defined in notifications.xml as +-- <notification name=> +-- vars is a table providing values for [VAR] substitution keys in the +-- notification body +-- payload prepopulates the response table +-- wait=false means fire and forget, otherwise wait for user response +local popup_meta = { + -- setting this function as getmetatable(popup).__call() means this gets + -- called when a consumer calls popup(notification, vars, payload) + __call = function(self, ...) + local args = mapargs('notification,vars,payload,wait', ...) + -- we use convenience argument names different from 'LLNotifications' + -- listener + args.name = args.notification + args.notification = nil + args.substitutions = args.vars + args.vars = nil + local wait = args.wait + args.wait = nil + args.op = 'requestAdd' + -- Specifically test (wait == false), NOT (not wait), because we treat + -- nil (omitted, default true) differently than false (explicitly + -- DON'T wait). + if wait == false then + leap.send('LLNotifications', args) + else + return leap.request('LLNotifications', args).response + end + end +} + +local popup = setmetatable({}, popup_meta) + +function popup:alert(message) + return self('GenericAlert', {MESSAGE=message}) +end + +function popup:alertOK(message) + return self('GenericAlertOK', {MESSAGE=message}) +end + +function popup:alertYesCancel(message) + return self('GenericAlertYesCancel', {MESSAGE=message}) +end + +function popup:tip(message) + self{'SystemMessageTip', {MESSAGE=message}, wait=false} +end + +return popup diff --git a/indra/newview/scripts/lua/require/popup.lua b/indra/newview/scripts/lua/require/popup.lua deleted file mode 100644 index 3aaadf85ba..0000000000 --- a/indra/newview/scripts/lua/require/popup.lua +++ /dev/null @@ -1,53 +0,0 @@ -local leap = require 'leap' -local mapargs = require 'mapargs' - --- notification is any name defined in notifications.xml as --- <notification name=> --- vars is a table providing values for [VAR] substitution keys in the --- notification body --- payload prepopulates the response table --- wait=false means fire and forget, otherwise wait for user response -local popup_meta = { - -- setting this function as getmetatable(popup).__call() means this gets - -- called when a consumer calls popup(notification, vars, payload) - __call = function(self, ...) - local args = mapargs('notification,vars,payload,wait', ...) - -- we use convenience argument names different from 'LLNotifications' - -- listener - args.name = args.notification - args.notification = nil - args.substitutions = args.vars - args.vars = nil - local wait = args.wait - args.wait = nil - args.op = 'requestAdd' - -- Specifically test (wait == false), NOT (not wait), because we treat - -- nil (omitted, default true) differently than false (explicitly - -- DON'T wait). - if wait == false then - leap.send('LLNotifications', args) - else - return leap.request('LLNotifications', args).response - end - end -} - -local popup = setmetatable({}, popup_meta) - -function popup:alert(message) - return self('GenericAlert', {MESSAGE=message}) -end - -function popup:alertOK(message) - return self('GenericAlertOK', {MESSAGE=message}) -end - -function popup:alertYesCancel(message) - return self('GenericAlertYesCancel', {MESSAGE=message}) -end - -function popup:tip(message) - self{'SystemMessageTip', {MESSAGE=message}, wait=false} -end - -return popup -- cgit v1.2.3 From 2e815acb529159f5b6f0a4365a2eaf64d35330cc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 23 Aug 2024 21:28:03 -0400 Subject: Encapsulate the lazy submodule idiom as util.submoduledir(). --- indra/newview/scripts/lua/require/UI.lua | 9 +-------- indra/newview/scripts/lua/require/util.lua | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 2df70fd453..bbcae3514a 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -7,14 +7,7 @@ local util = require 'util' -- Allow lazily accessing UI submodules on demand, e.g. a reference to -- UI.Floater lazily loads the UI/Floater module. -local UI = util.setmetamethods{ - __index=function(t, key) - local mod = require('UI/' .. key) - -- cache the submodule - t[key] = mod - return mod - end -} +local UI = util.submoduledir({}, 'UI') -- *************************************************************************** -- registered menu actions diff --git a/indra/newview/scripts/lua/require/util.lua b/indra/newview/scripts/lua/require/util.lua index a000359226..40737a159a 100644 --- a/indra/newview/scripts/lua/require/util.lua +++ b/indra/newview/scripts/lua/require/util.lua @@ -92,4 +92,23 @@ function util.setmetamethods(specs) return t end +-- On the passed module (i.e. table), set an __index metamethod such that +-- referencing module.submodule lazily requires(path/submodule). +-- The loaded submodule is cached in the module table so it need not be passed +-- to require() again. +-- 'path', like any require() string, can be relative to LuaRequirePath. +-- Returns the enriched module, permitting e.g. +-- mymod = util.submoduledir({}, 'mymod') +function util.submoduledir(module, path) + return util.setmetamethods{ + module, + __index=function(t, key) + local mod = require(`{path}/{key}`) + -- cache the submodule + t[key] = mod + return mod + end + } +end + return util -- cgit v1.2.3 From e6d8379744b08f9a52af6734ba1f0e1b50fb5906 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 23 Aug 2024 22:39:30 -0400 Subject: Massage results from UI.popup() for ease of use. In particular, where the raw leap.request().response call would return {OK_okcancelbuttons=true}, just return the string 'OK' or 'Cancel'. Update existing consumer scripts. --- indra/newview/scripts/lua/require/UI/popup.lua | 77 +++++++++++++++------- indra/newview/scripts/lua/test_group_chat.lua | 7 +- .../scripts/lua/test_luafloater_speedometer.lua | 5 +- indra/newview/scripts/lua/test_popup.lua | 9 ++- indra/newview/scripts/lua/test_toolbars.lua | 6 +- 5 files changed, 67 insertions(+), 37 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/UI/popup.lua b/indra/newview/scripts/lua/require/UI/popup.lua index 3aaadf85ba..8ccf3b87f3 100644 --- a/indra/newview/scripts/lua/require/UI/popup.lua +++ b/indra/newview/scripts/lua/require/UI/popup.lua @@ -1,53 +1,82 @@ local leap = require 'leap' local mapargs = require 'mapargs' +local util = require 'util' -- notification is any name defined in notifications.xml as -- <notification name=> -- vars is a table providing values for [VAR] substitution keys in the -- notification body -- payload prepopulates the response table --- wait=false means fire and forget, otherwise wait for user response -local popup_meta = { - -- setting this function as getmetatable(popup).__call() means this gets - -- called when a consumer calls popup(notification, vars, payload) +-- wait=false means fire and forget, returning nil +-- wait=true waits for user response: +-- * If the viewer returns a table containing exactly one key=true pair, +-- popup() returns just that key. If the key is a string containing an +-- underscore, e.g. 'OK_okcancelbuttons', it's truncated at the first +-- underscore, e.g. 'OK'. +-- * Otherwise the viewer's response is returned unchanged. To suppress the +-- above transformations, pass a non-empty payload table; this will cause +-- the viewer to return a table with at least two keys. +local popup = util.setmetamethods{ + -- this gets called when a consumer calls popup(notification, vars, payload) __call = function(self, ...) local args = mapargs('notification,vars,payload,wait', ...) -- we use convenience argument names different from 'LLNotifications' -- listener - args.name = args.notification - args.notification = nil - args.substitutions = args.vars - args.vars = nil - local wait = args.wait - args.wait = nil - args.op = 'requestAdd' + newargs = {op='requestAdd', + name=args.notification, + substitutions=args.vars, + payload=args.payload} -- Specifically test (wait == false), NOT (not wait), because we treat -- nil (omitted, default true) differently than false (explicitly -- DON'T wait). - if wait == false then - leap.send('LLNotifications', args) + if args.wait == false then + leap.send('LLNotifications', newargs) else - return leap.request('LLNotifications', args).response + local response = leap.request('LLNotifications', newargs).response + -- response is typically a table. It might have multiple keys, + -- e.g. if caller passed non-empty payload. In that case, just + -- return the whole thing. + if type(response) ~= 'table' then + return response + end + -- get first key=value pair, if any + local key, value = next(response) + if (not key) or next(response, key) then + -- key == nil means response is empty + -- next(response, non-nil first key) ~= nil means at least two keys + return response + end + -- Here response is a table containing exactly one key. The + -- notifications system typically returns a table of the form + -- {OK_okcancelbuttons=true}, which is tricky to test for because it + -- varies with each set of buttons. + if value == true then + -- change {key=true} to plain key + response = key + if type(response) == 'string' then + -- change 'OK_okcancelbuttons' to plain 'OK' + response = string.split(response, '_')[1] + end + end + return response end end } -local popup = setmetatable({}, popup_meta) - -function popup:alert(message) - return self('GenericAlert', {MESSAGE=message}) +function popup:alert(message, payload) + return self('GenericAlert', {MESSAGE=message, payload=payload}) end -function popup:alertOK(message) - return self('GenericAlertOK', {MESSAGE=message}) +function popup:alertOK(message, payload) + return self('GenericAlertOK', {MESSAGE=message, payload=payload}) end -function popup:alertYesCancel(message) - return self('GenericAlertYesCancel', {MESSAGE=message}) +function popup:alertYesCancel(message, payload) + return self('GenericAlertYesCancel', {MESSAGE=message, payload=payload}) end -function popup:tip(message) - self{'SystemMessageTip', {MESSAGE=message}, wait=false} +function popup:tip(message, payload) + self{'SystemMessageTip', {MESSAGE=message, payload=payload}, wait=false} end return popup diff --git a/indra/newview/scripts/lua/test_group_chat.lua b/indra/newview/scripts/lua/test_group_chat.lua index eaff07ed14..373411c26c 100644 --- a/indra/newview/scripts/lua/test_group_chat.lua +++ b/indra/newview/scripts/lua/test_group_chat.lua @@ -1,15 +1,14 @@ LLChat = require 'LLChat' LLAgent = require 'LLAgent' -popup = require 'popup' +UI = require 'UI' -local OK = 'OK_okcancelbuttons' local GROUPS = LLAgent.getGroups() -- Choose one of the groups randomly and send group message math.randomseed(os.time()) group_info = GROUPS[math.random(#GROUPS)] LLChat.startGroupChat(group_info.id) -response = popup:alertYesCancel('Started group chat with ' .. group_info.name .. ' group. Send greetings?') -if next(response) == OK then +response = UI.popup:alertYesCancel('Started group chat with ' .. group_info.name .. ' group. Send greetings?') +if response == 'OK' then LLChat.sendGroupIM('Greetings', group_info.id) end diff --git a/indra/newview/scripts/lua/test_luafloater_speedometer.lua b/indra/newview/scripts/lua/test_luafloater_speedometer.lua index af7189a2cb..8bc18ad286 100644 --- a/indra/newview/scripts/lua/test_luafloater_speedometer.lua +++ b/indra/newview/scripts/lua/test_luafloater_speedometer.lua @@ -1,8 +1,9 @@ local Floater = require 'Floater' local leap = require 'leap' -local popup = require 'popup' local startup = require 'startup' local Timer = (require 'timers').Timer +local UI = require 'UI' +local popup = UI.popup local max_speed = 0 local flt = Floater("luafloater_speedometer.xml") startup.wait('STATE_STARTED') @@ -25,7 +26,7 @@ end msg = 'Are you sure you want to run this "speedometer" script?' response = popup:alertYesCancel(msg) -if response.OK_okcancelbuttons then +if response == 'OK' then flt:show() timer = Timer(1, idle, true) -- iterate end diff --git a/indra/newview/scripts/lua/test_popup.lua b/indra/newview/scripts/lua/test_popup.lua index 156c09c78f..7a11895669 100644 --- a/indra/newview/scripts/lua/test_popup.lua +++ b/indra/newview/scripts/lua/test_popup.lua @@ -1,7 +1,10 @@ UI = require 'UI' popup = UI.popup +startup = require 'startup' + +startup.wait('STATE_STARTED') response = popup:alert('This just has a Close button') -response = popup:alertOK(string.format('You said "%s", is that OK?', next(response))) -response = popup:alertYesCancel(string.format('You said "%s"', next(response))) -popup:tip(string.format('You said "%s"', next(response))) +response = popup:alertOK(string.format('You said "%s", is that OK?', response)) +response = popup:alertYesCancel(string.format('You said "%s"', response)) +popup:tip(string.format('You said "%s"', response)) diff --git a/indra/newview/scripts/lua/test_toolbars.lua b/indra/newview/scripts/lua/test_toolbars.lua index 9a832c5644..7683fca8a3 100644 --- a/indra/newview/scripts/lua/test_toolbars.lua +++ b/indra/newview/scripts/lua/test_toolbars.lua @@ -1,13 +1,11 @@ -popup = require 'popup' UI = require 'UI' -local OK = 'OK_okcancelbuttons' local BUTTONS = UI.getToolbarBtnNames() local TOOLBARS = {'left','right','bottom'} -- Clear the toolbars and then add the toolbar buttons to the random toolbar -response = popup:alertYesCancel('Toolbars will be randomly reshuffled. Proceed?') -if next(response) == OK then +response = UI.popup:alertYesCancel('Toolbars will be randomly reshuffled. Proceed?') +if response == 'OK' then UI.clearAllToolbars() math.randomseed(os.time()) -- cgit v1.2.3 From 7b21acd39745d265548eeb62d687cde9febb1f7a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Sat, 24 Aug 2024 10:37:57 -0400 Subject: Update test scripts to reference UI.Floater, not standalone Floater. --- indra/newview/scripts/lua/require/LLChatListener.lua | 2 +- indra/newview/scripts/lua/test_LLAppearance.lua | 4 ++-- indra/newview/scripts/lua/test_camera_control.lua | 4 ++-- indra/newview/scripts/lua/test_luafloater_demo.lua | 6 +++--- indra/newview/scripts/lua/test_luafloater_gesture_list.lua | 4 ++-- indra/newview/scripts/lua/test_luafloater_speedometer.lua | 3 +-- 6 files changed, 11 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/LLChatListener.lua b/indra/newview/scripts/lua/require/LLChatListener.lua index 428dca881e..82b28966ce 100644 --- a/indra/newview/scripts/lua/require/LLChatListener.lua +++ b/indra/newview/scripts/lua/require/LLChatListener.lua @@ -23,7 +23,7 @@ function LLChatListener:handleMessages(event_data) end function LLChatListener:start() - waitfor = leap.WaitFor:new(-1, self.name) + waitfor = leap.WaitFor(-1, self.name) function waitfor:filter(pump, data) if pump == "LLNearbyChat" then return data diff --git a/indra/newview/scripts/lua/test_LLAppearance.lua b/indra/newview/scripts/lua/test_LLAppearance.lua index 5ddd9f15ff..a97ec4e0ca 100644 --- a/indra/newview/scripts/lua/test_LLAppearance.lua +++ b/indra/newview/scripts/lua/test_LLAppearance.lua @@ -1,7 +1,7 @@ -local Floater = require 'Floater' local LLAppearance = require 'LLAppearance' local startup = require 'startup' local inspect = require 'inspect' +local UI = require 'UI' local SHOW_OUTFITS = true local SELECTED_OUTFIT_ID = {} @@ -15,7 +15,7 @@ local outfits_title = 'Outfits' local wear_lbl = 'Wear item' local detach_lbl = 'Detach item' -local flt = Floater:new( +local flt = UI.Floater( "luafloater_outfits_list.xml", {outfits_list = {"double_click"}}) diff --git a/indra/newview/scripts/lua/test_camera_control.lua b/indra/newview/scripts/lua/test_camera_control.lua index 9b35cdf8cd..7ac0986ee6 100644 --- a/indra/newview/scripts/lua/test_camera_control.lua +++ b/indra/newview/scripts/lua/test_camera_control.lua @@ -1,8 +1,8 @@ -local Floater = require 'Floater' local LLAgent = require 'LLAgent' local startup = require 'startup' +local UI = require 'UI' -local flt = Floater('luafloater_camera_control.xml') +local flt = UI.Floater('luafloater_camera_control.xml') function getValue(ctrl_name) return flt:request({action="get_value", ctrl_name=ctrl_name}).value diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua index 3903d01e65..2158134511 100644 --- a/indra/newview/scripts/lua/test_luafloater_demo.lua +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -1,8 +1,8 @@ -local Floater = require 'Floater' local leap = require 'leap' local startup = require 'startup' +local UI = require 'UI' -local flt = Floater( +local flt = UI.Floater( 'luafloater_demo.xml', {show_time_lbl = {"right_mouse_down", "double_click"}}) @@ -10,7 +10,7 @@ local flt = Floater( function flt:handleEvents(event_data) self:post({action="add_text", ctrl_name="events_editor", value = event_data}) -- forward the call to base-class handleEvents() - return Floater.handleEvents(self, event_data) + return UI.Floater.handleEvents(self, event_data) end function flt:commit_disable_ctrl(event_data) diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua index bd397ef2a6..5f929c0d0c 100644 --- a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -1,8 +1,8 @@ -local Floater = require 'Floater' local LLGesture = require 'LLGesture' local startup = require 'startup' +local UI = require 'UI' -local flt = Floater( +local flt = UI.Floater( "luafloater_gesture_list.xml", {gesture_list = {"double_click"}}) diff --git a/indra/newview/scripts/lua/test_luafloater_speedometer.lua b/indra/newview/scripts/lua/test_luafloater_speedometer.lua index 8bc18ad286..2cdd41fd7e 100644 --- a/indra/newview/scripts/lua/test_luafloater_speedometer.lua +++ b/indra/newview/scripts/lua/test_luafloater_speedometer.lua @@ -1,11 +1,10 @@ -local Floater = require 'Floater' local leap = require 'leap' local startup = require 'startup' local Timer = (require 'timers').Timer local UI = require 'UI' local popup = UI.popup local max_speed = 0 -local flt = Floater("luafloater_speedometer.xml") +local flt = UI.Floater("luafloater_speedometer.xml") startup.wait('STATE_STARTED') local timer -- cgit v1.2.3 From 3cc48ac9e22fb562560929a5c45a8b6ef1ecc841 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 26 Aug 2024 13:48:12 +0300 Subject: clean up Lua prefix --- indra/newview/llviewermessage.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 4922e3c9f9..56f759833c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2646,15 +2646,19 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) else { chat.mText = ""; - std::string chat_text(mesg); auto [msg_without_prefix, is_lua] = LLStringUtil::withoutPrefix(mesg, LUA_PREFIX); + std::string prefix; + if (is_lua) + { + prefix = LUA_PREFIX; + } switch(chat.mChatType) { case CHAT_TYPE_WHISPER: + prefix += LLTrans::getString("whisper") + " "; + break; case CHAT_TYPE_SHOUT: - chat_text = LLTrans::getString(chat.mChatType == CHAT_TYPE_WHISPER ? "whisper" : "shout") + " " + msg_without_prefix; - if(is_lua) - chat_text = LUA_PREFIX + chat_text; + prefix += LLTrans::getString("shout") + " "; break; case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: @@ -2670,7 +2674,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) break; } - chat.mText += chat_text; + chat.mText = prefix + msg_without_prefix; } // We have a real utterance now, so can stop showing "..." and proceed. -- cgit v1.2.3 From 27ce2a23a286709c90579db31c2551e0c3f292e7 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 27 Aug 2024 16:27:34 +0300 Subject: code clean up --- indra/newview/llinventorylistener.cpp | 136 +++++++++++++--------- indra/newview/llinventorylistener.h | 28 ----- indra/newview/scripts/lua/require/LLInventory.lua | 12 +- indra/newview/scripts/lua/test_LLInventory.lua | 2 +- 4 files changed, 86 insertions(+), 92 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index 0aa1208d83..157e04dce3 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -40,18 +40,18 @@ LLInventoryListener::LLInventoryListener() "API for interactions with viewer Inventory items") { add("getItemsInfo", - "Return information about items or folders defined in [\"items_id\"]:\n" + "Return information about items or folders defined in [\"item_ids\"]:\n" "reply will contain [\"items\"] and [\"categories\"] tables accordingly", &LLInventoryListener::getItemsInfo, - llsd::map("items_id", LLSD(), "reply", LLSD())); + llsd::map("item_ids", LLSD(), "reply", LLSD())); add("getFolderTypeNames", - "Return the table of folder type names, contained in [\"type_names\"]\n", + "Return the table of folder type names, contained in [\"names\"]\n", &LLInventoryListener::getFolderTypeNames, llsd::map("reply", LLSD())); add("getAssetTypeNames", - "Return the table of asset type names, contained in [\"type_names\"]\n", + "Return the table of asset type names, contained in [\"names\"]\n", &LLInventoryListener::getAssetTypeNames, llsd::map("reply", LLSD())); @@ -70,8 +70,8 @@ LLInventoryListener::LLInventoryListener() "Return the descendents(both items and folders) of the [\"folder_id\"], if it passes specified filters:\n" "[\"name\"] is a substring of object's name,\n" "[\"desc\"] is a substring of object's description,\n" - "asset [\"type\"] corresponds to the object's asset type\n" - "[\"item_limit\"] sets item count limit in reply, maximum and default is 100\n" + "asset [\"type\"] corresponds to the string name of the object's asset type\n" + "[\"limit\"] sets item count limit in reply, maximum and default is 100\n" "[\"filter_links\"]: EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)", &LLInventoryListener::collectDescendentsIf, llsd::map("folder_id", LLSD(), "reply", LLSD())); @@ -81,23 +81,42 @@ LLInventoryListener::LLInventoryListener() void add_item_info(LLEventAPI::Response& response, LLViewerInventoryItem* item) { response["items"].insert(item->getUUID().asString(), - llsd::map("name", item->getName(), "parent_id", item->getParentUUID(), "desc", item->getDescription(), - "inv_type", LLInventoryType::lookup(item->getInventoryType()), "asset_type", LLAssetType::lookup(item->getType()), - "creation_date", (S32) item->getCreationDate(), "asset_id", item->getAssetUUID(), - "is_link", item->getIsLinkType(), "linked_id", item->getLinkedUUID())); + llsd::map("name", item->getName(), + "parent_id", item->getParentUUID(), + "desc", item->getDescription(), + "inv_type", LLInventoryType::lookup(item->getInventoryType()), + "asset_type", LLAssetType::lookup(item->getType()), + "creation_date", (S32) item->getCreationDate(), + "asset_id", item->getAssetUUID(), + "is_link", item->getIsLinkType(), + "linked_id", item->getLinkedUUID())); } void add_cat_info(LLEventAPI::Response &response, LLViewerInventoryCategory *cat) { response["categories"].insert(cat->getUUID().asString(), - llsd::map("name", cat->getName(), "parent_id", cat->getParentUUID(), "type", LLFolderType::lookup(cat->getPreferredType()))); + llsd::map("name", cat->getName(), + "parent_id", cat->getParentUUID(), + "type", LLFolderType::lookup(cat->getPreferredType()))); +} + +void add_objects_info(LLEventAPI::Response& response, LLInventoryModel::cat_array_t cat_array, LLInventoryModel::item_array_t item_array) +{ + for (auto &p : item_array) + { + add_item_info(response, p); + } + for (auto &p : cat_array) + { + add_cat_info(response, p); + } } void LLInventoryListener::getItemsInfo(LLSD const &data) { Response response(LLSD(), data); - uuid_vec_t ids = LLSDParam<uuid_vec_t>(data["items_id"]); + uuid_vec_t ids = LLSDParam<uuid_vec_t>(data["item_ids"]); for (auto &it : ids) { LLViewerInventoryItem* item = gInventory.getItem(it); @@ -105,22 +124,25 @@ void LLInventoryListener::getItemsInfo(LLSD const &data) { add_item_info(response, item); } - LLViewerInventoryCategory* cat = gInventory.getCategory(it); - if (cat) + else { - add_cat_info(response, cat); + LLViewerInventoryCategory *cat = gInventory.getCategory(it); + if (cat) + { + add_cat_info(response, cat); + } } } } void LLInventoryListener::getFolderTypeNames(LLSD const &data) { - Response response(llsd::map("type_names", LLFolderType::getTypeNames()), data); + Response response(llsd::map("names", LLFolderType::getTypeNames()), data); } void LLInventoryListener::getAssetTypeNames(LLSD const &data) { - Response response(llsd::map("type_names", LLAssetType::getTypeNames()), data); + Response response(llsd::map("names", LLAssetType::getTypeNames()), data); } void LLInventoryListener::getBasicFolderID(LLSD const &data) @@ -136,18 +158,37 @@ void LLInventoryListener::getDirectDescendents(LLSD const &data) LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(data["folder_id"], cats, items); - LLInventoryModel::item_array_t items_copy = *items; - for (LLInventoryModel::item_array_t::iterator iter = items_copy.begin(); iter != items_copy.end(); iter++) - { - add_item_info(response, *iter); - } - LLInventoryModel::cat_array_t cats_copy = *cats; - for (LLInventoryModel::cat_array_t::iterator iter = cats_copy.begin(); iter != cats_copy.end(); iter++) - { - add_cat_info(response, *iter); - } + add_objects_info(response, *cats, *items); } +struct LLFilteredCollector : public LLInventoryCollectFunctor +{ + enum EFilterLink + { + INCLUDE_LINKS, // show links too + EXCLUDE_LINKS, // don't show links + ONLY_LINKS // only show links + }; + + LLFilteredCollector(LLSD const &data); + virtual ~LLFilteredCollector() {} + virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item) override; + virtual bool exceedsLimit() override { return (mItemLimit <= mItemCount); }; + + protected: + bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item); + bool checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item); + bool checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item); + + LLAssetType::EType mType; + std::string mName; + std::string mDesc; + EFilterLink mLinkFilter; + + S32 mItemLimit; + S32 mItemCount; +}; + void LLInventoryListener::collectDescendentsIf(LLSD const &data) { Response response(LLSD(), data); @@ -164,14 +205,7 @@ void LLInventoryListener::collectDescendentsIf(LLSD const &data) gInventory.collectDescendentsIf(folder_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); - for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); iter != item_array.end(); iter++) - { - add_item_info(response, *iter); - } - for (LLInventoryModel::cat_array_t::iterator iter = cat_array.begin(); iter != cat_array.end(); iter++) - { - add_cat_info(response, *iter); - } + add_objects_info(response, cat_array, item_array); } LLFilteredCollector::LLFilteredCollector(LLSD const &data) : @@ -180,14 +214,10 @@ LLFilteredCollector::LLFilteredCollector(LLSD const &data) : mItemLimit(MAX_ITEM_LIMIT), mItemCount(0) { - if (data.has("name")) - { - mName = data["name"].asString(); - } - if (data.has("desc")) - { - mDesc = data["desc"].asString(); - } + + mName = data["name"].asString(); + mDesc = data["desc"].asString(); + if (data.has("type")) { mType = LLAssetType::lookup(data["type"]); @@ -203,9 +233,9 @@ LLFilteredCollector::LLFilteredCollector(LLSD const &data) : mLinkFilter = ONLY_LINKS; } } - if (data.has("item_limit")) + if (data["limit"].isInteger()) { - mItemLimit = llclamp(data["item_limit"].asInteger(), 1, MAX_ITEM_LIMIT); + mItemLimit = llclamp(data["limit"].asInteger(), 1, MAX_ITEM_LIMIT); } } @@ -222,11 +252,6 @@ bool LLFilteredCollector::operator()(LLInventoryCategory *cat, LLInventoryItem * return passed; } -bool LLFilteredCollector::exceedsLimit() -{ - return (mItemLimit <= mItemCount); -} - bool LLFilteredCollector::checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item) { std::string name, desc; @@ -239,10 +264,10 @@ bool LLFilteredCollector::checkagainstNameDesc(LLInventoryCategory *cat, LLInven if (item) { name = item->getName(); - passed = (mDesc.size() ? item->getDescription().find(mDesc) != std::string::npos : true); + passed = (mDesc.empty() || (item->getDescription().find(mDesc) != std::string::npos)); } - return passed && (mName.size() ? name.find(mName) != std::string::npos : true); + return passed && (mName.empty() || name.find(mName) != std::string::npos); } bool LLFilteredCollector::checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item) @@ -251,12 +276,9 @@ bool LLFilteredCollector::checkagainstType(LLInventoryCategory *cat, LLInventory { return true; } - if (mType == LLAssetType::AT_CATEGORY) + if (cat && (mType == LLAssetType::AT_CATEGORY)) { - if (cat) - { - return true; - } + return true; } if (item && item->getType() == mType) { diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h index 2c1eb2cb6d..5cbac2ca32 100644 --- a/indra/newview/llinventorylistener.h +++ b/indra/newview/llinventorylistener.h @@ -44,33 +44,5 @@ private: void collectDescendentsIf(LLSD const &data); }; -struct LLFilteredCollector : public LLInventoryCollectFunctor -{ - enum EFilterLink - { - INCLUDE_LINKS, // show links too - EXCLUDE_LINKS, // don't show links - ONLY_LINKS // only show links - }; - - LLFilteredCollector(LLSD const &data); - virtual ~LLFilteredCollector() {} - virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); - virtual bool exceedsLimit(); - - protected: - bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item); - bool checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item); - bool checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item); - - LLAssetType::EType mType; - std::string mName; - std::string mDesc; - EFilterLink mLinkFilter; - - S32 mItemLimit; - S32 mItemCount; -}; - #endif // LL_LLINVENTORYLISTENER_H diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index b3f817da94..dd1b910250 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -5,13 +5,13 @@ local LLInventory = {} -- Get the items/folders info by provided IDs, -- reply will contain "items" and "categories" tables accordingly -function LLInventory.getItemsInfo(items_id) - return leap.request('LLInventory', {op = 'getItemsInfo', items_id=items_id}) +function LLInventory.getItemsInfo(item_ids) + return leap.request('LLInventory', {op = 'getItemsInfo', item_ids=item_ids}) end -- Get the table of folder type names, which can be later used to get the ID of the basic folders function LLInventory.getFolderTypeNames() - return leap.request('LLInventory', {op = 'getFolderTypeNames'}).type_names + return leap.request('LLInventory', {op = 'getFolderTypeNames'}).names end -- Get the UUID of the basic folder("Textures", "My outfits", "Sounds" etc.) by specified folder type name @@ -21,7 +21,7 @@ end -- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendentsIf(...) function LLInventory.getAssetTypeNames() - return leap.request('LLInventory', {op = 'getAssetTypeNames'}).type_names + return leap.request('LLInventory', {op = 'getAssetTypeNames'}).names end -- Get the direct descendents of the 'folder_id' provided, @@ -36,10 +36,10 @@ end -- [, name] -- name (substring) -- [, desc] -- description (substring) -- [, type] -- asset type --- [, item_limit] -- item count limit in reply, maximum and default is 100 +-- [, limit] -- item count limit in reply, maximum and default is 100 -- [, filter_links]} -- EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default) function LLInventory.collectDescendentsIf(...) - local args = mapargs('folder_id,name,desc,type,filter_links,item_limit', ...) + local args = mapargs('folder_id,name,desc,type,filter_links,limit', ...) args.op = 'collectDescendentsIf' return leap.request('LLInventory', args) end diff --git a/indra/newview/scripts/lua/test_LLInventory.lua b/indra/newview/scripts/lua/test_LLInventory.lua index dc6eb243ad..107b0791d4 100644 --- a/indra/newview/scripts/lua/test_LLInventory.lua +++ b/indra/newview/scripts/lua/test_LLInventory.lua @@ -4,7 +4,7 @@ LLInventory = require 'LLInventory' -- Get 'My Landmarks' folder id (you can see all folder types via LLInventory.getFolderTypeNames()) my_landmarks_id = LLInventory.getBasicFolderID('landmark') -- Get 3 landmarks from the 'My Landmarks' folder (you can see all folder types via LLInventory.getAssetTypeNames()) -landmarks = LLInventory.collectDescendentsIf{folder_id=my_landmarks_id, type="landmark", item_limit=3} +landmarks = LLInventory.collectDescendentsIf{folder_id=my_landmarks_id, type="landmark", limit=3} print(inspect(landmarks)) -- Get 'Calling Cards' folder id -- cgit v1.2.3 From 14c8fc3768d978205bf17ffc1905c2772afbd434 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 28 Aug 2024 16:47:38 -0400 Subject: Add `LL.setdtor()` function to add a "destructor" to any Lua object. `setdtor('description', object, function)` returns a proxy userdata object referencing object and function. When the proxy is garbage-collected, or at the end of the script, its destructor calls `function(object)`. The original object may be retrieved as `proxy._target`, e.g. to pass it to the `table` library. The proxy also has a metatable with metamethods supporting arithmetic operations, string concatenation, length and table indexing. For other operations, retrieve `proxy._target`. (But don't assign to `proxy._target`. It will appear to work, in that subsequent references to `proxy._target` will retrieve the replacement object -- however, the destructor will still call `function(original object)`.) Fix bugs in `lua_setfieldv()`, `lua_rawgetfield()` and `lua_rawsetfield()`. Add C++ functions `lua_destroyuserdata()` to explicitly destroy a `lua_emplace<T>()` userdata object, plus `lua_destroybounduserdata()`. The latter can bind such a userdata object as an upvalue to pass to `LL.atexit()`. Make `LL.help()` and `LL.leaphelp()` help text include the `LL.` prefix. --- indra/newview/scripts/lua/test_setdtor.lua | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 indra/newview/scripts/lua/test_setdtor.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua new file mode 100644 index 0000000000..743c5168d0 --- /dev/null +++ b/indra/newview/scripts/lua/test_setdtor.lua @@ -0,0 +1,62 @@ +inspect = require 'inspect' + +print('initial setdtor') +bye = LL.setdtor('initial setdtor', 'Goodbye world!', print) + +print('arithmetic') +n = LL.setdtor('arithmetic', 11, print) +print("n =", n) +print("n._target =", n._target) +print("getmetatable(n) =", inspect(getmetatable(n))) +print("-n =", -n) +for i = 10, 12 do + -- Comparison metamethods are only called if both operands have the same + -- metamethod. + tempi = LL.setdtor('tempi', i, function(n) print('temp', i) end) + print(`n < {i}`, n < tempi) + print(`n <= {i}`, n <= tempi) + print(`n == {i}`, n == tempi) + print(`n ~= {i}`, n ~= tempi) + print(`n >= {i}`, n >= tempi) + print(`n > {i}`, n > tempi) +end +for i = 2, 3 do + print(`n + {i} =`, n + i) + print(`{i} + n =`, i + n) + print(`n - {i} =`, n - i) + print(`{i} - n =`, i - n) + print(`n * {i} =`, n * i) + print(`{i} * n =`, i * n) + print(`n / {i} =`, n / i) + print(`{i} / n =`, i / n) + print(`n % {i} =`, n % i) + print(`{i} % n =`, i % n) + print(`n ^ {i} =`, n ^ i) + print(`{i} ^ n =`, i ^ n) +end + +print('string') +s = LL.setdtor('string', 'hello', print) +print('s =', s) +print('#s =', #s) +print('s .. " world" =', s .. " world") +print('"world " .. s =', "world " .. s) + +print('table') +t = LL.setdtor('table', {'[1]', '[2]', abc='.abc', def='.def'}, + function(t) print(inspect(t)) end) +print('t =', inspect(t)) +print('t._target =', inspect(t._target)) +print('#t =', #t) +print('t[2] =', t[2]) +print('t.def =', t.def) +t[1] = 'new [1]' +print('t[1] =', t[1]) + +print('function') +f = LL.setdtor('function', function(a, b) return (a .. b) end, print) +print('f =', f) +print('f._target =', f._target) +print('f("Hello", " world") =', f("Hello", " world")) + +print('cleanup') -- cgit v1.2.3 From 364ea79ab3a4d48e0d10fbeabb9b8e88f226baac Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 28 Aug 2024 19:34:05 -0400 Subject: Prevent erroneous assignment to LL.setdtor() proxy._target field. Trim redundant output from test_setdtor.lua. --- indra/newview/scripts/lua/test_setdtor.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua index 743c5168d0..61ed86dcc8 100644 --- a/indra/newview/scripts/lua/test_setdtor.lua +++ b/indra/newview/scripts/lua/test_setdtor.lua @@ -7,6 +7,7 @@ print('arithmetic') n = LL.setdtor('arithmetic', 11, print) print("n =", n) print("n._target =", n._target) +print(pcall(function() n._target = 12 end)) print("getmetatable(n) =", inspect(getmetatable(n))) print("-n =", -n) for i = 10, 12 do @@ -20,20 +21,19 @@ for i = 10, 12 do print(`n >= {i}`, n >= tempi) print(`n > {i}`, n > tempi) end -for i = 2, 3 do - print(`n + {i} =`, n + i) - print(`{i} + n =`, i + n) - print(`n - {i} =`, n - i) - print(`{i} - n =`, i - n) - print(`n * {i} =`, n * i) - print(`{i} * n =`, i * n) - print(`n / {i} =`, n / i) - print(`{i} / n =`, i / n) - print(`n % {i} =`, n % i) - print(`{i} % n =`, i % n) - print(`n ^ {i} =`, n ^ i) - print(`{i} ^ n =`, i ^ n) -end +i = 2 +print(`n + {i} =`, n + i) +print(`{i} + n =`, i + n) +print(`n - {i} =`, n - i) +print(`{i} - n =`, i - n) +print(`n * {i} =`, n * i) +print(`{i} * n =`, i * n) +print(`n / {i} =`, n / i) +print(`{i} / n =`, i / n) +print(`n % {i} =`, n % i) +print(`{i} % n =`, i % n) +print(`n ^ {i} =`, n ^ i) +print(`{i} ^ n =`, i ^ n) print('string') s = LL.setdtor('string', 'hello', print) -- cgit v1.2.3 From baa7255687f265b2996754490083e7c26c646d72 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 28 Aug 2024 20:50:33 -0400 Subject: Add script control to "Inventory.DoCreate" registered menu action. --- indra/newview/llinventorygallerymenu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 37e2228b2e..2845c5b614 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -106,7 +106,8 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() { mGallery->doCreate(mUUIDs.front(), data); } - }); + }, + LLUICtrl::cb_info::UNTRUSTED_BLOCK); std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end()); registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)), LLUICtrl::cb_info::UNTRUSTED_BLOCK); -- cgit v1.2.3 From 03d7f2b84daf9ab991de6cad7d6149abda1ef716 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 28 Aug 2024 21:16:56 -0400 Subject: Ditch trailing spaces. --- indra/newview/llappearancemgr.cpp | 2 +- indra/newview/llappearancemgr.h | 2 +- indra/newview/llfloatergodtools.cpp | 2 +- indra/newview/llfloaterluadebug.h | 12 ++++++------ indra/newview/llfloaterluascripts.cpp | 22 +++++++++++----------- indra/newview/llfloaterluascripts.h | 12 ++++++------ indra/newview/llinventorygallerymenu.cpp | 4 ++-- indra/newview/llinventorylistener.cpp | 2 +- indra/newview/llluamanager.cpp | 14 +++++++------- indra/newview/llluamanager.h | 16 ++++++++-------- indra/newview/llpanelmaininventory.cpp | 2 +- indra/newview/llpanelobjectinventory.cpp | 4 ++-- indra/newview/lluilistener.cpp | 16 ++++++++-------- indra/newview/lluilistener.h | 10 +++++----- indra/newview/llviewerchat.cpp | 2 +- indra/newview/llvoavatar.cpp | 2 +- indra/newview/tests/llluamanager_test.cpp | 2 +- 17 files changed, 63 insertions(+), 63 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 72c20d377b..632366e801 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2957,7 +2957,7 @@ bool LLAppearanceMgr::wearOutfit(const LLUUID &cat_id, std::string &error_msg, b return wearOutfit(stringize(cat_id), cat, error_msg, false, append); } -bool LLAppearanceMgr::wearOutfit(const std::string &desc, LLInventoryCategory* cat, +bool LLAppearanceMgr::wearOutfit(const std::string &desc, LLInventoryCategory* cat, std::string &error_msg, bool copy_items, bool append) { if (!cat) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index d15394df15..9e624f593f 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -264,7 +264,7 @@ private: static void onOutfitRename(const LLSD& notification, const LLSD& response); // used by both wearOutfit(LLUUID) and wearOutfitByName(std::string) - bool wearOutfit(const std::string &desc, LLInventoryCategory* cat, + bool wearOutfit(const std::string &desc, LLInventoryCategory* cat, std::string &error_msg, bool copy_items, bool append); bool mAttachmentInvLinkEnabled; diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index 4217b3ad49..f2884c3a6e 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -854,7 +854,7 @@ void LLPanelRegionTools::onSelectRegion() LLPanelGridTools::LLPanelGridTools() : LLPanel() { - mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches", + mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches", { boost::bind(&LLPanelGridTools::onClickFlushMapVisibilityCaches, this), cb_info::UNTRUSTED_BLOCK }); } diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index e513d9a095..9f044df9d9 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -1,24 +1,24 @@ -/** +/** * @file llfloaterluadebug.h * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,7 +41,7 @@ extern "C" class LLLineEditor; class LLTextEditor; -class LLFloaterLUADebug : +class LLFloaterLUADebug : public LLFloater { public: diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 189ee0c9d1..60cdadfbee 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llfloaterluascriptsinfo.cpp * * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2024, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,16 +41,16 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) mUpdateTimer(new LLTimer()), mContextMenuHandle() { - mCommitCallbackRegistrar.add("Script.OpenFolder", {[this](LLUICtrl*, const LLSD &userdata) - { + mCommitCallbackRegistrar.add("Script.OpenFolder", {[this](LLUICtrl*, const LLSD &userdata) + { if (mScriptList->hasSelectedItem()) { std::string target_folder_path = std::filesystem::path((mScriptList->getFirstSelected()->getColumn(1)->getValue().asString())).parent_path().string(); gViewerWindow->getWindow()->openFolder(target_folder_path); } }, cb_info::UNTRUSTED_BLOCK }); - mCommitCallbackRegistrar.add("Script.Terminate", {[this](LLUICtrl*, const LLSD &userdata) - { + mCommitCallbackRegistrar.add("Script.Terminate", {[this](LLUICtrl*, const LLSD &userdata) + { if (mScriptList->hasSelectedItem()) { std::string coro_name = mScriptList->getSelectedValue(); @@ -75,7 +75,7 @@ BOOL LLFloaterLUAScripts::postBuild() return TRUE; } -LLFloaterLUAScripts::~LLFloaterLUAScripts() +LLFloaterLUAScripts::~LLFloaterLUAScripts() { auto menu = mContextMenuHandle.get(); if (menu) @@ -94,7 +94,7 @@ void LLFloaterLUAScripts::draw() LLFloater::draw(); } -void LLFloaterLUAScripts::populateScriptList() +void LLFloaterLUAScripts::populateScriptList() { S32 prev_pos = mScriptList->getScrollPos(); LLSD prev_selected = mScriptList->getSelectedValue(); diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h index 932c5c78dd..24d3f00a80 100644 --- a/indra/newview/llfloaterluascripts.h +++ b/indra/newview/llfloaterluascripts.h @@ -1,24 +1,24 @@ -/** +/** * @file llfloaterluascriptsinfo.h * * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2024, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,7 +30,7 @@ class LLScrollListCtrl; -class LLFloaterLUAScripts : +class LLFloaterLUAScripts : public LLFloater { public: diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 2845c5b614..133ef51a21 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -92,9 +92,9 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK); - registrar.add("Inventory.EmptyTrash", + registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK); - registrar.add("Inventory.EmptyLostAndFound", + registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK); registrar.add("Inventory.DoCreate", [this](LLUICtrl*, const LLSD& data) { diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index 157e04dce3..9263663997 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -154,7 +154,7 @@ void LLInventoryListener::getBasicFolderID(LLSD const &data) void LLInventoryListener::getDirectDescendents(LLSD const &data) { Response response(LLSD(), data); - LLInventoryModel::cat_array_t* cats; + LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(data["folder_id"], cats, items); diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 22b51d7b72..41b1cd55b7 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llluamanager.cpp - * @brief classes and functions for interfacing with LUA. + * @brief classes and functions for interfacing with LUA. * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @@ -193,7 +193,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r llifstream in_file; in_file.open(filename.c_str()); - if (in_file.is_open()) + if (in_file.is_open()) { // A script_finished_fn is used to initialize the LuaState. // It will be called when the LuaState is destroyed. diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 50f922a80f..08997c29a5 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -1,25 +1,25 @@ -/** +/** * @file llluamanager.h - * @brief classes and functions for interfacing with LUA. + * @brief classes and functions for interfacing with LUA. * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -110,9 +110,9 @@ class LLRequireResolver class ScriptObserver { public: - ScriptObserver(const std::string &coro_name, const std::string &filename) : mCoroName(coro_name) + ScriptObserver(const std::string &coro_name, const std::string &filename) : mCoroName(coro_name) { - LLLUAmanager::sScriptNames[mCoroName] = filename; + LLLUAmanager::sScriptNames[mCoroName] = filename; } ~ScriptObserver() { LLLUAmanager::sScriptNames.erase(mCoroName); } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index fc5390e0dc..622698c5fa 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -127,7 +127,7 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p) // Menu Callbacks (non contex menus) mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLPanelMainInventory::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", { boost::bind(&LLPanelMainInventory::closeAllFolders, this) }); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK }); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 64a9518e21..395e9eca82 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1347,9 +1347,9 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par { // Setup context menu callbacks mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLPanelObjectInventory::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK }); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), cb_info::UNTRUSTED_BLOCK }); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), cb_info::UNTRUSTED_BLOCK }); mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&do_nothing) }); mCommitCallbackRegistrar.add("Inventory.AttachObject", { boost::bind(&do_nothing) }); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 0280836075..6f567e67f8 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-18 * @brief Implementation for lluilistener. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -93,7 +93,7 @@ LLUIListener::LLUIListener(): "to the [\"parent_menu\"] within the Top menu.", &LLUIListener::addMenuItem, required_args.with("func", LLSD())); - + add("addMenuSeparator", "Add menu separator to the [\"parent_menu\"] within the Top menu.", &LLUIListener::addMenuSeparator, @@ -147,7 +147,7 @@ void LLUIListener::call(const LLSD& event) { return response.error(stringize("Function ", std::quoted(event["function"].asString()), " was not found")); } - if (info->handle_untrusted == cb_info::UNTRUSTED_BLOCK) + if (info->handle_untrusted == cb_info::UNTRUSTED_BLOCK) { return response.error(stringize("Function ", std::quoted(event["function"].asString()), " may not be called from the script")); } @@ -226,7 +226,7 @@ void LLUIListener::getValue(const LLSD& event) const const LLView* view = LLUI::getInstance()->resolvePath(root, event["path"].asString()); const LLUICtrl* ctrl(dynamic_cast<const LLUICtrl*>(view)); - if (ctrl) + if (ctrl) { response["value"] = ctrl->getValue(); } diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index c839c03a57..8fc8e6ebb4 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-18 * @brief Engage named functions as specified by XUI - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 00520f100e..440c0a2f69 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -227,7 +227,7 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg) formated_msg = tmpmsg; } - if (chat.mIsScript) + if (chat.mIsScript) { formated_msg = LLTrans::getString("ScriptStr") + formated_msg; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index ae6500da70..7f8f3961d3 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -11784,7 +11784,7 @@ class LLVOAvatarListener : public LLEventAPI } void isInAir(const LLSD &request) const { - Response response(llsd::map("value", gAgentAvatarp->mInAir, + Response response(llsd::map("value", gAgentAvatarp->mInAir, "duration", gAgentAvatarp->mInAir ? gAgentAvatarp->mTimeInAir.getElapsedTimeF32() : 0), request); } }; diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 3209d93d39..4b143b52db 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2023-09-28 * @brief Test for llluamanager. - * + * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Copyright (c) 2023, Linden Research, Inc. * $/LicenseInfo$ -- cgit v1.2.3 From e25d23aaac77f3793207aa0baf59ae64ea5eba41 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Thu, 29 Aug 2024 08:54:40 +0300 Subject: #2059 Linux build fix --- indra/newview/pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index eaf54356a2..cd93df71c7 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -121,7 +121,7 @@ #define A_GCC 1 #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" -#if LL_LINUX +#if LL_LINUX && defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic ignored "-Wrestrict" #endif #endif -- cgit v1.2.3 From 11e6c77129ae27756df627ccc1ea0ffa279976e6 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Thu, 29 Aug 2024 20:04:34 +0300 Subject: Add simple metrics of Lua usage --- indra/newview/llappviewer.cpp | 2 +- indra/newview/llfloaterluadebug.cpp | 2 +- indra/newview/llluamanager.cpp | 16 ++++++++++++---- indra/newview/llluamanager.h | 5 ++++- indra/newview/llviewerstats.cpp | 5 +++++ 5 files changed, 23 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c259275d8f..686b97390a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1252,7 +1252,7 @@ bool LLAppViewer::init() while (scripts.next(script)) { LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << ": " << script << LL_ENDL; - LLLUAmanager::runScriptFile((abspath / script).string()); + LLLUAmanager::runScriptFile((abspath / script).string(), true); } }); diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index ef24481464..1831edb452 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -127,7 +127,7 @@ void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filena if (!filepath.empty()) { mScriptPath->setText(filepath); - LLLUAmanager::runScriptFile(filepath, [this](int count, const LLSD &result) + LLLUAmanager::runScriptFile(filepath, false, [this](int count, const LLSD &result) { completion(count, result); }); diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 22b51d7b72..befd231e92 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -49,6 +49,8 @@ #include <string_view> #include <vector> +S32 LLLUAmanager::sAutorunScriptCount = 0; +S32 LLLUAmanager::sScriptCount = 0; std::map<std::string, std::string> LLLUAmanager::sScriptNames; lua_function(sleep, "sleep(seconds): pause the running coroutine") @@ -172,7 +174,7 @@ LLLUAmanager::startScriptFile(const std::string& filename) // Despite returning from startScriptFile(), we need this Promise to // remain alive until the callback has fired. auto promise{ std::make_shared<LLCoros::Promise<script_result>>() }; - runScriptFile(filename, + runScriptFile(filename, false, [promise](int count, LLSD result) { promise->set_value({ count, result }); }); return LLCoros::getFuture(*promise); @@ -183,11 +185,11 @@ LLLUAmanager::script_result LLLUAmanager::waitScriptFile(const std::string& file return startScriptFile(filename).get(); } -void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, - script_finished_fn finished_cb) +void LLLUAmanager::runScriptFile(const std::string &filename, bool autorun, + script_result_fn result_cb, script_finished_fn finished_cb) { // A script_result_fn will be called when LuaState::expr() completes. - LLCoros::instance().launch(filename, [filename, result_cb, finished_cb]() + LLCoros::instance().launch(filename, [filename, autorun, result_cb, finished_cb]() { ScriptObserver observer(LLCoros::getName(), filename); llifstream in_file; @@ -195,6 +197,12 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r if (in_file.is_open()) { + if (autorun) + { + sAutorunScriptCount++; + } + sScriptCount++; + // A script_finished_fn is used to initialize the LuaState. // It will be called when the LuaState is destroyed. LuaState L(finished_cb); diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index 50f922a80f..309cb87cac 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -58,7 +58,7 @@ public: // same semantics as script_result_fn parameters typedef std::pair<int, LLSD> script_result; - static void runScriptFile(const std::string &filename, script_result_fn result_cb = {}, + static void runScriptFile(const std::string &filename, bool autorun = false, script_result_fn result_cb = {}, script_finished_fn finished_cb = {}); // Start running a Lua script file, returning an LLCoros::Future whose // get() method will pause the calling coroutine until it can deliver the @@ -84,6 +84,9 @@ public: static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } + static S32 sAutorunScriptCount; + static S32 sScriptCount; + private: static std::map<std::string, std::string> sScriptNames; }; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 62b4c390d0..60e8cf2e52 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -66,6 +66,7 @@ #include "llinventorymodel.h" #include "lluiusage.h" #include "lltranslate.h" +#include "llluamanager.h" // "Minimal Vulkan" to get max API Version @@ -673,6 +674,10 @@ void send_viewer_stats(bool include_preferences) system["shader_level"] = shader_level; + LLSD &scripts = body["scripts"]; + scripts["lua_scripts"] = LLLUAmanager::sScriptCount; + scripts["lua_auto_scripts"] = LLLUAmanager::sAutorunScriptCount; + LLSD &download = body["downloads"]; download["world_kbytes"] = F64Kilobytes(gTotalWorldData).value(); -- cgit v1.2.3 From 2d5cf36be6e0e367efec2bfa01378146269f33db Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 29 Aug 2024 21:36:39 -0400 Subject: Support next(), pairs(), ipairs() for LL.setdtor() table proxies. Replace the global next(), pairs() and ipairs() functions with a C++ function that drills down through layers of setdtor() proxy objects and then forwards the updated arguments to the original global function. Add a Luau __iter() metamethod to setdtor() proxy objects that, like other proxy metamethods, drills down to the underlying _target object. __iter() recognizes the case of a _target table which itself has a __iter() metamethod. Also add __idiv() metamethod to support integer division. Add tests for proxy // division, next(proxy), next(proxy, key), pairs(proxy), ipairs(proxy) and 'for k, v in proxy'. Also test the case where the table wrapped in the proxy has an __iter() metamethod of its own. --- indra/newview/scripts/lua/test_setdtor.lua | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua index 61ed86dcc8..ec5cd47e93 100644 --- a/indra/newview/scripts/lua/test_setdtor.lua +++ b/indra/newview/scripts/lua/test_setdtor.lua @@ -30,6 +30,8 @@ print(`n * {i} =`, n * i) print(`{i} * n =`, i * n) print(`n / {i} =`, n / i) print(`{i} / n =`, i / n) +print(`n // {i} =`, n // i) +print(`{i} // n =`, i // n) print(`n % {i} =`, n % i) print(`{i} % n =`, i % n) print(`n ^ {i} =`, n ^ i) @@ -48,10 +50,37 @@ t = LL.setdtor('table', {'[1]', '[2]', abc='.abc', def='.def'}, print('t =', inspect(t)) print('t._target =', inspect(t._target)) print('#t =', #t) +print('next(t) =', next(t)) +print('next(t, 1) =', next(t, 1)) print('t[2] =', t[2]) print('t.def =', t.def) t[1] = 'new [1]' print('t[1] =', t[1]) +print('for k, v in pairs(t) do') +for k, v in pairs(t) do + print(`{k}: {v}`) +end +print('for k, v in ipairs(t) do') +for k, v in ipairs(t) do + print(`{k}: {v}`) +end +print('for k, v in t do') +for k, v in t do + print(`{k}: {v}`) +end +-- and now for something completely different +setmetatable( + t._target, + { + __iter = function(arg) + return next, {'alternate', '__iter'} + end + } +) +print('for k, v in t with __iter() metamethod do') +for k, v in t do + print(`{k}: {v}`) +end print('function') f = LL.setdtor('function', function(a, b) return (a .. b) end, print) -- cgit v1.2.3 From 6e47dc1af90c242c792c90e93d013355c9a43b97 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 30 Aug 2024 12:18:20 +0300 Subject: Add Lua api to start/stop playing animation --- indra/newview/llagentlistener.cpp | 66 +++++++++++++++++++++++++++ indra/newview/llagentlistener.h | 4 ++ indra/newview/scripts/lua/require/LLAgent.lua | 14 ++++++ 3 files changed, 84 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 80460666a5..95b7ebd5db 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -34,12 +34,14 @@ #include "llagentcamera.h" #include "llvoavatar.h" #include "llcommandhandler.h" +#include "llinventorymodel.h" #include "llslurl.h" #include "llurldispatcher.h" #include "llviewernetwork.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llvoavatarself.h" #include "llsdutil.h" #include "llsdutil_math.h" #include "lltoolgrab.h" @@ -157,6 +159,19 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("removeCameraParams", "Reset Follow camera params", &LLAgentListener::removeFollowCamParams); + + add("playAnimation", + "Play [\"item_id\"] animation locally (by default) or [\"inworld\"] (when set to true)", + &LLAgentListener::playAnimation, + llsd::map("item_id", LLSD(), "reply", LLSD())); + add("stopAnimation", + "Stop playing [\"item_id\"] animation", + &LLAgentListener::stopAnimation, + llsd::map("item_id", LLSD(), "reply", LLSD())); + add("getAnimationInfo", + "Return information about [\"item_id\"] animation", + &LLAgentListener::getAnimationInfo, + llsd::map("item_id", LLSD(), "reply", LLSD())); } void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -591,3 +606,54 @@ void LLAgentListener::removeFollowCamParams(LLSD const & event) const { LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID); } + +void LLAgentListener::playAnimation(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID()); + if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) + { + return response.error(stringize("Item ", std::quoted(event_data["item_id"].asString()), " was not found")); + } + LLUUID assset_id = item->getAssetUUID(); + if(event_data["inworld"].asBoolean()) + { + gAgent.sendAnimationRequest(assset_id, ANIM_REQUEST_START); + } + else + { + gAgentAvatarp->startMotion(assset_id); + } +} + +void LLAgentListener::stopAnimation(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID()); + if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) + { + return response.error(stringize("Item ", std::quoted(event_data["item_id"].asString()), " was not found")); + } + LLUUID assset_id = item->getAssetUUID(); + gAgentAvatarp->stopMotion(assset_id); + gAgent.sendAnimationRequest(assset_id, ANIM_REQUEST_STOP); +} + +void LLAgentListener::getAnimationInfo(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + LLUUID item_id(event_data["item_id"].asUUID()); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) + { + return response.error(stringize("Item ", std::quoted(item_id.asString()), " was not found")); + } + // if motion exists, will return existing one + LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID()); + response["anim_info"].insert(item_id.asString(), + llsd::map("duration", motion->getDuration(), + "is_loop", motion->getLoop(), + "num_joints", motion->getNumJointMotions(), + "asset_id", item->getAssetUUID(), + "priority", motion->getPriority())); +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 2a24de3f52..cf914a17d0 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -60,6 +60,10 @@ private: void setFollowCamParams(LLSD const & event_data) const; void setFollowCamActive(LLSD const & event_data) const; void removeFollowCamParams(LLSD const & event_data) const; + + void playAnimation(LLSD const &event_data); + void stopAnimation(LLSD const &event_data); + void getAnimationInfo(LLSD const &event_data); LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 5ee092f2f6..56907f53cd 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -53,4 +53,18 @@ function LLAgent.removeCamParams() leap.send('LLAgent', {op = 'removeCameraParams'}) end +function LLAgent.playAnimation(...) + local args = mapargs('item_id,inworld', ...) + args.op = 'playAnimation' + return leap.request('LLAgent', args) +end + +function LLAgent.stopAnimation(item_id) + return leap.request('LLAgent', {op = 'stopAnimation', item_id=item_id}) +end + +function LLAgent.getAnimationInfo(item_id) + return leap.request('LLAgent', {op = 'getAnimationInfo', item_id=item_id}).anim_info +end + return LLAgent -- cgit v1.2.3 From 4312a2b7703f6ba35a1cdcd1edc48dddfe084270 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 30 Aug 2024 14:48:36 +0300 Subject: Add throttle for playing an animation; add demo script --- indra/newview/llagentlistener.cpp | 59 +++++++++++++++------------ indra/newview/llagentlistener.h | 4 ++ indra/newview/scripts/lua/require/LLAgent.lua | 4 ++ indra/newview/scripts/lua/test_animation.lua | 28 +++++++++++++ 4 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 indra/newview/scripts/lua/test_animation.lua (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 95b7ebd5db..4980c7075f 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -49,9 +49,12 @@ #include "llagentcamera.h" #include <functional> +static const F64 PLAY_ANIM_THROTTLE_PERIOD = 1.f; + LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", "LLAgent listener to (e.g.) teleport, sit, stand, etc."), + mPlayAnimThrottle("playAnimation", &LLAgentListener::playAnimation_, this, PLAY_ANIM_THROTTLE_PERIOD), mAgent(agent) { add("requestTeleport", @@ -607,53 +610,59 @@ void LLAgentListener::removeFollowCamParams(LLSD const & event) const LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID); } -void LLAgentListener::playAnimation(LLSD const &event_data) +LLViewerInventoryItem* get_anim_item(LLEventAPI::Response &response, const LLSD &event_data) { - Response response(LLSD(), event_data); LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID()); if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) { - return response.error(stringize("Item ", std::quoted(event_data["item_id"].asString()), " was not found")); + response.error(stringize("Animation item ", std::quoted(event_data["item_id"].asString()), " was not found")); + return NULL; + } + return item; +} + +void LLAgentListener::playAnimation(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) + { + mPlayAnimThrottle(item->getAssetUUID(), event_data["inworld"].asBoolean()); } - LLUUID assset_id = item->getAssetUUID(); - if(event_data["inworld"].asBoolean()) +} + +void LLAgentListener::playAnimation_(const LLUUID& asset_id, const bool inworld) +{ + if (inworld) { - gAgent.sendAnimationRequest(assset_id, ANIM_REQUEST_START); + mAgent.sendAnimationRequest(asset_id, ANIM_REQUEST_START); } else { - gAgentAvatarp->startMotion(assset_id); + gAgentAvatarp->startMotion(asset_id); } } void LLAgentListener::stopAnimation(LLSD const &event_data) { Response response(LLSD(), event_data); - LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID()); - if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) + if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) { - return response.error(stringize("Item ", std::quoted(event_data["item_id"].asString()), " was not found")); + gAgentAvatarp->stopMotion(item->getAssetUUID()); + mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); } - LLUUID assset_id = item->getAssetUUID(); - gAgentAvatarp->stopMotion(assset_id); - gAgent.sendAnimationRequest(assset_id, ANIM_REQUEST_STOP); } void LLAgentListener::getAnimationInfo(LLSD const &event_data) { Response response(LLSD(), event_data); - LLUUID item_id(event_data["item_id"].asUUID()); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) + if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) { - return response.error(stringize("Item ", std::quoted(item_id.asString()), " was not found")); + // if motion exists, will return existing one + LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID()); + response["anim_info"] = llsd::map("duration", motion->getDuration(), + "is_loop", motion->getLoop(), + "num_joints", motion->getNumJointMotions(), + "asset_id", item->getAssetUUID(), + "priority", motion->getPriority()); } - // if motion exists, will return existing one - LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID()); - response["anim_info"].insert(item_id.asString(), - llsd::map("duration", motion->getDuration(), - "is_loop", motion->getLoop(), - "num_joints", motion->getNumJointMotions(), - "asset_id", item->getAssetUUID(), - "priority", motion->getPriority())); } diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index cf914a17d0..c77d1b3fc9 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -31,6 +31,7 @@ #define LL_LLAGENTLISTENER_H #include "lleventapi.h" +#include "throttle.h" class LLAgent; class LLSD; @@ -62,6 +63,7 @@ private: void removeFollowCamParams(LLSD const & event_data) const; void playAnimation(LLSD const &event_data); + void playAnimation_(const LLUUID& asset_id, const bool inworld); void stopAnimation(LLSD const &event_data); void getAnimationInfo(LLSD const &event_data); @@ -70,6 +72,8 @@ private: private: LLAgent & mAgent; LLUUID mFollowTarget; + + LogThrottle<LLError::LEVEL_DEBUG, void(const LLUUID &, const bool)> mPlayAnimThrottle; }; #endif // LL_LLAGENTLISTENER_H diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 56907f53cd..07ef1e0b0b 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -53,6 +53,8 @@ function LLAgent.removeCamParams() leap.send('LLAgent', {op = 'removeCameraParams'}) end +-- Play specified animation by "item_id" locally +-- if "inworld" is specified as true, animation will be played inworld instead function LLAgent.playAnimation(...) local args = mapargs('item_id,inworld', ...) args.op = 'playAnimation' @@ -63,6 +65,8 @@ function LLAgent.stopAnimation(item_id) return leap.request('LLAgent', {op = 'stopAnimation', item_id=item_id}) end +-- Get animation info by "item_id" +-- reply contains "duration", "is_loop", "num_joints", "asset_id", "priority" function LLAgent.getAnimationInfo(item_id) return leap.request('LLAgent', {op = 'getAnimationInfo', item_id=item_id}).anim_info end diff --git a/indra/newview/scripts/lua/test_animation.lua b/indra/newview/scripts/lua/test_animation.lua new file mode 100644 index 0000000000..c16fef4918 --- /dev/null +++ b/indra/newview/scripts/lua/test_animation.lua @@ -0,0 +1,28 @@ +LLInventory = require 'LLInventory' +LLAgent = require 'LLAgent' + +-- Get 'Animations' folder id (you can see all folder types via LLInventory.getFolderTypeNames()) +animations_id = LLInventory.getBasicFolderID('animatn') +-- Get animations from the 'Animation' folder (you can see all folder types via LLInventory.getAssetTypeNames()) +anims = LLInventory.collectDescendentsIf{folder_id=animations_id, type="animatn"}.items + +local anim_ids = {} +for key in pairs(anims) do + table.insert(anim_ids, key) +end + +-- Start playing a random animation +math.randomseed(os.time()) +local random_id = anim_ids[math.random(#anim_ids)] +local anim_info = LLAgent.getAnimationInfo(random_id) + +print("Starting animation locally: " .. anims[random_id].name) +print("Loop: " .. anim_info.is_loop .. " Joints: " .. anim_info.num_joints .. " Duration " .. tonumber(string.format("%.2f", anim_info.duration))) +LLAgent.playAnimation{item_id=random_id} + +-- Stop animation after 3 sec if it's looped or longer than 3 sec +if anim_info.is_loop == 1 or anim_info.duration > 3 then + LL.sleep(3) + print("Stop animation.") + LLAgent.stopAnimation(random_id) +end -- cgit v1.2.3 From 23f0aafb74551a741de8c87d62d74e7c6cee8b01 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Sat, 31 Aug 2024 09:42:52 -0400 Subject: Give certain LLInventory queries an API based on result sets. Introduce abstract base class InvResultSet, derived from LLIntTracker so each instance has a unique int key. InvResultSet supports virtual getLength() and getSlice() operations. getSlice() returns an LLSD array limited to MAX_ITEM_LIMIT result set entries. It permits retrieving a "slice" of the contained result set starting at an arbitrary index. A sequence of getSlice() calls can eventually retrieve a whole result set. InvResultSet has subclasses CatResultSet containing cat_array_t, and ItemResultSet containing item_array_t. Each implements a virtual method that produces an LLSD map from a single array item. Make LLInventoryListener::getItemsInfo(), getDirectDescendants() and collectDescendantsIf() instantiate heap CatResultSet and ItemResultSet objects containing the resultant LLPointer arrays, and return their int keys for categories and items. Add LLInventoryListener::getSlice() and closeResult() methods that accept the int keys of result sets. getSlice() returns the requested LLSD array to its caller, while closeResult() is fire-and-forget. Because bulk data transfer is now performed by getSlice() rather than by collectDescendantsIf(), change the latter's "limit" default to unlimited. Allow the C++ code to collect an arbitrary number of LLPointer array entries, as long as getSlice() limits retrieval overhead. Spell "descendants" correctly, unlike the "descendents" spelling embedded in the rest of the viewer... sigh. Make the Lua module provide both spellings. Make MAX_ITEM_LIMIT a U32 instead of F32. In LLInventory.lua, store int result set keys from 'getItemsInfo', 'getDirectDescendants' and 'collectDescendantsIf' in a table with a close() function. The close() function invokes 'closeResult' with the bound int keys. Give that table an __index() metamethod that recognizes only 'categories' and 'items' keys: anything else returns nil. For either of the recognized keys, call 'getSlice' with the corresponding result set key to retrieve (the initial slice of) the actual result set. Cache that result. Lazy retrieval means that if the caller only cares about categories, or only about items, the other result set need never be retrieved at all. This is a first step: like the previous code, it still retrieves only up to the first 100 result set entries. But the C++ code now supports retrieval of additional slices, so extending result set retrieval is mostly Lua work. Finally, wrap the table-with-metamethod in an LL.setdtor() proxy whose destructor calls its close() method to tell LLInventoryListener to destroy the CatResultSet and ItemResultSet with the bound keys. --- indra/newview/llinventorylistener.cpp | 261 ++++++++++++++++++---- indra/newview/llinventorylistener.h | 9 +- indra/newview/scripts/lua/require/LLInventory.lua | 79 ++++++- 3 files changed, 289 insertions(+), 60 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index 157e04dce3..c330ef42a0 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -28,12 +28,13 @@ #include "llinventorylistener.h" #include "llappearancemgr.h" +#include "llinttracker.h" #include "llinventoryfunctions.h" #include "lltransutil.h" #include "llwearableitemslist.h" #include "stringize.h" -static const F32 MAX_ITEM_LIMIT = 100; +constexpr U32 MAX_ITEM_LIMIT = 100; LLInventoryListener::LLInventoryListener() : LLEventAPI("LLInventory", @@ -41,7 +42,7 @@ LLInventoryListener::LLInventoryListener() { add("getItemsInfo", "Return information about items or folders defined in [\"item_ids\"]:\n" - "reply will contain [\"items\"] and [\"categories\"] tables accordingly", + "reply will contain [\"items\"] and [\"categories\"] result set keys", &LLInventoryListener::getItemsInfo, llsd::map("item_ids", LLSD(), "reply", LLSD())); @@ -61,78 +62,190 @@ LLInventoryListener::LLInventoryListener() &LLInventoryListener::getBasicFolderID, llsd::map("ft_name", LLSD(), "reply", LLSD())); - add("getDirectDescendents", - "Return the direct descendents(both items and folders) of the [\"folder_id\"]", - &LLInventoryListener::getDirectDescendents, + add("getDirectDescendants", + "Return result set keys [\"categories\"] and [\"items\"] for the direct\n" + "descendants of the [\"folder_id\"]", + &LLInventoryListener::getDirectDescendants, llsd::map("folder_id", LLSD(), "reply", LLSD())); - add("collectDescendentsIf", - "Return the descendents(both items and folders) of the [\"folder_id\"], if it passes specified filters:\n" + add("collectDescendantsIf", + "Return result set keys [\"categories\"] and [\"items\"] for the descendants\n" + "of the [\"folder_id\"], if it passes specified filters:\n" "[\"name\"] is a substring of object's name,\n" "[\"desc\"] is a substring of object's description,\n" "asset [\"type\"] corresponds to the string name of the object's asset type\n" - "[\"limit\"] sets item count limit in reply, maximum and default is 100\n" + "[\"limit\"] sets item count limit in result set (default unlimited)\n" "[\"filter_links\"]: EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)", - &LLInventoryListener::collectDescendentsIf, + &LLInventoryListener::collectDescendantsIf, llsd::map("folder_id", LLSD(), "reply", LLSD())); - } - -void add_item_info(LLEventAPI::Response& response, LLViewerInventoryItem* item) -{ - response["items"].insert(item->getUUID().asString(), - llsd::map("name", item->getName(), - "parent_id", item->getParentUUID(), - "desc", item->getDescription(), - "inv_type", LLInventoryType::lookup(item->getInventoryType()), - "asset_type", LLAssetType::lookup(item->getType()), - "creation_date", (S32) item->getCreationDate(), - "asset_id", item->getAssetUUID(), - "is_link", item->getIsLinkType(), - "linked_id", item->getLinkedUUID())); +/*==========================================================================*| + add("getSingle", + "Return LLSD [\"single\"] for a single folder or item from the specified\n" + "[\"result\"] key at the specified 0-relative [\"index\"].", + &LLInventoryListener::getSingle, + llsd::map("result", LLSD::Integer(), "index", LLSD::Integer(), + "reply", LLSD::String())); +|*==========================================================================*/ + + add("getSlice", + stringize( + "Return an LLSD array [\"slice\"] from the specified [\"result\"] key\n" + "starting at 0-relative [\"index\"] with (up to) [\"count\"] entries.\n" + "count is limited to ", MAX_ITEM_LIMIT, " (default and max)."), + &LLInventoryListener::getSlice, + llsd::map("result", LLSD::Integer(), "index", LLSD::Integer(), + "reply", LLSD::String())); + + add("closeResult", + "Release resources associated with specified [\"result\"] key,\n" + "or keys if [\"result\"] is an array.", + &LLInventoryListener::closeResult, + llsd::map("result", LLSD())); } -void add_cat_info(LLEventAPI::Response &response, LLViewerInventoryCategory *cat) +// This abstract base class defines the interface for CatResultSet and +// ItemResultSet. It isa LLIntTracker so we can pass its unique int key to a +// consuming script via LLSD. +struct InvResultSet: public LLIntTracker<InvResultSet> { - response["categories"].insert(cat->getUUID().asString(), - llsd::map("name", cat->getName(), - "parent_id", cat->getParentUUID(), - "type", LLFolderType::lookup(cat->getPreferredType()))); -} + // Get the length of the result set. Indexes are 0-relative. + virtual int getLength() const = 0; +/*==========================================================================*| + // Retrieve LLSD corresponding to a single entry from the result set, + // with index validation. + LLSD getSingle(int index) const + { + if (0 <= index && index < getLength()) + { + return getSingle_(index); + } + else + { + return {}; + } + } +|*==========================================================================*/ + // Retrieve LLSD corresponding to a single entry from the result set, + // once we're sure the index is valid. + virtual LLSD getSingle(int index) const = 0; + // Retrieve LLSD corresponding to a "slice" of the result set: a + // contiguous sub-array starting at index. The returned LLSD array might + // be shorter than count entries if count > MAX_ITEM_LIMIT, or if the + // specified slice contains the end of the result set. + LLSD getSlice(int index, int count) const + { + // only call getLength() once + auto length = getLength(); + // Adjust bounds [start, end) to overlap the actual result set from + // [0, getLength()). Permit negative index; e.g. with a result set + // containing 5 entries, getSlice(-2, 5) will adjust start to 0 and + // end to 3. + int start = llclamp(index, 0, length); + // Constrain count to MAX_ITEM_LIMIT even before clamping end. + int end = llclamp(index + llclamp(count, 0, MAX_ITEM_LIMIT), 0, length); + LLSD result{ LLSD::emptyArray() }; + // beware of count == 0, or an [index, count) range that doesn't even + // overlap [0, length) at all + if (end > start) + { + // right away expand the result array to the size we'll need + result[end - 1] = LLSD(); + for (int i = start; i < end; ++i) + { + result[i] = getSingle(i); + } + } + return result; + } + + /*---------------- the rest is solely for debug logging ----------------*/ + std::string mName; + + friend std::ostream& operator<<(std::ostream& out, const InvResultSet& self) + { + return out << "InvResultSet(" << self.mName << ", " << self.getKey() << ")"; + } + + InvResultSet(const std::string& name): + mName(name) + { + LL_DEBUGS("Lua") << *this << LL_ENDL; + } + virtual ~InvResultSet() + { + // We want to be able to observe that the consuming script uses + // LL.setdtor() to eventually destroy each of these InvResultSets. + LL_DEBUGS("Lua") << "~" << *this << LL_ENDL; + } +}; -void add_objects_info(LLEventAPI::Response& response, LLInventoryModel::cat_array_t cat_array, LLInventoryModel::item_array_t item_array) +// This struct captures (possibly large) category results from +// getDirectDescendants() and collectDescendantsIf(). +struct CatResultSet: public InvResultSet { - for (auto &p : item_array) + CatResultSet(): InvResultSet("categories") {} + LLInventoryModel::cat_array_t mCategories; + + int getLength() const override { return narrow(mCategories.size()); } + LLSD getSingle(int index) const override { - add_item_info(response, p); + auto cat = mCategories[index]; + return llsd::map("name", cat->getName(), + "parent_id", cat->getParentUUID(), + "type", LLFolderType::lookup(cat->getPreferredType())); } - for (auto &p : cat_array) +}; + +// This struct captures (possibly large) item results from +// getDirectDescendants() and collectDescendantsIf(). +struct ItemResultSet: public InvResultSet +{ + ItemResultSet(): InvResultSet("items") {} + LLInventoryModel::item_array_t mItems; + + int getLength() const override { return narrow(mItems.size()); } + LLSD getSingle(int index) const override { - add_cat_info(response, p); + auto item = mItems[index]; + return llsd::map("name", item->getName(), + "parent_id", item->getParentUUID(), + "desc", item->getDescription(), + "inv_type", LLInventoryType::lookup(item->getInventoryType()), + "asset_type", LLAssetType::lookup(item->getType()), + "creation_date", LLSD::Integer(item->getCreationDate()), + "asset_id", item->getAssetUUID(), + "is_link", item->getIsLinkType(), + "linked_id", item->getLinkedUUID()); } -} +}; void LLInventoryListener::getItemsInfo(LLSD const &data) { Response response(LLSD(), data); + auto catresult = new CatResultSet; + auto itemresult = new ItemResultSet; + uuid_vec_t ids = LLSDParam<uuid_vec_t>(data["item_ids"]); for (auto &it : ids) { LLViewerInventoryItem* item = gInventory.getItem(it); if (item) { - add_item_info(response, item); + itemresult->mItems.push_back(item); } else { LLViewerInventoryCategory *cat = gInventory.getCategory(it); if (cat) { - add_cat_info(response, cat); + catresult->mCategories.push_back(cat); } } } + response["categories"] = catresult->getKey(); + response["items"] = itemresult->getKey(); } void LLInventoryListener::getFolderTypeNames(LLSD const &data) @@ -151,14 +264,21 @@ void LLInventoryListener::getBasicFolderID(LLSD const &data) } -void LLInventoryListener::getDirectDescendents(LLSD const &data) +void LLInventoryListener::getDirectDescendants(LLSD const &data) { Response response(LLSD(), data); LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(data["folder_id"], cats, items); - add_objects_info(response, *cats, *items); + auto catresult = new CatResultSet; + auto itemresult = new ItemResultSet; + + catresult->mCategories = *cats; + itemresult->mItems = *items; + + response["categories"] = catresult->getKey(); + response["items"] = itemresult->getKey(); } struct LLFilteredCollector : public LLInventoryCollectFunctor @@ -173,7 +293,11 @@ struct LLFilteredCollector : public LLInventoryCollectFunctor LLFilteredCollector(LLSD const &data); virtual ~LLFilteredCollector() {} virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item) override; - virtual bool exceedsLimit() override { return (mItemLimit <= mItemCount); }; + virtual bool exceedsLimit() override + { + // mItemLimit == 0 means unlimited + return (mItemLimit && mItemLimit <= mItemCount); + } protected: bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item); @@ -189,7 +313,7 @@ struct LLFilteredCollector : public LLInventoryCollectFunctor S32 mItemCount; }; -void LLInventoryListener::collectDescendentsIf(LLSD const &data) +void LLInventoryListener::collectDescendantsIf(LLSD const &data) { Response response(LLSD(), data); LLUUID folder_id(data["folder_id"].asUUID()); @@ -198,20 +322,63 @@ void LLInventoryListener::collectDescendentsIf(LLSD const &data) { return response.error(stringize("Folder ", std::quoted(data["folder_id"].asString()), " was not found")); } - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; + auto catresult = new CatResultSet; + auto itemresult = new ItemResultSet; LLFilteredCollector collector = LLFilteredCollector(data); - gInventory.collectDescendentsIf(folder_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); + // Populate results directly into the catresult and itemresult arrays. + // TODO: sprinkle count-based coroutine yields into the real + // collectDescendentsIf() method so it doesn't steal too many cycles. + gInventory.collectDescendentsIf( + folder_id, + catresult->mCategories, + itemresult->mItems, + LLInventoryModel::EXCLUDE_TRASH, + collector); + + response["categories"] = catresult->getKey(); + response["items"] = itemresult->getKey(); +} + +/*==========================================================================*| +void LLInventoryListener::getSingle(LLSD const& data) +{ + auto result = InvResultSet::getInstance(data["result"]); + sendReply(llsd::map("single", result->getSingle(data["index"])), data); +} +|*==========================================================================*/ - add_objects_info(response, cat_array, item_array); +void LLInventoryListener::getSlice(LLSD const& data) +{ + auto result = InvResultSet::getInstance(data["result"]); + int count = data.has("count")? data["count"].asInteger() : MAX_ITEM_LIMIT; + LL_DEBUGS("Lua") << *result << ".getSlice(" << data["index"].asInteger() + << ", " << count << ')' << LL_ENDL; + sendReply(llsd::map("slice", result->getSlice(data["index"], count)), data); +} + +void LLInventoryListener::closeResult(LLSD const& data) +{ + LLSD results = data["result"]; + if (results.isInteger()) + { + results = llsd::array(results); + } + for (const auto& result : llsd::inArray(results)) + { + auto ptr = InvResultSet::getInstance(result); + if (ptr) + { + delete ptr.get(); + } + } } LLFilteredCollector::LLFilteredCollector(LLSD const &data) : mType(LLAssetType::EType::AT_UNKNOWN), mLinkFilter(INCLUDE_LINKS), - mItemLimit(MAX_ITEM_LIMIT), + mItemLimit(0), mItemCount(0) { @@ -235,7 +402,7 @@ LLFilteredCollector::LLFilteredCollector(LLSD const &data) : } if (data["limit"].isInteger()) { - mItemLimit = llclamp(data["limit"].asInteger(), 1, MAX_ITEM_LIMIT); + mItemLimit = std::max(data["limit"].asInteger(), 1); } } diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h index 5cbac2ca32..a05385f2c8 100644 --- a/indra/newview/llinventorylistener.h +++ b/indra/newview/llinventorylistener.h @@ -40,8 +40,13 @@ private: void getFolderTypeNames(LLSD const &data); void getAssetTypeNames(LLSD const &data); void getBasicFolderID(LLSD const &data); - void getDirectDescendents(LLSD const &data); - void collectDescendentsIf(LLSD const &data); + void getDirectDescendants(LLSD const &data); + void collectDescendantsIf(LLSD const &data); +/*==========================================================================*| + void getSingle(LLSD const& data); +|*==========================================================================*/ + void getSlice(LLSD const& data); + void closeResult(LLSD const& data); }; #endif // LL_LLINVENTORYLISTENER_H diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index dd1b910250..0ff6b9fb37 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -1,12 +1,66 @@ local leap = require 'leap' local mapargs = require 'mapargs' +local function result(keys) + return LL.setdtor( + 'LLInventory result', + setmetatable( + -- the basic table wrapped by setmetatable just captures the int + -- result-set keys from 'keys', but with underscore prefixes + { + _categories=keys.categories, + _items=keys.items, + -- call result:close() to release result sets before garbage + -- collection or script completion + close = function(self) + leap.send('LLInventory', + {op='closeResult', + result={self._categories, self._items}}) + end + }, + -- The caller of one of our methods that returns a result set + -- isn't necessarily interested in both categories and items, so + -- don't proactively populate both. Instead, when caller references + -- either 'categories' or 'items', the __index() metamethod + -- populates that field. + { + __index = function(t, key) + -- we really don't care about references to any other field + if not table.find({'categories', 'items'}, key) then + return nil + end + -- We cleverly saved the int result set key in a field + -- with the same name but an underscore prefix. + local resultkey = t['_' .. key] + -- TODO: This only ever fetches the FIRST slice. What we + -- really want is to return a table with metamethods that + -- manage indexed access and table iteration. + -- Remember our C++ entry point uses 0-relative indexing. + local slice = leap.request( + 'LLInventory', + {op='getSlice', result=resultkey, index=0}).slice + print(`getSlice({resultkey}, 0) => {slice} ({#slice} entries)`) + -- cache this slice for future reference + t[key] = slice + return slice + end + } + ), + -- When the table-with-metatable above is destroyed, tell LLInventory + -- we're done with its result sets -- whether or not we ever fetched + -- either of them. + function(keys) + keys:close() + end + ) +end + local LLInventory = {} -- Get the items/folders info by provided IDs, -- reply will contain "items" and "categories" tables accordingly function LLInventory.getItemsInfo(item_ids) - return leap.request('LLInventory', {op = 'getItemsInfo', item_ids=item_ids}) + return result(leap.request('LLInventory', {op = 'getItemsInfo', item_ids=item_ids})) end -- Get the table of folder type names, which can be later used to get the ID of the basic folders @@ -19,30 +73,33 @@ function LLInventory.getBasicFolderID(ft_name) return leap.request('LLInventory', {op = 'getBasicFolderID', ft_name=ft_name}).id end --- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendentsIf(...) +-- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendantsIf(...) function LLInventory.getAssetTypeNames() return leap.request('LLInventory', {op = 'getAssetTypeNames'}).names end --- Get the direct descendents of the 'folder_id' provided, +-- Get the direct descendants of the 'folder_id' provided, -- reply will contain "items" and "categories" tables accordingly -function LLInventory.getDirectDescendents(folder_id) - return leap.request('LLInventory', {op = 'getDirectDescendents', folder_id=folder_id}) +function LLInventory.getDirectDescendants(folder_id) + return result(leap.request('LLInventory', {op = 'getDirectDescendants', folder_id=folder_id})) end +-- backwards compatibility +LLInventory.getDirectDescendents = LLInventory.getDirectDescendants --- Get the descendents of the 'folder_id' provided, which pass specified filters +-- Get the descendants of the 'folder_id' provided, which pass specified filters -- reply will contain "items" and "categories" tables accordingly --- LLInventory.collectDescendentsIf{ folder_id -- parent folder ID +-- LLInventory.collectDescendantsIf{ folder_id -- parent folder ID -- [, name] -- name (substring) -- [, desc] -- description (substring) -- [, type] -- asset type -- [, limit] -- item count limit in reply, maximum and default is 100 -- [, filter_links]} -- EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default) -function LLInventory.collectDescendentsIf(...) +function LLInventory.collectDescendantsIf(...) local args = mapargs('folder_id,name,desc,type,filter_links,limit', ...) - args.op = 'collectDescendentsIf' - return leap.request('LLInventory', args) + args.op = 'collectDescendantsIf' + return result(leap.request('LLInventory', args)) end - +-- backwards compatibility +LLInventory.collectDescendentsIf = LLInventory.collectDescendantsIf return LLInventory -- cgit v1.2.3 From 1101ed699a0c3c23c0bb11267d390febfdc02409 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 2 Sep 2024 16:41:09 -0400 Subject: Introduce result_view.lua, and use it in LLInventory.lua. result_view(key_length, fetch) returns a virtual view of a potentially-large C++ result set. Given the result-set key, its total length and a function fetch(key, start) => (slice, adjusted start), the read-only table returned by result_view() manages indexed access and table iteration over the entire result set, fetching a slice at a time as required. Change LLInventory to use result_view() instead of only ever fetching the first slice of a result set. TODO: This depends on the viewer's "LLInventory" listener returning the total result set length as well as the result set key. It does not yet return the length. --- indra/newview/scripts/lua/require/LLInventory.lua | 38 +++++++------- indra/newview/scripts/lua/require/result_view.lua | 62 +++++++++++++++++++++++ 2 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 indra/newview/scripts/lua/require/result_view.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index 0ff6b9fb37..ce501e75f3 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -1,12 +1,14 @@ local leap = require 'leap' local mapargs = require 'mapargs' +local result_view = require 'result_view' local function result(keys) return LL.setdtor( 'LLInventory result', setmetatable( -- the basic table wrapped by setmetatable just captures the int - -- result-set keys from 'keys', but with underscore prefixes + -- result-set {key, length} pairs from 'keys', but with underscore + -- prefixes { _categories=keys.categories, _items=keys.items, @@ -15,7 +17,7 @@ local function result(keys) close = function(self) leap.send('LLInventory', {op='closeResult', - result={self._categories, self._items}}) + result={self._categories[1], self._items[1]}}) end }, -- The caller of one of our methods that returns a result set @@ -24,25 +26,25 @@ local function result(keys) -- either 'categories' or 'items', the __index() metamethod -- populates that field. { - __index = function(t, key) + __index = function(t, field) -- we really don't care about references to any other field - if not table.find({'categories', 'items'}, key) then + if not table.find({'categories', 'items'}, field) then return nil end - -- We cleverly saved the int result set key in a field - -- with the same name but an underscore prefix. - local resultkey = t['_' .. key] - -- TODO: This only ever fetches the FIRST slice. What we - -- really want is to return a table with metamethods that - -- manage indexed access and table iteration. - -- Remember our C++ entry point uses 0-relative indexing. - local slice = leap.request( - 'LLInventory', - {op='getSlice', result=resultkey, index=0}).slice - print(`getSlice({resultkey}, 0) => {slice} ({#slice} entries)`) - -- cache this slice for future reference - t[key] = slice - return slice + local view = result_view( + -- We cleverly saved the result set {key, length} pair in + -- a field with the same name but an underscore prefix. + t['_' .. field], + function(key, start) + local fetched = leap.request( + 'LLInventory', + {op='getSlice', result=key, index=start}) + return fetched.slice, fetched.start + end + ) + -- cache that view for future reference + t[field] = view + return view end } ), diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua new file mode 100644 index 0000000000..4a58636f2f --- /dev/null +++ b/indra/newview/scripts/lua/require/result_view.lua @@ -0,0 +1,62 @@ +-- result_view(key_length, fetch) returns a table which stores only a slice +-- of a result set plus some control values, yet presents read-only virtual +-- access to the entire result set. +-- key_length: {result set key, total result set length} +-- fetch: function(key, start) that returns (slice, adjusted start) +local function result_view(key_length, fetch) + return setmetatable( + { + key=key_length[1], + length=key_length[2], + -- C++ result sets use 0-based indexing, so internally we do too + start=0, + -- start with a dummy array with length 0 + slice={} + }, + { + __len = function(this) + return this.length + end, + __index = function(this, i) + -- right away, convert to 0-relative indexing + i -= 1 + -- can we find this index within the current slice? + local reli = i - this.start + if 0 <= reli and reli < #this.slice then + return this.slice[reli] + end + -- is this index outside the overall result set? + if not (0 <= i and i < this.length) then + return nil + end + -- fetch a new slice starting at i, using provided fetch() + local start + this.slice, start = fetch(key, i) + -- It's possible that caller-provided fetch() function forgot + -- to return the adjusted start index of the new slice. In + -- Lua, 0 tests as true, so if fetch() returned (slice, 0), + -- we'll duly reset this.start to 0. + if start then + this.start = start + end + -- hopefully this slice contains the desired i + return this.slice[i - this.start] + end, + -- We purposely avoid putting any array entries (int keys) into + -- our table so that access to any int key will always call our + -- __index() metamethod. Moreover, we want any table iteration to + -- call __index(table, i) however many times; we do NOT want it to + -- retrieve key, length, start, slice. + -- So turn 'for k, v in result' into 'for k, v in ipairs(result)'. + __iter = ipairs, + -- This result set provides read-only access. + -- We do not support pushing updates to individual items back to + -- C++; for the intended use cases, that makes no sense. + __newindex = function(this, i, value) + error("result_view is a read-only data structure", 2) + end + } + ) +end + +return result_view -- cgit v1.2.3 From 6a4b9b1184c142ca1b317296fa12304bf231fc7d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 12:34:21 -0400 Subject: Add test_result_view.lua; fix minor bugs in result_view.lua. --- indra/newview/scripts/lua/require/result_view.lua | 18 ++++---- indra/newview/scripts/lua/test_result_view.lua | 55 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 indra/newview/scripts/lua/test_result_view.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua index 4a58636f2f..d53d953c24 100644 --- a/indra/newview/scripts/lua/require/result_view.lua +++ b/indra/newview/scripts/lua/require/result_view.lua @@ -23,7 +23,8 @@ local function result_view(key_length, fetch) -- can we find this index within the current slice? local reli = i - this.start if 0 <= reli and reli < #this.slice then - return this.slice[reli] + -- Lua 1-relative indexing + return this.slice[reli + 1] end -- is this index outside the overall result set? if not (0 <= i and i < this.length) then @@ -31,16 +32,17 @@ local function result_view(key_length, fetch) end -- fetch a new slice starting at i, using provided fetch() local start - this.slice, start = fetch(key, i) + this.slice, start = fetch(this.key, i) -- It's possible that caller-provided fetch() function forgot -- to return the adjusted start index of the new slice. In -- Lua, 0 tests as true, so if fetch() returned (slice, 0), - -- we'll duly reset this.start to 0. - if start then - this.start = start - end - -- hopefully this slice contains the desired i - return this.slice[i - this.start] + -- we'll duly reset this.start to 0. Otherwise, assume the + -- requested index was not adjusted: that the returned slice + -- really does start at i. + this.start = start or i + -- Hopefully this slice contains the desired i. + -- Back to 1-relative indexing. + return this.slice[i - this.start + 1] end, -- We purposely avoid putting any array entries (int keys) into -- our table so that access to any int key will always call our diff --git a/indra/newview/scripts/lua/test_result_view.lua b/indra/newview/scripts/lua/test_result_view.lua new file mode 100644 index 0000000000..304633a472 --- /dev/null +++ b/indra/newview/scripts/lua/test_result_view.lua @@ -0,0 +1,55 @@ +-- Verify the functionality of result_view. +result_view = require 'result_view' + +print('alphabet') +alphabet = "abcdefghijklmnopqrstuvwxyz" +assert(#alphabet == 26) +alphabits = string.split(alphabet, '') + +print('function slice()') +function slice(t, index, count) + return table.move(t, index, index + count - 1, 1, {}) +end + +print('verify slice()') +-- verify that slice() does what we expect +assert(table.concat(slice(alphabits, 4, 3)) == "def") +assert(table.concat(slice(alphabits, 14, 3)) == "nop") +assert(table.concat(slice(alphabits, 25, 3)) == "yz") + +print('function fetch()') +function fetch(key, index) + -- fetch function is defined to be 0-relative: fix for Lua data + -- constrain view of alphabits to slices of at most 3 elements + return slice(alphabits, index+1, 3), index +end + +print('result_view()') +-- for test purposes, key is irrelevant, so just 'key' +view = result_view({'key', #alphabits}, fetch) + +print('function check_iter()') +function check_iter(...) + result = {} + for k, v in ... do + table.insert(result, v) + end + assert(table.concat(result) == alphabet) +end + +print('check_iter(pairs(view))') +check_iter(pairs(view)) +print('check_iter(ipairs(view))') +check_iter(ipairs(view)) +print('check_iter(view)') +check_iter(view) + +print('raw index access') +assert(view[5] == 'e') +assert(view[10] == 'j') +assert(view[15] == 'o') +assert(view[20] == 't') +assert(view[25] == 'y') + +print('Success!') + -- cgit v1.2.3 From ab04d116cc47fa979018525fce4f11b379aeeec5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 12:35:55 -0400 Subject: Break out llinventorylistener.cpp's InvResultSet as LL::ResultSet. We may well want to leverage that API for additional queries that could potentially return large datasets. --- indra/newview/llinventorylistener.cpp | 111 ++++++---------------------------- 1 file changed, 19 insertions(+), 92 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index c330ef42a0..6a8182c539 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -28,13 +28,14 @@ #include "llinventorylistener.h" #include "llappearancemgr.h" -#include "llinttracker.h" #include "llinventoryfunctions.h" #include "lltransutil.h" #include "llwearableitemslist.h" +#include "resultset.h" #include "stringize.h" +#include <algorithm> // std::min() -constexpr U32 MAX_ITEM_LIMIT = 100; +constexpr S32 MAX_ITEM_LIMIT = 100; LLInventoryListener::LLInventoryListener() : LLEventAPI("LLInventory", @@ -104,87 +105,11 @@ LLInventoryListener::LLInventoryListener() llsd::map("result", LLSD())); } -// This abstract base class defines the interface for CatResultSet and -// ItemResultSet. It isa LLIntTracker so we can pass its unique int key to a -// consuming script via LLSD. -struct InvResultSet: public LLIntTracker<InvResultSet> -{ - // Get the length of the result set. Indexes are 0-relative. - virtual int getLength() const = 0; -/*==========================================================================*| - // Retrieve LLSD corresponding to a single entry from the result set, - // with index validation. - LLSD getSingle(int index) const - { - if (0 <= index && index < getLength()) - { - return getSingle_(index); - } - else - { - return {}; - } - } -|*==========================================================================*/ - // Retrieve LLSD corresponding to a single entry from the result set, - // once we're sure the index is valid. - virtual LLSD getSingle(int index) const = 0; - // Retrieve LLSD corresponding to a "slice" of the result set: a - // contiguous sub-array starting at index. The returned LLSD array might - // be shorter than count entries if count > MAX_ITEM_LIMIT, or if the - // specified slice contains the end of the result set. - LLSD getSlice(int index, int count) const - { - // only call getLength() once - auto length = getLength(); - // Adjust bounds [start, end) to overlap the actual result set from - // [0, getLength()). Permit negative index; e.g. with a result set - // containing 5 entries, getSlice(-2, 5) will adjust start to 0 and - // end to 3. - int start = llclamp(index, 0, length); - // Constrain count to MAX_ITEM_LIMIT even before clamping end. - int end = llclamp(index + llclamp(count, 0, MAX_ITEM_LIMIT), 0, length); - LLSD result{ LLSD::emptyArray() }; - // beware of count == 0, or an [index, count) range that doesn't even - // overlap [0, length) at all - if (end > start) - { - // right away expand the result array to the size we'll need - result[end - 1] = LLSD(); - for (int i = start; i < end; ++i) - { - result[i] = getSingle(i); - } - } - return result; - } - - /*---------------- the rest is solely for debug logging ----------------*/ - std::string mName; - - friend std::ostream& operator<<(std::ostream& out, const InvResultSet& self) - { - return out << "InvResultSet(" << self.mName << ", " << self.getKey() << ")"; - } - - InvResultSet(const std::string& name): - mName(name) - { - LL_DEBUGS("Lua") << *this << LL_ENDL; - } - virtual ~InvResultSet() - { - // We want to be able to observe that the consuming script uses - // LL.setdtor() to eventually destroy each of these InvResultSets. - LL_DEBUGS("Lua") << "~" << *this << LL_ENDL; - } -}; - // This struct captures (possibly large) category results from // getDirectDescendants() and collectDescendantsIf(). -struct CatResultSet: public InvResultSet +struct CatResultSet: public LL::ResultSet { - CatResultSet(): InvResultSet("categories") {} + CatResultSet(): LL::ResultSet("categories") {} LLInventoryModel::cat_array_t mCategories; int getLength() const override { return narrow(mCategories.size()); } @@ -199,9 +124,9 @@ struct CatResultSet: public InvResultSet // This struct captures (possibly large) item results from // getDirectDescendants() and collectDescendantsIf(). -struct ItemResultSet: public InvResultSet +struct ItemResultSet: public LL::ResultSet { - ItemResultSet(): InvResultSet("items") {} + ItemResultSet(): LL::ResultSet("items") {} LLInventoryModel::item_array_t mItems; int getLength() const override { return narrow(mItems.size()); } @@ -244,8 +169,9 @@ void LLInventoryListener::getItemsInfo(LLSD const &data) } } } - response["categories"] = catresult->getKey(); - response["items"] = itemresult->getKey(); + // Each of categories and items is a { result set key, total length } pair. + response["categories"] = catresult->getKeyLength(); + response["items"] = itemresult->getKeyLength(); } void LLInventoryListener::getFolderTypeNames(LLSD const &data) @@ -277,8 +203,8 @@ void LLInventoryListener::getDirectDescendants(LLSD const &data) catresult->mCategories = *cats; itemresult->mItems = *items; - response["categories"] = catresult->getKey(); - response["items"] = itemresult->getKey(); + response["categories"] = catresult->getKeyLength(); + response["items"] = itemresult->getKeyLength(); } struct LLFilteredCollector : public LLInventoryCollectFunctor @@ -337,25 +263,26 @@ void LLInventoryListener::collectDescendantsIf(LLSD const &data) LLInventoryModel::EXCLUDE_TRASH, collector); - response["categories"] = catresult->getKey(); - response["items"] = itemresult->getKey(); + response["categories"] = catresult->getKeyLength(); + response["items"] = itemresult->getKeyLength(); } /*==========================================================================*| void LLInventoryListener::getSingle(LLSD const& data) { - auto result = InvResultSet::getInstance(data["result"]); + auto result = LL::ResultSet::getInstance(data["result"]); sendReply(llsd::map("single", result->getSingle(data["index"])), data); } |*==========================================================================*/ void LLInventoryListener::getSlice(LLSD const& data) { - auto result = InvResultSet::getInstance(data["result"]); + auto result = LL::ResultSet::getInstance(data["result"]); int count = data.has("count")? data["count"].asInteger() : MAX_ITEM_LIMIT; LL_DEBUGS("Lua") << *result << ".getSlice(" << data["index"].asInteger() << ", " << count << ')' << LL_ENDL; - sendReply(llsd::map("slice", result->getSlice(data["index"], count)), data); + auto pair{ result->getSliceStart(data["index"], std::min(count, MAX_ITEM_LIMIT)) }; + sendReply(llsd::map("slice", pair.first, "start", pair.second), data); } void LLInventoryListener::closeResult(LLSD const& data) @@ -367,7 +294,7 @@ void LLInventoryListener::closeResult(LLSD const& data) } for (const auto& result : llsd::inArray(results)) { - auto ptr = InvResultSet::getInstance(result); + auto ptr = LL::ResultSet::getInstance(result); if (ptr) { delete ptr.get(); -- cgit v1.2.3 From 2157fa4fa9acf4db6093b962569274105e4d1fb4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 12:52:34 -0400 Subject: result_view() now reuses same metatable instance for every table. --- indra/newview/scripts/lua/require/result_view.lua | 97 ++++++++++++----------- 1 file changed, 51 insertions(+), 46 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua index d53d953c24..c719681c66 100644 --- a/indra/newview/scripts/lua/require/result_view.lua +++ b/indra/newview/scripts/lua/require/result_view.lua @@ -1,3 +1,50 @@ +-- metatable for every result_view() table +local mt = { + __len = function(this) + return this.length + end, + __index = function(this, i) + -- right away, convert to 0-relative indexing + i -= 1 + -- can we find this index within the current slice? + local reli = i - this.start + if 0 <= reli and reli < #this.slice then + -- Lua 1-relative indexing + return this.slice[reli + 1] + end + -- is this index outside the overall result set? + if not (0 <= i and i < this.length) then + return nil + end + -- fetch a new slice starting at i, using provided fetch() + local start + this.slice, start = this.fetch(this.key, i) + -- It's possible that caller-provided fetch() function forgot + -- to return the adjusted start index of the new slice. In + -- Lua, 0 tests as true, so if fetch() returned (slice, 0), + -- we'll duly reset this.start to 0. Otherwise, assume the + -- requested index was not adjusted: that the returned slice + -- really does start at i. + this.start = start or i + -- Hopefully this slice contains the desired i. + -- Back to 1-relative indexing. + return this.slice[i - this.start + 1] + end, + -- We purposely avoid putting any array entries (int keys) into + -- our table so that access to any int key will always call our + -- __index() metamethod. Moreover, we want any table iteration to + -- call __index(table, i) however many times; we do NOT want it to + -- retrieve key, length, start, slice. + -- So turn 'for k, v in result' into 'for k, v in ipairs(result)'. + __iter = ipairs, + -- This result set provides read-only access. + -- We do not support pushing updates to individual items back to + -- C++; for the intended use cases, that makes no sense. + __newindex = function(this, i, value) + error("result_view is a read-only data structure", 2) + end +} + -- result_view(key_length, fetch) returns a table which stores only a slice -- of a result set plus some control values, yet presents read-only virtual -- access to the entire result set. @@ -11,53 +58,11 @@ local function result_view(key_length, fetch) -- C++ result sets use 0-based indexing, so internally we do too start=0, -- start with a dummy array with length 0 - slice={} + slice={}, + fetch=fetch }, - { - __len = function(this) - return this.length - end, - __index = function(this, i) - -- right away, convert to 0-relative indexing - i -= 1 - -- can we find this index within the current slice? - local reli = i - this.start - if 0 <= reli and reli < #this.slice then - -- Lua 1-relative indexing - return this.slice[reli + 1] - end - -- is this index outside the overall result set? - if not (0 <= i and i < this.length) then - return nil - end - -- fetch a new slice starting at i, using provided fetch() - local start - this.slice, start = fetch(this.key, i) - -- It's possible that caller-provided fetch() function forgot - -- to return the adjusted start index of the new slice. In - -- Lua, 0 tests as true, so if fetch() returned (slice, 0), - -- we'll duly reset this.start to 0. Otherwise, assume the - -- requested index was not adjusted: that the returned slice - -- really does start at i. - this.start = start or i - -- Hopefully this slice contains the desired i. - -- Back to 1-relative indexing. - return this.slice[i - this.start + 1] - end, - -- We purposely avoid putting any array entries (int keys) into - -- our table so that access to any int key will always call our - -- __index() metamethod. Moreover, we want any table iteration to - -- call __index(table, i) however many times; we do NOT want it to - -- retrieve key, length, start, slice. - -- So turn 'for k, v in result' into 'for k, v in ipairs(result)'. - __iter = ipairs, - -- This result set provides read-only access. - -- We do not support pushing updates to individual items back to - -- C++; for the intended use cases, that makes no sense. - __newindex = function(this, i, value) - error("result_view is a read-only data structure", 2) - end - } + -- use our special metatable + mt ) end -- cgit v1.2.3 From 93c21b503abdf4f9530064f8c3f1df7ea0dc244f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 13:01:11 -0400 Subject: test_inv_resultset.lua exercises LLInventory's result-set functionality. --- indra/newview/scripts/lua/test_inv_resultset.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 indra/newview/scripts/lua/test_inv_resultset.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_inv_resultset.lua b/indra/newview/scripts/lua/test_inv_resultset.lua new file mode 100644 index 0000000000..c31cfe3c67 --- /dev/null +++ b/indra/newview/scripts/lua/test_inv_resultset.lua @@ -0,0 +1,18 @@ +local LLInventory = require 'LLInventory' +local inspect = require 'inspect' + +print('basic folders:') +print(inspect(LLInventory.getFolderTypeNames())) + +local folder = LLInventory.getBasicFolderID('my_otfts') +print(`folder = {folder}`) +local result = LLInventory.getDirectDescendants(folder) +print(`type(result) = {type(result)}`) +print(#result.categories, 'categories:') +for i, cat in pairs(result.categories) do + print(`{i}: {cat.name}`) +end +print(#result.items, 'items') +for i, item in pairs(result.items) do + print(`{i}: {item.name}`) +end -- cgit v1.2.3 From 83eace32cfccc672e7a5a2841bd7d844dce0ea3e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 13:13:22 -0400 Subject: Iterate to print landmarks returned by LLInventory. At this point, inspect(landmarks) just returns "<userdata 1>". --- indra/newview/scripts/lua/test_LLInventory.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_LLInventory.lua b/indra/newview/scripts/lua/test_LLInventory.lua index 107b0791d4..918ca56a2e 100644 --- a/indra/newview/scripts/lua/test_LLInventory.lua +++ b/indra/newview/scripts/lua/test_LLInventory.lua @@ -5,7 +5,9 @@ LLInventory = require 'LLInventory' my_landmarks_id = LLInventory.getBasicFolderID('landmark') -- Get 3 landmarks from the 'My Landmarks' folder (you can see all folder types via LLInventory.getAssetTypeNames()) landmarks = LLInventory.collectDescendentsIf{folder_id=my_landmarks_id, type="landmark", limit=3} -print(inspect(landmarks)) +for _, landmark in pairs(landmarks.items) do + print(landmark.name) +end -- Get 'Calling Cards' folder id calling_cards_id = LLInventory.getBasicFolderID('callcard') -- cgit v1.2.3 From f3896d37ca625a4f7060ee5139a8825c2f6e6a74 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 20:39:14 -0400 Subject: Generalize Lua-side result-set machinery for other use cases. Change `result_view()` from a simple function to a callable table so we can add conventional/default functions to it: `result_view.fetch()` is a generic `fetch()` function suitable for use with `result_view()`, and `result_view.close()` is a variadic function that closes result sets for whichever keys are passed. This arises from the fact that any `LL::ResultSet` subclass is accessed generically through its base class, therefore we don't need distinct "getSlice" and "closeResult" operations for different `LLEventAPI` listeners. (It might make sense to relocate those operations to a new generic listener, but for now "LLInventory" works.) That lets `result_view()`'s caller omit the `fetch` parameter unless it requires special behavior. Omitting it uses the generic `result_view.fetch()` function. Moreover, every view returned by `result_view()` now contains a close() function that closes that view's result set. The table returned by LLInventory.lua's `result()` function has a `close()` method; that method can now call `result_view.close()` with the two keys of interest. That table's `__index()` metamethod can now leverage `result_view()`'s default `fetch` function. --- indra/newview/scripts/lua/require/LLInventory.lua | 22 ++---- indra/newview/scripts/lua/require/result_view.lua | 83 +++++++++++++++-------- 2 files changed, 62 insertions(+), 43 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index ce501e75f3..9cf72a8678 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -15,9 +15,7 @@ local function result(keys) -- call result:close() to release result sets before garbage -- collection or script completion close = function(self) - leap.send('LLInventory', - {op='closeResult', - result={self._categories[1], self._items[1]}}) + result_view.close(self._categories[1], self._items[1]) end }, -- The caller of one of our methods that returns a result set @@ -31,17 +29,9 @@ local function result(keys) if not table.find({'categories', 'items'}, field) then return nil end - local view = result_view( - -- We cleverly saved the result set {key, length} pair in - -- a field with the same name but an underscore prefix. - t['_' .. field], - function(key, start) - local fetched = leap.request( - 'LLInventory', - {op='getSlice', result=key, index=start}) - return fetched.slice, fetched.start - end - ) + -- We cleverly saved the result set {key, length} pair in + -- a field with the same name but an underscore prefix. + local view = result_view(t['_' .. field]) -- cache that view for future reference t[field] = view return view @@ -51,8 +41,8 @@ local function result(keys) -- When the table-with-metatable above is destroyed, tell LLInventory -- we're done with its result sets -- whether or not we ever fetched -- either of them. - function(keys) - keys:close() + function(res) + res:close() end ) end diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua index c719681c66..5301d7838c 100644 --- a/indra/newview/scripts/lua/require/result_view.lua +++ b/indra/newview/scripts/lua/require/result_view.lua @@ -1,34 +1,36 @@ +local leap = require 'leap' + -- metatable for every result_view() table local mt = { - __len = function(this) - return this.length + __len = function(self) + return self.length end, - __index = function(this, i) + __index = function(self, i) -- right away, convert to 0-relative indexing i -= 1 -- can we find this index within the current slice? - local reli = i - this.start - if 0 <= reli and reli < #this.slice then + local reli = i - self.start + if 0 <= reli and reli < #self.slice then -- Lua 1-relative indexing - return this.slice[reli + 1] + return self.slice[reli + 1] end -- is this index outside the overall result set? - if not (0 <= i and i < this.length) then + if not (0 <= i and i < self.length) then return nil end -- fetch a new slice starting at i, using provided fetch() local start - this.slice, start = this.fetch(this.key, i) + self.slice, start = self.fetch(self.key, i) -- It's possible that caller-provided fetch() function forgot -- to return the adjusted start index of the new slice. In -- Lua, 0 tests as true, so if fetch() returned (slice, 0), - -- we'll duly reset this.start to 0. Otherwise, assume the + -- we'll duly reset self.start to 0. Otherwise, assume the -- requested index was not adjusted: that the returned slice -- really does start at i. - this.start = start or i + self.start = start or i -- Hopefully this slice contains the desired i. -- Back to 1-relative indexing. - return this.slice[i - this.start + 1] + return self.slice[i - self.start + 1] end, -- We purposely avoid putting any array entries (int keys) into -- our table so that access to any int key will always call our @@ -40,7 +42,7 @@ local mt = { -- This result set provides read-only access. -- We do not support pushing updates to individual items back to -- C++; for the intended use cases, that makes no sense. - __newindex = function(this, i, value) + __newindex = function(self, i, value) error("result_view is a read-only data structure", 2) end } @@ -50,20 +52,47 @@ local mt = { -- access to the entire result set. -- key_length: {result set key, total result set length} -- fetch: function(key, start) that returns (slice, adjusted start) -local function result_view(key_length, fetch) - return setmetatable( - { - key=key_length[1], - length=key_length[2], - -- C++ result sets use 0-based indexing, so internally we do too - start=0, - -- start with a dummy array with length 0 - slice={}, - fetch=fetch - }, - -- use our special metatable - mt - ) -end +local result_view = setmetatable( + { + -- generic fetch() function + fetch = function(key, start) + local fetched = leap.request( + 'LLInventory', + {op='getSlice', result=key, index=start}) + return fetched.slice, fetched.start + end, + -- generic close() function accepting variadic result-set keys + close = function(...) + local keys = table.pack(...) + -- table.pack() produces a table with an array entry for every + -- parameter, PLUS an 'n' key with the count. Unfortunately that + -- 'n' key bollixes our conversion to LLSD, which requires either + -- all int keys (for an array) or all string keys (for a map). + keys.n = nil + leap.send('LLInventory', {op='closeResult', result=keys}) + end + }, + { + -- result_view(key_length, fetch) calls this + __call = function(class, key_length, fetch) + return setmetatable( + { + key=key_length[1], + length=key_length[2], + -- C++ result sets use 0-based indexing, so internally we do too + start=0, + -- start with a dummy array with length 0 + slice={}, + -- if caller didn't pass fetch() function, use generic + fetch=fetch or class.fetch, + -- returned view:close() will close result set with passed key + close=function(self) class.close(key_length[1]) end + }, + -- use our special metatable + mt + ) + end + } +) return result_view -- cgit v1.2.3 From a8dd7135f0423384dbbb1e3b98514149c6a69e6b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 3 Sep 2024 20:50:18 -0400 Subject: Use Lua result-set logic for "LLFloaterReg"s "getFloaterNames" op. This is the query that produced so many results that, before we lifted the infinite-loop interrupt limit, inspect(result) hit the limit and terminated. --- indra/newview/scripts/lua/require/UI.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index bbcae3514a..aa64c0c7f9 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -2,6 +2,7 @@ local leap = require 'leap' local mapargs = require 'mapargs' +local result_view = require 'result_view' local Timer = (require 'timers').Timer local util = require 'util' @@ -234,7 +235,12 @@ function UI.closeAllFloaters() end function UI.getFloaterNames() - return leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters + local key_length = leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters + local view = result_view(key_length) + return LL.setdtor( + 'registered floater names', + view, + function(self) view:close() end) end return UI -- cgit v1.2.3 From 35c3f0227c334e059abdc36c36cc942a517d92ec Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 07:43:48 -0400 Subject: Instead of traversing all calling cards, pick a selected few. Make test_LLInventory.lua directly select from the calling_cards result set, instead of first copying all names to a separate array. --- indra/newview/scripts/lua/test_LLInventory.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_LLInventory.lua b/indra/newview/scripts/lua/test_LLInventory.lua index 918ca56a2e..de57484bcd 100644 --- a/indra/newview/scripts/lua/test_LLInventory.lua +++ b/indra/newview/scripts/lua/test_LLInventory.lua @@ -15,9 +15,10 @@ calling_cards_id = LLInventory.getBasicFolderID('callcard') calling_cards = LLInventory.getDirectDescendents(calling_cards_id).items -- Print a random calling card name from 'Calling Cards' folder -local card_names = {} -for _, value in pairs(calling_cards) do - table.insert(card_names, value.name) -end +-- (because getDirectDescendents().items is a Lua result set, selecting +-- a random entry only fetches one slice containing that entry) math.randomseed(os.time()) -print("Random calling card: " .. inspect(card_names[math.random(#card_names)])) +for i = 1, 5 do + pick = math.random(#calling_cards) + print(`Random calling card (#{pick} of {#calling_cards}): {calling_cards[pick].name}`) +end -- cgit v1.2.3 From d67ad5da3b5a37f7b4cb78e686ae36f31c513153 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 09:15:10 -0400 Subject: `result_view()`'s table's `close()` method need not be further wrapped. `LL.setdtor(desc, table, func)` eventually calls `func(table)`. So the `close()` method on the table returned by `result_view()` can be directly passed to `setdtor()`, instead of wrapped in a new anonymous function whose only job is to pass the table to it. Moreover, there's no need for the table returned by LLInventory.lua's `result()` function to lazily instantiate the `result_view()` for `categories` or `items`: neither `result_view` will fetch a slice unless asked. Just return `{categories=result_view(...), items=result_view(...), close=...}`. This dramatically simplifies the `result()` function. Since that table also defines a `close()` function, that too can be passed directly to `setdtor()` without being wrapped in a new anonymous function. --- indra/newview/scripts/lua/require/LLInventory.lua | 52 +++++------------------ indra/newview/scripts/lua/require/UI.lua | 5 +-- 2 files changed, 12 insertions(+), 45 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua index 9cf72a8678..2c80a8602b 100644 --- a/indra/newview/scripts/lua/require/LLInventory.lua +++ b/indra/newview/scripts/lua/require/LLInventory.lua @@ -3,48 +3,18 @@ local mapargs = require 'mapargs' local result_view = require 'result_view' local function result(keys) - return LL.setdtor( - 'LLInventory result', - setmetatable( - -- the basic table wrapped by setmetatable just captures the int - -- result-set {key, length} pairs from 'keys', but with underscore - -- prefixes - { - _categories=keys.categories, - _items=keys.items, - -- call result:close() to release result sets before garbage - -- collection or script completion - close = function(self) - result_view.close(self._categories[1], self._items[1]) - end - }, - -- The caller of one of our methods that returns a result set - -- isn't necessarily interested in both categories and items, so - -- don't proactively populate both. Instead, when caller references - -- either 'categories' or 'items', the __index() metamethod - -- populates that field. - { - __index = function(t, field) - -- we really don't care about references to any other field - if not table.find({'categories', 'items'}, field) then - return nil - end - -- We cleverly saved the result set {key, length} pair in - -- a field with the same name but an underscore prefix. - local view = result_view(t['_' .. field]) - -- cache that view for future reference - t[field] = view - return view - end - } - ), - -- When the table-with-metatable above is destroyed, tell LLInventory - -- we're done with its result sets -- whether or not we ever fetched - -- either of them. - function(res) - res:close() + -- capture result_view() instances for both categories and items + local result_table = { + categories=result_view(keys.categories), + items=result_view(keys.items), + -- call result_table:close() to release result sets before garbage + -- collection or script completion + close = function(self) + result_view.close(keys.categories[1], keys.items[1]) end - ) + } + -- When the result_table is destroyed, close its result_views. + return LL.setdtor('LLInventory result', result_table, result_table.close) end local LLInventory = {} diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index aa64c0c7f9..73a76fa6b8 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -237,10 +237,7 @@ end function UI.getFloaterNames() local key_length = leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters local view = result_view(key_length) - return LL.setdtor( - 'registered floater names', - view, - function(self) view:close() end) + return LL.setdtor('registered floater names', view, view.close) end return UI -- cgit v1.2.3 From a6b85244a6f943a4598ff9b7b8a3343eb1e0d11e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 10:26:40 -0400 Subject: Fix test: new traceback info changed error message. --- indra/newview/tests/llluamanager_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 3209d93d39..c2abd27f96 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -463,8 +463,8 @@ namespace tut // but now we have to give the startScriptLine() coroutine a chance to run auto [count, result] = future.get(); ensure_equals("killed Lua script terminated normally", count, -1); - ensure_equals("unexpected killed Lua script error", - result.asString(), "viewer is stopping"); + ensure_contains("unexpected killed Lua script error", + result.asString(), "viewer is stopping"); } template<> template<> -- cgit v1.2.3 From c4f29a535359fe1ecdb8bec45596f40b02891cd1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 14:17:32 -0400 Subject: Resolve a few unresolved merge conflicts. --- indra/newview/llmediadataclient.h | 6 ------ indra/newview/llpanelpeople.cpp | 12 ------------ 2 files changed, 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 736f4d8537..a5e6e43e3f 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -286,13 +286,7 @@ private: { public: QueueTimer(F32 time, LLMediaDataClient *mdc); -<<<<<<< variant A bool tick() override; ->>>>>>> variant B - virtual bool tick(); -####### Ancestor - virtual BOOL tick(); -======= end private: // back-pointer LLPointer<LLMediaDataClient> mMDC; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index ea4a5bfdf1..fb96718d1c 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -364,13 +364,7 @@ public: } -<<<<<<< variant A bool tick() override ->>>>>>> variant B - /*virtual*/ bool tick() -####### Ancestor - /*virtual*/ BOOL tick() -======= end { if (!mIsActive) return false; @@ -510,13 +504,7 @@ public: } } -<<<<<<< variant A bool tick() override ->>>>>>> variant B - /*virtual*/ bool tick() -####### Ancestor - /*virtual*/ BOOL tick() -======= end { update(); return false; -- cgit v1.2.3 From d5fa10180344d419d5d9a9fe580044f28aa64e43 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 14:19:29 -0400 Subject: Adapt new code from main branch to Lua project calling convention. --- indra/newview/llpanelnearbymedia.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index de59feab8e..86a88d6793 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -103,10 +103,10 @@ LLPanelNearByMedia::LLPanelNearByMedia() // Context menu handler. mCommitCallbackRegistrar.add("SelectedMediaCtrl.Action", - [this](LLUICtrl* ctrl, const LLSD& data) + {[this](LLUICtrl* ctrl, const LLSD& data) { onMenuAction(data); - }); + }}); mEnableCallbackRegistrar.add("SelectedMediaCtrl.Visible", [this](LLUICtrl* ctrl, const LLSD& data) { -- cgit v1.2.3 From a980a8f30870d35a5a45cbf52169f7bf35cf95ce Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 14:23:31 -0400 Subject: Swat a few more buzzing BOOLs. --- indra/newview/llfloaterluadebug.cpp | 2 +- indra/newview/llfloaterluadebug.h | 2 +- indra/newview/llfloaterluascripts.cpp | 2 +- indra/newview/llfloaterluascripts.h | 2 +- indra/newview/lltoolplacer.cpp | 2 +- indra/newview/lltoolplacer.h | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index ef24481464..2d0f8949e5 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -49,7 +49,7 @@ LLFloaterLUADebug::LLFloaterLUADebug(const LLSD &key) } -BOOL LLFloaterLUADebug::postBuild() +bool LLFloaterLUADebug::postBuild() { mResultOutput = getChild<LLTextEditor>("result_text"); mLineInput = getChild<LLLineEditor>("lua_cmd"); diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h index 9f044df9d9..e27c63b74d 100644 --- a/indra/newview/llfloaterluadebug.h +++ b/indra/newview/llfloaterluadebug.h @@ -48,7 +48,7 @@ class LLFloaterLUADebug : LLFloaterLUADebug(const LLSD& key); virtual ~LLFloaterLUADebug(); - /*virtual*/ BOOL postBuild(); + /*virtual*/ bool postBuild(); void onExecuteClicked(); void onBtnBrowse(); diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 60cdadfbee..79623cdefb 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -60,7 +60,7 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) } -BOOL LLFloaterLUAScripts::postBuild() +bool LLFloaterLUAScripts::postBuild() { mScriptList = getChild<LLScrollListCtrl>("scripts_list"); mScriptList->setRightMouseDownCallback([this](LLUICtrl *ctrl, S32 x, S32 y, MASK mask) { onScrollListRightClicked(ctrl, x, y);}); diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h index 24d3f00a80..14ca42d6fb 100644 --- a/indra/newview/llfloaterluascripts.h +++ b/indra/newview/llfloaterluascripts.h @@ -37,7 +37,7 @@ class LLFloaterLUAScripts : LLFloaterLUAScripts(const LLSD &key); virtual ~LLFloaterLUAScripts(); - BOOL postBuild(); + bool postBuild(); void draw(); private: diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 63846bf5b7..2ac5d6b6b1 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -172,7 +172,7 @@ bool LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) return rezNewObject(pcode,hit_obj, hit_face, b_hit_land, ray_start_region, ray_end_region, regionp, use_physics); } -BOOL LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, +bool LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, bool b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion* regionp, U8 use_physics) { if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index 421a2f25f7..92446c319b 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -50,8 +50,8 @@ public: static void setObjectType( LLPCode type ) { sObjectType = type; } static LLPCode getObjectType() { return sObjectType; } - static BOOL addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics); - static BOOL rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, +// static bool addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics); + static bool rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, bool b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion *regionp, U8 use_physics); protected: -- cgit v1.2.3 From 12283fd8f700bd713a2d9eb5e1918fbcf41450cd Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:58:27 +0200 Subject: Merge fixes (#2499) --- indra/newview/llappviewerlinux.cpp | 19 ++++++++++--------- indra/newview/llconversationloglist.cpp | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 2f366f0538..38f2f1ae7f 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -68,8 +68,7 @@ extern "C" #include "breakpad/common/linux/http_upload.h" #include "lldir.h" #include "../llcrashlogger/llcrashlogger.h" -#include "jsoncpp/reader.h" // JSON - +#include "boost/json.hpp" #endif #define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" @@ -181,26 +180,28 @@ void setupBreadpad() return; } - Json::Reader reader; - Json::Value build_data; - if(!reader.parse(inf, build_data, false)) + boost::json::error_code ec; + boost::json::value build_data = boost::json::parse(inf, ec); + if(ec.failed()) { LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " - << reader.getFormatedErrorMessages() << LL_ENDL; + << ec.what() << LL_ENDL; return; } - Json::Value BugSplat_DB = build_data["BugSplat DB"]; - if(!BugSplat_DB) + if (!build_data.is_object() || !build_data.as_object().contains("BugSplat DB")) { LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname << "'" << LL_ENDL; return; } + gVersion = STRINGIZE( LL_VIEWER_VERSION_MAJOR << '.' << LL_VIEWER_VERSION_MINOR << '.' << LL_VIEWER_VERSION_PATCH << '.' << LL_VIEWER_VERSION_BUILD); - gBugsplatDB = BugSplat_DB.asString(); + + boost::json::value BugSplat_DB = build_data.at("BugSplat DB"); + gBugsplatDB = boost::json::value_to<std::string>(BugSplat_DB); LL_INFOS("BUGSPLAT") << "Initializing with crash logger: " << gCrashLogger << " database: " << gBugsplatDB << " version: " << gVersion << LL_ENDL; diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 3e08c6ee60..58c05af4db 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -94,8 +94,7 @@ bool LLConversationLogList::handleRightMouseDown(S32 x, S32 y, MASK mask) if (context_menu && size()) { context_menu->buildDrawLabels(); - if (context_menu && size()) - context_menu->updateParent(LLMenuGL::sMenuContainer); + context_menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, context_menu, x, y); } -- cgit v1.2.3 From 5319d314206c7c1c21b2bbd3a661c0c520373dcc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 16:24:42 -0400 Subject: Windows build fixes --- indra/newview/llfloatersettingsdebug.cpp | 2 +- indra/newview/tests/llluamanager_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 9c87e6fb3b..63ae1e60e8 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -660,5 +660,5 @@ void LLFloaterSettingsDebug::hideUIControls() void LLFloaterSettingsDebug::onClickCopy() { std::string setting_name = mSettingName->getText(); - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(setting_name), 0, setting_name.size()); + LLClipboard::instance().copyToClipboard(utf8str_to_wstring(setting_name), 0, narrow(setting_name.size())); } diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 4b143b52db..8ce5c357e0 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -287,7 +287,7 @@ namespace tut while (expect_array.size() > 0 && send_array[expect_array.size() - 1].isUndefined()) { - expect_array.erase(expect_array.size() - 1); + expect_array.erase(LLSD::Integer(expect_array.size() - 1)); } round_trip("array", send_array, expect_array); -- cgit v1.2.3 From 6a747e1ce027700a3609f4c377179bfa29c3ce31 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 4 Sep 2024 16:29:09 -0400 Subject: Insidious trailing whitespace --- indra/newview/llagentlistener.cpp | 2 +- indra/newview/llagentlistener.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 2ff4adcf5e..10810b569f 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -162,7 +162,7 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("removeCameraParams", "Reset Follow camera params", &LLAgentListener::removeFollowCamParams); - + add("playAnimation", "Play [\"item_id\"] animation locally (by default) or [\"inworld\"] (when set to true)", &LLAgentListener::playAnimation, diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index c77d1b3fc9..2765bb5b66 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -61,7 +61,7 @@ private: void setFollowCamParams(LLSD const & event_data) const; void setFollowCamActive(LLSD const & event_data) const; void removeFollowCamParams(LLSD const & event_data) const; - + void playAnimation(LLSD const &event_data); void playAnimation_(const LLUUID& asset_id, const bool inworld); void stopAnimation(LLSD const &event_data); -- cgit v1.2.3 From 953f7c9c1da4b83cabbf91f281445c3704a2f229 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 5 Sep 2024 12:33:47 -0400 Subject: Fix build errors from merging develop into release/luau-scripting. --- indra/newview/llfloatergltfasseteditor.cpp | 4 ++-- indra/newview/llfloatersettingscolor.cpp | 4 ++-- indra/newview/llfloatersettingsdebug.cpp | 3 +-- indra/newview/lluilistener.cpp | 5 +++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp index d2cf24f1dd..f28c01d713 100644 --- a/indra/newview/llfloatergltfasseteditor.cpp +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -46,8 +46,8 @@ LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key) { setTitle("GLTF Asset Editor (WIP)"); - mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); }); - mEnableCallbackRegistrar.add("PanelObject.menuEnable", [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); }); + mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", { [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); }}); + mEnableCallbackRegistrar.add("PanelObject.menuEnable", { [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); }}); } LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor() diff --git a/indra/newview/llfloatersettingscolor.cpp b/indra/newview/llfloatersettingscolor.cpp index d9c382a1dc..1ca2412907 100644 --- a/indra/newview/llfloatersettingscolor.cpp +++ b/indra/newview/llfloatersettingscolor.cpp @@ -43,8 +43,8 @@ LLFloaterSettingsColor::LLFloaterSettingsColor(const LLSD& key) : LLFloater(key), mSettingList(NULL) { - mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsColor::onCommitSettings, this)); - mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsColor::onClickDefault, this)); + mCommitCallbackRegistrar.add("CommitSettings", { boost::bind(&LLFloaterSettingsColor::onCommitSettings, this) }); + mCommitCallbackRegistrar.add("ClickDefault", { boost::bind(&LLFloaterSettingsColor::onClickDefault, this) }); } LLFloaterSettingsColor::~LLFloaterSettingsColor() diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 4a053a99de..0a01fff36d 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -66,7 +66,6 @@ bool LLFloaterSettingsDebug::postBuild() mSettingNameText = getChild<LLTextBox>("setting_name_txt"); mComment = getChild<LLTextEditor>("comment_text"); - mSettingName = getChild<LLTextBox>("setting_name_txt"); mLLSDVal = getChild<LLTextEditor>("llsd_text"); mCopyBtn = getChild<LLButton>("copy_btn"); @@ -658,6 +657,6 @@ void LLFloaterSettingsDebug::hideUIControls() void LLFloaterSettingsDebug::onClickCopy() { - std::string setting_name = mSettingName->getText(); + std::string setting_name = mSettingNameText->getText(); LLClipboard::instance().copyToClipboard(utf8str_to_wstring(setting_name), 0, narrow(setting_name.size())); } diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 6f567e67f8..c389d04443 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -255,10 +255,11 @@ LLMenuGL::Params get_params(const LLSD&event) LLMenuGL* get_parent_menu(LLEventAPI::Response& response, const LLSD&event) { - LLMenuGL* parent_menu = gMenuBarView->findChildMenuByName(event["parent_menu"], true); + auto parent_menu_name{ event["parent_menu"].asString() }; + LLMenuGL* parent_menu = gMenuBarView->findChildMenuByName(parent_menu_name, true); if(!parent_menu) { - response.error(stringize("Parent menu ", std::quoted(event["parent_menu"].asString()), " was not found")); + response.error(stringize("Parent menu ", std::quoted(parent_menu_name), " was not found")); } return parent_menu; } -- cgit v1.2.3 From 25a86618002a397d1d8dabf2ec1f093489b2f816 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 5 Sep 2024 13:41:41 -0400 Subject: Fix Windows build errors from develop => release/luau-scripting. --- indra/newview/llinventorylistener.cpp | 2 +- indra/newview/llluamanager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp index 9263663997..753ad3ddeb 100644 --- a/indra/newview/llinventorylistener.cpp +++ b/indra/newview/llinventorylistener.cpp @@ -33,7 +33,7 @@ #include "llwearableitemslist.h" #include "stringize.h" -static const F32 MAX_ITEM_LIMIT = 100; +constexpr S32 MAX_ITEM_LIMIT = 100; LLInventoryListener::LLInventoryListener() : LLEventAPI("LLInventory", diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 91a34345be..6a725e785f 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -56,9 +56,9 @@ std::map<std::string, std::string> LLLUAmanager::sScriptNames; lua_function(sleep, "sleep(seconds): pause the running coroutine") { lua_checkdelta(L, -1); - F32 seconds = lua_tonumber(L, -1); + lua_Number seconds = lua_tonumber(L, -1); lua_pop(L, 1); - llcoro::suspendUntilTimeout(seconds); + llcoro::suspendUntilTimeout(narrow(seconds)); LuaState::getParent(L).set_interrupts_counter(0); return 0; }; -- cgit v1.2.3 From 89992713218dba9f1a15973decad897127e90545 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 5 Sep 2024 17:31:14 -0400 Subject: Fix typo in cppfeatures_test.cpp --- indra/newview/tests/cppfeatures_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp index f5ea3a522b..ca94dcfc95 100644 --- a/indra/newview/tests/cppfeatures_test.cpp +++ b/indra/newview/tests/cppfeatures_test.cpp @@ -283,7 +283,7 @@ void cpp_features_test_object_t::test<8>() ensure("init member inline 1", ii.mFoo==10); InitInlineWithConstructor iici; - ensure("init member inline 2", iici.mFoo=10); + ensure("init member inline 2", iici.mFoo==10); ensure("init member inline 3", iici.mBar==25); } -- cgit v1.2.3 From 2841ca7229e076f9ddd1b2ec2e77099bab7753d9 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Fri, 6 Sep 2024 00:11:01 +0200 Subject: Fix remaining occurrences of fake BOOL --- indra/newview/llfloaterluadebug.cpp | 2 +- indra/newview/llfloaterluascripts.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index dc989fe15d..06877df816 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -69,7 +69,7 @@ bool LLFloaterLUADebug::postBuild() mLineInput->setCommitCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); mLineInput->setSelectAllonCommit(false); - return TRUE; + return true; } LLFloaterLUADebug::~LLFloaterLUADebug() diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 79623cdefb..0eba45ec29 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -72,7 +72,7 @@ bool LLFloaterLUAScripts::postBuild() mContextMenuHandle = menu->getHandle(); } - return TRUE; + return true; } LLFloaterLUAScripts::~LLFloaterLUAScripts() -- cgit v1.2.3 From 13ec4bccb534ef55a773004bd3c5a5ac9027600b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 6 Sep 2024 15:06:54 -0400 Subject: Add pos to 'UI' listener's 'addMenuItem' and 'addMenuSeparator' 'pos' is a 0-relative index at which to insert the desired menu item or separator. If 'pos' is omitted, the item is appended to the menu. --- indra/newview/lluilistener.cpp | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index c389d04443..44eb8461f1 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -90,12 +90,14 @@ LLUIListener::LLUIListener(): add("addMenuItem", "Add new menu item [\"name\"] with displayed [\"label\"]\n" "and call-on-click UI function [\"func\"] with optional [\"param\"]\n" - "to the [\"parent_menu\"] within the Top menu.", + "to the [\"parent_menu\"] within the Top menu.\n" + "If [\"pos\"] is present, insert at specified 0-relative position.", &LLUIListener::addMenuItem, required_args.with("func", LLSD())); add("addMenuSeparator", - "Add menu separator to the [\"parent_menu\"] within the Top menu.", + "Add menu separator to the [\"parent_menu\"] within the Top menu.\n" + "If [\"pos\"] is present, insert at specified 0-relative position.", &LLUIListener::addMenuSeparator, llsd::map("parent_menu", LLSD(), "reply", LLSD())); @@ -264,6 +266,13 @@ LLMenuGL* get_parent_menu(LLEventAPI::Response& response, const LLSD&event) return parent_menu; } +// Return event["pos"].asInteger() if passed, but clamp (0 <= pos <= size). +// Reserve -1 return to mean event has no "pos" key. +S32 get_pos(const LLSD& event, U32 size) +{ + return event["pos"].isInteger()? llclamp(event["pos"].asInteger(), 0, size) : -1; +} + void LLUIListener::addMenu(const LLSD&event) const { Response response(LLSD(), event); @@ -302,9 +311,19 @@ void LLUIListener::addMenuItem(const LLSD&event) const item_params.on_click = item_func; if(LLMenuGL* parent_menu = get_parent_menu(response, event)) { - if(!parent_menu->append(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params))) + auto item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + // Clamp pos to getItemCount(), meaning append. If pos exceeds that, + // insert() will silently ignore the request. + auto pos = get_pos(event, parent_menu->getItemCount()); + if (pos >= 0) { - response.error(stringize("Menu item ", std::quoted(event["name"].asString()), " was not added")); + // insert() returns void: we just have to assume it worked. + parent_menu->insert(pos, item); + } + else if (! parent_menu->append(item)) + { + response.error(stringize("Menu item ", std::quoted(event["name"].asString()), + " was not added")); } } } @@ -314,7 +333,19 @@ void LLUIListener::addMenuSeparator(const LLSD&event) const Response response(LLSD(), event); if(LLMenuGL* parent_menu = get_parent_menu(response, event)) { - if(!parent_menu->addSeparator()) + // Clamp pos to getItemCount(), meaning append. If pos exceeds that, + // insert() will silently ignore the request. + auto pos = get_pos(event, parent_menu->getItemCount()); + if (pos >= 0) + { + // Even though addSeparator() does not accept a position, + // LLMenuItemSeparatorGL isa LLMenuItemGL, so we can use insert(). + LLMenuItemSeparatorGL::Params p; + LLMenuItemGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(p); + // insert() returns void: we just have to assume it worked. + parent_menu->insert(pos, separator); + } + else if (! parent_menu->addSeparator()) { response.error("Separator was not added"); } -- cgit v1.2.3 From 782a898efadadf2747cc3310749f34a8dde8dd60 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 6 Sep 2024 15:11:15 -0400 Subject: Introduce LuaFeature debug setting, default off. Make central Lua engine functionality conditional on that flag. --- indra/newview/app_settings/settings.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 248992fd07..c6946d1ec1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3999,6 +3999,17 @@ <string>scripts/lua</string> </array> </map> + <key>LuaFeature</key> + <map> + <key>Comment</key> + <string>Enable viewer's Lua script engine.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>LuaRequirePath</key> <map> <key>Comment</key> -- cgit v1.2.3 From 8c68abb2f63d54aeb4614c63a109b838ed8d0656 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 6 Sep 2024 15:14:59 -0400 Subject: Remove Lua floaters from menu_viewer.xml; re-add if Lua enabled. Add a menus.lua autorun script that waits until login, then adds the Lua floaters back into the Develop->Consoles menu where they were originally. Extend UI.addMenuItem() and addMenuSeparator() to support pos argument. --- indra/newview/scripts/lua/auto/menus.lua | 51 ++++++++++++++++++++++ indra/newview/scripts/lua/require/UI.lua | 4 +- indra/newview/skins/default/xui/en/menu_viewer.xml | 21 --------- 3 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 indra/newview/scripts/lua/auto/menus.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/auto/menus.lua b/indra/newview/scripts/lua/auto/menus.lua new file mode 100644 index 0000000000..b2f54d83df --- /dev/null +++ b/indra/newview/scripts/lua/auto/menus.lua @@ -0,0 +1,51 @@ +-- Inject Lua-related menus into the top menu structure. Run this as a Lua +-- script so that turning off the Lua feature also disables these menus. + +-- Under Develop -> Consoles, want to present the equivalent of: +-- <menu_item_separator/> +-- <menu_item_check +-- label="LUA Debug Console" +-- name="LUA Debug Console"> +-- <menu_item_check.on_check +-- function="Floater.Visible" +-- parameter="lua_debug" /> +-- <menu_item_check.on_click +-- function="Floater.Toggle" +-- parameter="lua_debug" /> +-- </menu_item_check> +-- <menu_item_check +-- label="LUA Scripts Info" +-- name="LUA Scripts"> +-- <menu_item_check.on_check +-- function="Floater.Visible" +-- parameter="lua_scripts" /> +-- <menu_item_check.on_click +-- function="Floater.Toggle" +-- parameter="lua_scripts" /> +-- </menu_item_check> + +local startup = require 'startup' +local UI = require 'UI' + +-- Don't mess with the viewer's menu structure until we've logged in. +startup.wait('STATE_STARTED') + +-- Add LUA Debug Console to Develop->Consoles +local pos = 9 +UI.addMenuSeparator{ + parent_menu='Consoles', pos=pos, +} +pos += 1 +UI.addMenuItem{ + parent_menu='Consoles', pos=pos, + name='lua_debug', label='LUA Debug Console', + func='Floater.ToggleOrBringToFront', param='lua_debug', +} +pos += 1 + +-- Add LUA Scripts Info to Develop->Consoles +UI.addMenuItem{ + parent_menu='Consoles', pos=pos, + name='lua_scripts', label='LUA Scripts Info', + func='Floater.ToggleOrBringToFront', param='lua_scripts', +} diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua index 73a76fa6b8..cf2695917e 100644 --- a/indra/newview/scripts/lua/require/UI.lua +++ b/indra/newview/scripts/lua/require/UI.lua @@ -170,13 +170,13 @@ end -- see UI.callables() for valid values of 'func' function UI.addMenuItem(...) - local args = mapargs('name,label,parent_menu,func,param', ...) + local args = mapargs('name,label,parent_menu,func,param,pos', ...) args.op = 'addMenuItem' return leap.request('UI', args) end function UI.addMenuSeparator(...) - local args = mapargs('parent_menu', ...) + local args = mapargs('parent_menu,pos', ...) args.op = 'addMenuSeparator' return leap.request('UI', args) end diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8999797049..7fe9d0efe5 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2565,27 +2565,6 @@ function="World.EnvPreset" parameter="scene monitor" /> </menu_item_check> <menu_item_separator/> - <menu_item_check - label="LUA Debug Console" - name="LUA Debug Console"> - <menu_item_check.on_check - function="Floater.Visible" - parameter="lua_debug" /> - <menu_item_check.on_click - function="Floater.Toggle" - parameter="lua_debug" /> - </menu_item_check> - <menu_item_check - label="LUA Scripts Info" - name="LUA Scripts"> - <menu_item_check.on_check - function="Floater.Visible" - parameter="lua_scripts" /> - <menu_item_check.on_click - function="Floater.Toggle" - parameter="lua_scripts" /> - </menu_item_check> - <menu_item_separator/> <menu_item_call label="Region Info to Debug Console" -- cgit v1.2.3 From b8678d8fa3521f4496ddc569de391633711e46cb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 10 Sep 2024 09:56:36 -0400 Subject: Fix a couple errors from merging in new code. --- indra/newview/llviewermenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a5d199d9d7..3b45dd71a7 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9768,8 +9768,8 @@ void initialize_menus() registrar.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2), cb_info::UNTRUSTED_BLOCK); enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); - commit.add("Agent.ToggleHearMediaSoundFromAvatar", boost::bind(&LLAgent::toggleHearMediaSoundFromAvatar)); - commit.add("Agent.ToggleHearVoiceFromAvatar", boost::bind(&LLAgent::toggleHearVoiceFromAvatar)); + registrar.add("Agent.ToggleHearMediaSoundFromAvatar", boost::bind(&LLAgent::toggleHearMediaSoundFromAvatar), cb_info::UNTRUSTED_BLOCK); + registrar.add("Agent.ToggleHearVoiceFromAvatar", boost::bind(&LLAgent::toggleHearVoiceFromAvatar), cb_info::UNTRUSTED_BLOCK); // File menu init_menu_file(); -- cgit v1.2.3 From 26efc7e376ef52284a6281f36cf45eb03bc13507 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 10 Sep 2024 15:25:07 -0400 Subject: Pass std::string_view by value, not by const reference. Consensus seems to be that (a) string_view is, in effect, already a reference, (b) it's small enough to make pass-by-value reasonable and (c) the optimizer can reason about values way better than it can about references. --- indra/newview/llluamanager.cpp | 2 +- indra/newview/tests/llluamanager_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 6a725e785f..0bd21516bc 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -65,7 +65,7 @@ lua_function(sleep, "sleep(seconds): pause the running coroutine") // This function consumes ALL Lua stack arguments and returns concatenated // message string -std::string lua_print_msg(lua_State* L, const std::string_view& level) +std::string lua_print_msg(lua_State* L, std::string_view level) { // On top of existing Lua arguments, we're going to push tostring() and // duplicate each existing stack entry so we can stringize each one. diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 8d1333815b..f0a1b32eed 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -123,7 +123,7 @@ namespace tut } } - void from_lua(const std::string& desc, const std::string_view& construct, const LLSD& expect) + void from_lua(const std::string& desc, std::string_view construct, const LLSD& expect) { LLSD fromlua; LLStreamListener pump("testpump", -- cgit v1.2.3 From dca6f0deae49d133f180ef937939b8648649fbc6 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 10 Sep 2024 17:16:14 -0400 Subject: Fix risky signature of `wchar_to_utf8chars()`. Add `ll_convert()` alias. `wchar_to_utf8chars()` used to require a `char*` output buffer with no length, assuming that its caller knew enough to provide a buffer of sufficient length. In fact a `char[8]` buffer suffices, but nothing in the header indicated that. Eliminate the output parameter and return `std::string`. Fix the few existing callers. Also set an `ll_convert_alias` so that `ll_convert_to<std::string>(llwchar)` directly calls `wchar_to_utf8chars()`. Replace instances of the workaround `wstring_to_utf8str(LLWString(1, llwchar))`. --- indra/newview/llpanelemojicomplete.cpp | 3 +-- indra/newview/llviewermedia.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp index cb89a5910e..7f72677e34 100644 --- a/indra/newview/llpanelemojicomplete.cpp +++ b/indra/newview/llpanelemojicomplete.cpp @@ -280,8 +280,7 @@ void LLPanelEmojiComplete::onCommit() { if (mCurSelected < mTotalEmojis) { - LLSD value(wstring_to_utf8str(LLWString(1, mEmojis[mCurSelected].Character))); - setValue(value); + setValue(ll_convert_to<std::string>(mEmojis[mCurSelected].Character)); LLUICtrl::onCommit(); } } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9739cac311..1c8f1a32b9 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2766,7 +2766,8 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(false), native_key_data); + mMediaSource->textInput(ll_convert_to<std::string>(uni_char), + gKeyboard->currentMask(false), native_key_data); } } -- cgit v1.2.3 From d5712689d36a1ee1af32242706901fde7229b08d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 11 Sep 2024 12:29:18 -0400 Subject: Make Develop->Render Tests->Frame Profile dump JSON to a file too. Make `LLGLSLShader::finishProfile()` accept a string pathname instead of a bool and, in addition to logging statistics to the viewer log, output statistics to that file as JSON. The calls that used to pass `emit_report=false` now pass `report_name=std::string()`. Make llviewerdisplay.cpp's `display()` function synthesize a profile filename in the viewer's logs directory, and pass that filename to `LLGLSLShader::finishProfile()`. --- indra/newview/llfeaturemanager.cpp | 2 +- indra/newview/llglsandbox.cpp | 2 +- indra/newview/llviewerdisplay.cpp | 102 ++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 27 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index aa04221f4b..dded4d1e92 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -393,7 +393,7 @@ F32 logExceptionBenchmark() __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) { // HACK - ensure that profiling is disabled - LLGLSLShader::finishProfile(false); + LLGLSLShader::finishProfile(); // convert to C++ styled exception char integer_string[32]; diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 930a8c28d9..c932312135 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -923,7 +923,7 @@ struct ShaderProfileHelper } ~ShaderProfileHelper() { - LLGLSLShader::finishProfile(false); + LLGLSLShader::finishProfile(); } }; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 9bd0973cc0..c62702e820 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -28,58 +28,69 @@ #include "llviewerdisplay.h" -#include "llgl.h" -#include "llrender.h" -#include "llglheaders.h" -#include "llgltfmateriallist.h" +#include "fsyspath.h" +#include "hexdump.h" #include "llagent.h" #include "llagentcamera.h" -#include "llviewercontrol.h" +#include "llappviewer.h" #include "llcoord.h" #include "llcriticaldamp.h" +#include "llcubemap.h" #include "lldir.h" -#include "lldynamictexture.h" #include "lldrawpoolalpha.h" +#include "lldrawpoolbump.h" +#include "lldrawpoolwater.h" +#include "lldynamictexture.h" +#include "llenvironment.h" +#include "llfasttimer.h" #include "llfeaturemanager.h" -//#include "llfirstuse.h" +#include "llfloatertools.h" +#include "llfocusmgr.h" +#include "llgl.h" +#include "llglheaders.h" +#include "llgltfmateriallist.h" #include "llhudmanager.h" #include "llimagepng.h" +#include "llmachineid.h" #include "llmemory.h" +#include "llparcel.h" +#include "llperfstats.h" +#include "llpostprocess.h" +#include "llrender.h" +#include "llscenemonitor.h" #include "llselectmgr.h" #include "llsky.h" +#include "llspatialpartition.h" #include "llstartup.h" +#include "llstartup.h" +#include "lltooldraganddrop.h" #include "lltoolfocus.h" #include "lltoolmgr.h" -#include "lltooldraganddrop.h" #include "lltoolpie.h" #include "lltracker.h" #include "lltrans.h" #include "llui.h" +#include "lluuid.h" +#include "llversioninfo.h" #include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewernetwork.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llvograss.h" #include "llworld.h" #include "pipeline.h" -#include "llspatialpartition.h" -#include "llappviewer.h" -#include "llstartup.h" -#include "llviewershadermgr.h" -#include "llfasttimer.h" -#include "llfloatertools.h" -#include "llviewertexturelist.h" -#include "llfocusmgr.h" -#include "llcubemap.h" -#include "llviewerregion.h" -#include "lldrawpoolwater.h" -#include "lldrawpoolbump.h" -#include "llpostprocess.h" -#include "llscenemonitor.h" -#include "llenvironment.h" -#include "llperfstats.h" +#include <boost/json.hpp> + +#include <filesystem> +#include <iomanip> +#include <sstream> extern LLPointer<LLViewerTexture> gStartTexture; extern bool gShiftFrame; @@ -123,6 +134,8 @@ void render_ui_3d(); void render_ui_2d(); void render_disconnected_background(); +std::string getProfileStatsFilename(); + void display_startup() { if ( !gViewerWindow @@ -1023,10 +1036,49 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) if (gShaderProfileFrame) { gShaderProfileFrame = false; - LLGLSLShader::finishProfile(); + LLGLSLShader::finishProfile(getProfileStatsFilename()); } } +std::string getProfileStatsFilename() +{ + std::ostringstream basebuff; + // viewer build + basebuff << "profile.v" << LLVersionInfo::instance().getBuild(); + // machine ID: zero-initialize unique_id in case LLMachineID fails + unsigned char unique_id[MAC_ADDRESS_BYTES]{}; + LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); + basebuff << ".m" << LL::hexdump(unique_id, sizeof(unique_id)); + // region ID + LLViewerRegion *region = gAgent.getRegion(); + basebuff << ".r" << (region? region->getRegionID() : LLUUID()); + // local parcel ID + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + basebuff << ".p" << (parcel? parcel->getLocalID() : 0); + // date/time -- omit seconds for now + auto now = LLDate::now(); + basebuff << ".t" << LLDate::now().toHTTPDateString("%Y-%m-%dT%H-%M-"); + // put this candidate file in our logs directory + auto base = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, basebuff.str()); + S32 sec; + now.split(nullptr, nullptr, nullptr, nullptr, nullptr, &sec); + // Loop over finished filename, incrementing sec until we find one that + // doesn't yet exist. Should rarely loop (only if successive calls within + // same second), may produce (e.g.) sec==61, but avoids collisions and + // preserves chronological filename sort order. + std::string name; + std::error_code ec; + do + { + // base + missing 2-digit seconds, append ".json" + // post-increment sec in case we have to try again + name = stringize(base, std::setw(2), std::setfill('0'), sec++, ".json"); + } while (std::filesystem::exists(fsyspath(name), ec)); + // Ignoring ec means we might potentially return a name that does already + // exist -- but if we can't check its existence, what more can we do? + return name; +} + // WIP simplified copy of display() that does minimal work void display_cube_face() { -- cgit v1.2.3 From f789bf05053c99d550e6d95e9a512c984ea43ed5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 10:39:05 -0400 Subject: Populate the viewer package's lua/auto subdir as well as require. --- indra/newview/viewer_manifest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index aa2b0b0e25..c403b57813 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -169,8 +169,9 @@ class ViewerManifest(LLManifest): with self.prefix(src_dst="scripts/lua"): self.path("*.lua") self.path("*.xml") - with self.prefix(src_dst='require'): - self.path("*.lua") + for subdir in 'require', 'auto': + with self.prefix(src_dst=subdir): + self.path("*.lua") #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing -- cgit v1.2.3 From 4ae12a08265998055627a0530f6e7ef8da5ca2ed Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 11:05:24 -0400 Subject: Add LLAgent.teleport() Lua function that wraps existing "LLTeleportHandler" LEAP listener. --- indra/newview/scripts/lua/require/LLAgent.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 07ef1e0b0b..9eebede59f 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -71,4 +71,12 @@ function LLAgent.getAnimationInfo(item_id) return leap.request('LLAgent', {op = 'getAnimationInfo', item_id=item_id}).anim_info end +-- Teleport to specified "regionname" at specified region-relative "x", "y", "z". +-- If "regionname" omitted, teleport to GLOBAL coordinates "x", "y", "z". +function LLAgent.teleport(...) + local args = mapargs('regionname,x,y,z', ...) + args.op = 'teleport' + return leap.request('LLTeleportHandler', args) +end + return LLAgent -- cgit v1.2.3 From 499c62637f487b673bac86be566588a8ccde388d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 11:14:40 -0400 Subject: Recursively package all of indra/newview/scripts/lua. Instead of trying to continue mirroring the lua subdirectory structure in viewer_manifest.py, and enumerating the relevant file extensions, just pack up the whole subtree. --- indra/newview/viewer_manifest.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c403b57813..9f77dba3bc 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -166,12 +166,7 @@ class ViewerManifest(LLManifest): self.path("*/*/*/*.js") self.path("*/*/*.html") - with self.prefix(src_dst="scripts/lua"): - self.path("*.lua") - self.path("*.xml") - for subdir in 'require', 'auto': - with self.prefix(src_dst=subdir): - self.path("*.lua") + self.path('scripts/lua') #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing -- cgit v1.2.3 From a68bb4eb27573a9313169799a188dda3ae765666 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 12:27:08 -0400 Subject: Support "LLTeleportHandler" "teleport" regionname="home". --- indra/newview/llurldispatcher.cpp | 9 ++++++++- indra/newview/scripts/lua/require/LLAgent.lua | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 39a9f0f8bc..166542324d 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -289,6 +289,8 @@ public: LLEventAPI::add("teleport", "Teleport to specified [\"regionname\"] at\n" "specified region-relative [\"x\"], [\"y\"], [\"z\"].\n" + "If [\"regionname\"] is \"home\", ignore [\"x\"], [\"y\"], [\"z\"]\n" + "and teleport home.\n" "If [\"regionname\"] omitted, teleport to GLOBAL\n" "coordinates [\"x\"], [\"y\"], [\"z\"].", &LLTeleportHandler::from_event); @@ -328,7 +330,12 @@ public: void from_event(const LLSD& params) const { Response response(LLSD(), params); - if (params.has("regionname")) + if (params["regionname"].asString() == "home") + { + gAgent.teleportHome(); + response["message"] = "Teleporting home"; + } + else if (params.has("regionname")) { // region specified, coordinates (if any) are region-local LLVector3 local_pos( diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 9eebede59f..5cee998fcd 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -72,11 +72,12 @@ function LLAgent.getAnimationInfo(item_id) end -- Teleport to specified "regionname" at specified region-relative "x", "y", "z". +-- If "regionname" is "home", ignore "x", "y", "z" and teleport home. -- If "regionname" omitted, teleport to GLOBAL coordinates "x", "y", "z". function LLAgent.teleport(...) local args = mapargs('regionname,x,y,z', ...) args.op = 'teleport' - return leap.request('LLTeleportHandler', args) + return leap.request('LLTeleportHandler', args).message end return LLAgent -- cgit v1.2.3 From 6c6a42fbbc231bad6a7921c37cdcb82d17dc225f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 13:46:30 -0400 Subject: Let test_animation.lua cope with the case of 0 animations. --- indra/newview/scripts/lua/test_animation.lua | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/test_animation.lua b/indra/newview/scripts/lua/test_animation.lua index c16fef4918..37e7254a6c 100644 --- a/indra/newview/scripts/lua/test_animation.lua +++ b/indra/newview/scripts/lua/test_animation.lua @@ -11,18 +11,22 @@ for key in pairs(anims) do table.insert(anim_ids, key) end --- Start playing a random animation -math.randomseed(os.time()) -local random_id = anim_ids[math.random(#anim_ids)] -local anim_info = LLAgent.getAnimationInfo(random_id) +if #anim_ids == 0 then + print("No animations found") +else + -- Start playing a random animation + math.randomseed(os.time()) + local random_id = anim_ids[math.random(#anim_ids)] + local anim_info = LLAgent.getAnimationInfo(random_id) -print("Starting animation locally: " .. anims[random_id].name) -print("Loop: " .. anim_info.is_loop .. " Joints: " .. anim_info.num_joints .. " Duration " .. tonumber(string.format("%.2f", anim_info.duration))) -LLAgent.playAnimation{item_id=random_id} + print("Starting animation locally: " .. anims[random_id].name) + print("Loop: " .. anim_info.is_loop .. " Joints: " .. anim_info.num_joints .. " Duration " .. tonumber(string.format("%.2f", anim_info.duration))) + LLAgent.playAnimation{item_id=random_id} --- Stop animation after 3 sec if it's looped or longer than 3 sec -if anim_info.is_loop == 1 or anim_info.duration > 3 then - LL.sleep(3) - print("Stop animation.") - LLAgent.stopAnimation(random_id) + -- Stop animation after 3 sec if it's looped or longer than 3 sec + if anim_info.is_loop == 1 or anim_info.duration > 3 then + LL.sleep(3) + print("Stop animation.") + LLAgent.stopAnimation(random_id) + end end -- cgit v1.2.3 From 2b851fbd0b4f72f46ec68965b3e06451e20a5b39 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 15:08:54 -0400 Subject: Mediate "LLAppViewer" "userQuit" et al. via "mainloop" WorkQueue. Empirically, this works better than engaging the respective LLAppViewer methods directly. --- indra/newview/llappviewerlistener.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp index d02b1b4a79..4690c91b61 100644 --- a/indra/newview/llappviewerlistener.cpp +++ b/indra/newview/llappviewerlistener.cpp @@ -35,6 +35,7 @@ // external library headers // other Linden headers #include "llappviewer.h" +#include "workqueue.h" LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): LLEventAPI("LLAppViewer", @@ -56,17 +57,23 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter): void LLAppViewerListener::userQuit(const LLSD& event) { LL_INFOS() << "Listener requested user quit" << LL_ENDL; - mAppViewerGetter()->userQuit(); + // Trying to engage this from (e.g.) a Lua-hosting C++ coroutine runs + // afoul of an assert in the logging machinery that LLMutex must be locked + // only from the main coroutine. + LL::WorkQueue::getInstance("mainloop")->post( + [appviewer=mAppViewerGetter()]{ appviewer->userQuit(); }); } void LLAppViewerListener::requestQuit(const LLSD& event) { LL_INFOS() << "Listener requested quit" << LL_ENDL; - mAppViewerGetter()->requestQuit(); + LL::WorkQueue::getInstance("mainloop")->post( + [appviewer=mAppViewerGetter()]{ appviewer->requestQuit(); }); } void LLAppViewerListener::forceQuit(const LLSD& event) { LL_INFOS() << "Listener requested force quit" << LL_ENDL; - mAppViewerGetter()->forceQuit(); + LL::WorkQueue::getInstance("mainloop")->post( + [appviewer=mAppViewerGetter()]{ appviewer->forceQuit(); }); } -- cgit v1.2.3 From 1b7fdac4689e29ec3f64c37f10b843a114d7805d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 12 Sep 2024 15:09:24 -0400 Subject: Add frame_profile.lua to TP to known spot and take frame profile. frame_profile.lua teleports home when done. Further add frame_profile bash script to run the specified viewer, automatically log into said known spot, take frame profile and quit. The frame_profile bash script runs frame_profile_quit.lua. frame_profile_quit.lua is derived from frame_profile.lua, but different: it doesn't teleport either way because it assumes autologin to the target location, and because it logs out instead of returning home. --- indra/newview/scripts/lua/frame_profile.lua | 24 +++++++++++++++++++++++ indra/newview/scripts/lua/frame_profile_quit.lua | 25 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 indra/newview/scripts/lua/frame_profile.lua create mode 100644 indra/newview/scripts/lua/frame_profile_quit.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/frame_profile.lua b/indra/newview/scripts/lua/frame_profile.lua new file mode 100644 index 0000000000..3c6353ff68 --- /dev/null +++ b/indra/newview/scripts/lua/frame_profile.lua @@ -0,0 +1,24 @@ +-- Trigger Develop -> Render Tests -> Frame Profile + +LLAgent = require 'LLAgent' +startup = require 'startup' +Timer = (require 'timers').Timer +UI = require 'UI' + +startup.wait('STATE_STARTED') + +-- teleport to http://maps.secondlife.com/secondlife/Bug%20Island/220/224/27 +print(LLAgent.teleport{regionname='Bug Island', x=220, y=224, z=27}) +Timer(10, 'wait') +LLAgent.setCamera{camera_pos={220, 224, 26}, camera_locked=true, + focus_pos ={228, 232, 26}, focus_locked=true} +Timer(1, 'wait') +-- This freezes the viewer for perceptible realtime +UI.popup:tip('starting Render Tests -> Frame Profile') +UI.call("Advanced.ClickRenderProfile") +Timer(1, 'wait') +LLAgent.removeCamParams() +LLAgent.setFollowCamActive(false) + +-- Home, James! +print(LLAgent.teleport('home')) diff --git a/indra/newview/scripts/lua/frame_profile_quit.lua b/indra/newview/scripts/lua/frame_profile_quit.lua new file mode 100644 index 0000000000..e3177a3f67 --- /dev/null +++ b/indra/newview/scripts/lua/frame_profile_quit.lua @@ -0,0 +1,25 @@ +-- Trigger Develop -> Render Tests -> Frame Profile and quit + +LLAgent = require 'LLAgent' +logout = require 'logout' +startup = require 'startup' +Timer = (require 'timers').Timer +UI = require 'UI' + +startup.wait('STATE_STARTED') + +-- Assume we logged into http://maps.secondlife.com/secondlife/Bug%20Island/220/224/27 +-- (see frame_profile bash script) +Timer(10, 'wait') +LLAgent.setCamera{camera_pos={220, 224, 26}, camera_locked=true, + focus_pos ={228, 232, 26}, focus_locked=true} +Timer(1, 'wait') +-- This freezes the viewer for perceptible realtime +UI.popup:tip('starting Render Tests -> Frame Profile') +UI.call("Advanced.ClickRenderProfile") +Timer(1, 'wait') +LLAgent.removeCamParams() +LLAgent.setFollowCamActive(false) + +-- done +logout() -- cgit v1.2.3 From ae2f4f6f6a05e1d6f327887204add2c984999db2 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Fri, 13 Sep 2024 20:40:51 +0200 Subject: Restore LUA debug consoles in viewer menu and tie visibility to feature flag --- indra/newview/skins/default/xui/en/menu_viewer.xml | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 324e868bd5..f4864dabef 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2583,6 +2583,37 @@ function="World.EnvPreset" parameter="scene monitor" /> </menu_item_check> <menu_item_separator/> + <menu_item_check + label="LUA Debug Console" + name="LUA Debug Console"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="lua_debug" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="lua_debug" /> + <menu_item_check.on_visible + function="CheckControl" + parameter="LuaFeature" /> + </menu_item_check> + <menu_item_check + label="LUA Scripts Info" + name="LUA Scripts"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="lua_scripts" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="lua_scripts" /> + <menu_item_check.on_visible + function="CheckControl" + parameter="LuaFeature" /> + </menu_item_check> + <menu_item_separator> + <menu_item_separator.on_visible + function="CheckControl" + parameter="LuaFeature"/> + </menu_item_separator> <menu_item_call label="Region Info to Debug Console" -- cgit v1.2.3 From 6c226ac96c8ba01e62ea1085177b2859b74b85d8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 13 Sep 2024 16:01:05 -0400 Subject: Add context info to Develop->Render Tests->Frame Profile stats file. Specifically, add the viewer version, the machine ID, the grid, the region name and ID, the parcel name and ID and the timestamp. This is both richer and less fragile than trying to extract that information from the generated filename: e.g. we now have region and parcel names. Instead of making `LLGLSLShader::finishProfile()` mess with file I/O, pass it a reference to a `boost::json::value` to be filled in with statistics, if it's a `boost::json::object`. Otherwise it's `boost::json::null`, meaning no report. Make llviewerdisplay.cpp's `display()` function instantiate a `boost::json::value` to pass to `finishProfile()`. That lets llviewerdisplay.cpp also set the `"context"` entry, with a new `getProfileStatsContext()` function quite similar to `getProfileStatsFilename()`. --- indra/newview/llviewerdisplay.cpp | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index fdfe477a6c..aad11d9372 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -138,6 +138,7 @@ void render_ui_3d(); void render_ui_2d(); void render_disconnected_background(); +void getProfileStatsContext(boost::json::object& stats); std::string getProfileStatsFilename(); void display_startup() @@ -1040,8 +1041,49 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) if (gShaderProfileFrame) { gShaderProfileFrame = false; - LLGLSLShader::finishProfile(getProfileStatsFilename()); + boost::json::value stats{ boost::json::object_kind }; + getProfileStatsContext(stats.as_object()); + LLGLSLShader::finishProfile(stats); + + auto report_name = getProfileStatsFilename(); + std::ofstream outf(report_name); + if (! outf) + { + LL_WARNS() << "Couldn't write to " << std::quoted(report_name) << LL_ENDL; + } + else + { + outf << stats; + LL_INFOS() << "(also dumped to " << std::quoted(report_name) << ")" << LL_ENDL; + } + } +} + +void getProfileStatsContext(boost::json::object& stats) +{ + auto contextit = stats.emplace("context", boost::json::object_kind).first; + auto& context = contextit->value().as_object(); + + auto& versionInfo = LLVersionInfo::instance(); + context.emplace("channel", versionInfo.getChannel()); + context.emplace("version", versionInfo.getVersion()); + unsigned char unique_id[MAC_ADDRESS_BYTES]{}; + LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); + context.emplace("machine", stringize(LL::hexdump(unique_id, sizeof(unique_id)))); + context.emplace("grid", LLGridManager::instance().getGrid()); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + context.emplace("region", region->getName()); + context.emplace("regionid", stringize(region->getRegionID())); + } + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + if (parcel) + { + context.emplace("parcel", parcel->getName()); + context.emplace("parcelid", parcel->getLocalID()); } + context.emplace("time", LLDate::now().toHTTPDateString("%Y-%m-%dT%H:%M:%S")); } std::string getProfileStatsFilename() -- cgit v1.2.3 From 328bdeb3cc26648060a3d7331ccdb80539953f33 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 13 Sep 2024 16:52:17 -0400 Subject: Remove autorun 'menus.lua' since menu_viewer.xml handles visibility --- indra/newview/scripts/lua/auto/menus.lua | 51 -------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 indra/newview/scripts/lua/auto/menus.lua (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/auto/menus.lua b/indra/newview/scripts/lua/auto/menus.lua deleted file mode 100644 index b2f54d83df..0000000000 --- a/indra/newview/scripts/lua/auto/menus.lua +++ /dev/null @@ -1,51 +0,0 @@ --- Inject Lua-related menus into the top menu structure. Run this as a Lua --- script so that turning off the Lua feature also disables these menus. - --- Under Develop -> Consoles, want to present the equivalent of: --- <menu_item_separator/> --- <menu_item_check --- label="LUA Debug Console" --- name="LUA Debug Console"> --- <menu_item_check.on_check --- function="Floater.Visible" --- parameter="lua_debug" /> --- <menu_item_check.on_click --- function="Floater.Toggle" --- parameter="lua_debug" /> --- </menu_item_check> --- <menu_item_check --- label="LUA Scripts Info" --- name="LUA Scripts"> --- <menu_item_check.on_check --- function="Floater.Visible" --- parameter="lua_scripts" /> --- <menu_item_check.on_click --- function="Floater.Toggle" --- parameter="lua_scripts" /> --- </menu_item_check> - -local startup = require 'startup' -local UI = require 'UI' - --- Don't mess with the viewer's menu structure until we've logged in. -startup.wait('STATE_STARTED') - --- Add LUA Debug Console to Develop->Consoles -local pos = 9 -UI.addMenuSeparator{ - parent_menu='Consoles', pos=pos, -} -pos += 1 -UI.addMenuItem{ - parent_menu='Consoles', pos=pos, - name='lua_debug', label='LUA Debug Console', - func='Floater.ToggleOrBringToFront', param='lua_debug', -} -pos += 1 - --- Add LUA Scripts Info to Develop->Consoles -UI.addMenuItem{ - parent_menu='Consoles', pos=pos, - name='lua_scripts', label='LUA Scripts Info', - func='Floater.ToggleOrBringToFront', param='lua_scripts', -} -- cgit v1.2.3 From 1154e02fdded191147284997707a3b18ee3b43fd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 16 Sep 2024 13:53:11 -0400 Subject: WIP: edits in support of Lua script args --- indra/newview/llluamanager.cpp | 79 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 21 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 0bd21516bc..c4ce07e492 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -192,35 +192,72 @@ void LLLUAmanager::runScriptFile(const std::string &filename, bool autorun, LLCoros::instance().launch(filename, [filename, autorun, result_cb, finished_cb]() { ScriptObserver observer(LLCoros::getName(), filename); - llifstream in_file; - in_file.open(filename.c_str()); + // Use LLStringUtil::getTokens() to parse the script command line + auto tokens = LLStringUtil::getTokens(filename, + " \t\r\n", // drop_delims + "", // no keep_delims + "\"'", // either kind of quotes + "\\"); // backslash escape + +#error Under construction + // TODO: + // - Move this either/or file existence logic to LuaCommand() + // - Accept LuaCommand in all LLLUAmanager::mumbleScriptFile() methods + // - Update all existing mumbleScriptFile() callers + llifstream in_file; + in_file.open(tokens[0]); if (in_file.is_open()) { - if (autorun) - { - sAutorunScriptCount++; - } - sScriptCount++; - - // A script_finished_fn is used to initialize the LuaState. - // It will be called when the LuaState is destroyed. - LuaState L(finished_cb); - std::string text{std::istreambuf_iterator<char>(in_file), {}}; - auto [count, result] = L.expr(filename, text); - if (result_cb) - { - result_cb(count, result); - } + // The first token is in fact the script filename. Now that the + // script file is open, we've consumed that token. The rest are + // command-line arguments. + tokens.erase(tokens.begin()); } else { - auto msg{ stringize("unable to open script file '", filename, "'") }; - LL_WARNS("Lua") << msg << LL_ENDL; - if (result_cb) + // Parsing the command line produced a script file path we can't + // open. Maybe that's because there are spaces in the original + // pathname that were neither quoted nor escaped? See if we can + // open the whole original command line string. + in_file.open(filename); + if (! in_file.is_open()) { - result_cb(-1, msg); + std::ostringstream msgstream; + msgstream << "Can't open script file " << std::quoted(tokens[0]); + if (filename != tokens[0]) + { + msgstream << " or " << std::quoted(filename); + } + auto msg = msgstream.str(); + LL_WARNS("Lua") << msg << LL_ENDL; + if (result_cb) + { + result_cb(-1, msg); + } + return; } + // Here we do have in_file open, using the whole input command + // line as its pathname. Discard any parts of it we mistook for + // command-line arguments. + tokens.clear(); + } + + // Here in_file is open. + if (autorun) + { + sAutorunScriptCount++; + } + sScriptCount++; + + // A script_finished_fn is used to initialize the LuaState. + // It will be called when the LuaState is destroyed. + LuaState L(finished_cb); + std::string text{std::istreambuf_iterator<char>(in_file), {}}; + auto [count, result] = L.expr(filename, text, tokens); + if (result_cb) + { + result_cb(count, result); } }); } -- cgit v1.2.3 From f4b65638879c10c832b3bb8448f82001106ffd11 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 16 Sep 2024 17:25:48 -0400 Subject: Add LLFloaterAbout info (esp. GPU info) to Frame Profile stats dump With the About info added, `getProfileStatsContext()` need not redundantly add `"channel"`, `"version"` or `"region"`. Slightly improve the efficiency of `LlsdToJson()` and `LlsdFromJson()` by preallocating the known size of the source array or map. (Unfortunately the C++ `LLSD` class offers us no way to preallocate a map.) In `LLAppViewer::getViewerInfo()`, avoid immediate successive calls to `gAgent.getRegion()`. --- indra/newview/llappviewer.cpp | 4 ++-- indra/newview/llviewerdisplay.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 789aaab70d..77797ad5f0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3351,10 +3351,10 @@ LLSD LLAppViewer::getViewerInfo() const LLVector3d pos = gAgent.getPositionGlobal(); info["POSITION"] = ll_sd_from_vector3d(pos); info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); + info["REGION"] = region->getName(); boost::regex regex("\\.(secondlife|lindenlab)\\..*"); - info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); + info["HOSTNAME"] = boost::regex_replace(region->getSimHostName(), regex, ""); info["SERVER_VERSION"] = gLastVersionChannel; LLSLURL slurl; LLAgentUI::buildSLURL(slurl); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index aad11d9372..f722d0bd1d 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -58,6 +58,7 @@ #include "llpostprocess.h" #include "llrender.h" #include "llscenemonitor.h" +#include "llsdjson.h" #include "llselectmgr.h" #include "llsky.h" #include "llspatialpartition.h" @@ -1061,12 +1062,12 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) void getProfileStatsContext(boost::json::object& stats) { - auto contextit = stats.emplace("context", boost::json::object_kind).first; + // populate the context with info from LLFloaterAbout + auto contextit = stats.emplace("context", + LlsdToJson(LLAppViewer::instance()->getViewerInfo())).first; auto& context = contextit->value().as_object(); - auto& versionInfo = LLVersionInfo::instance(); - context.emplace("channel", versionInfo.getChannel()); - context.emplace("version", versionInfo.getVersion()); + // then add a few more things unsigned char unique_id[MAC_ADDRESS_BYTES]{}; LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); context.emplace("machine", stringize(LL::hexdump(unique_id, sizeof(unique_id)))); @@ -1074,7 +1075,6 @@ void getProfileStatsContext(boost::json::object& stats) LLViewerRegion* region = gAgent.getRegion(); if (region) { - context.emplace("region", region->getName()); context.emplace("regionid", stringize(region->getRegionID())); } LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); -- cgit v1.2.3 From 870ffbd55b4ffdfad27edf8824de0c9cbc577a80 Mon Sep 17 00:00:00 2001 From: Dave Parks <davep@lindenlab.com> Date: Tue, 17 Sep 2024 12:43:47 -0500 Subject: Suppress mapBuffer warnings. (#2584) --- indra/newview/lldynamictexture.cpp | 4 +-- indra/newview/llvoavatar.cpp | 18 ++++-------- indra/newview/llvoavatar.h | 2 +- indra/newview/llvograss.cpp | 1 - indra/newview/llvopartgroup.cpp | 58 -------------------------------------- indra/newview/llvosurfacepatch.cpp | 1 - indra/newview/pipeline.cpp | 1 + 7 files changed, 10 insertions(+), 75 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 0b9f76e7f6..33325e352f 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -200,8 +200,8 @@ bool LLViewerDynamicTexture::updateAllInstances() } llassert(preview_target.getWidth() >= LLPipeline::MAX_PREVIEW_WIDTH); llassert(preview_target.getHeight() >= LLPipeline::MAX_PREVIEW_WIDTH); - llassert(bake_target.getWidth() >= LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH); - llassert(bake_target.getHeight() >= LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT); + llassert(bake_target.getWidth() >= (U32) LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH); + llassert(bake_target.getHeight() >= (U32) LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT); preview_target.bindTarget(); preview_target.clear(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index ef0bb3b926..b6a2dac1e9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2406,8 +2406,6 @@ void LLVOAvatar::updateMeshData() { if (mDrawable.notNull()) { - stop_glerror(); - S32 f_num = 0 ; const U32 VERTEX_NUMBER_THRESHOLD = 128 ;//small number of this means each part of an avatar has its own vertex buffer. const auto num_parts = mMeshLOD.size(); @@ -2534,7 +2532,6 @@ void LLVOAvatar::updateMeshData() } } - stop_glerror(); buff->unmapBuffer(); if(!f_num) @@ -10754,9 +10751,8 @@ void LLVOAvatar::updateRiggingInfo() getAssociatedVolumes(volumes); { - LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR("update rig info - get key") - HBXXH128 hash; - + LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR("update rig info - get key"); + size_t hash = 0; // Get current rigging info key for (LLVOVolume* vol : volumes) { @@ -10765,22 +10761,20 @@ void LLVOAvatar::updateRiggingInfo() const LLUUID& mesh_id = vol->getVolume()->getParams().getSculptID(); S32 max_lod = llmax(vol->getLOD(), vol->mLastRiggingInfoLOD); - hash.update(mesh_id.mData, sizeof(mesh_id.mData)); - hash.update(&max_lod, sizeof(max_lod)); + boost::hash_combine(hash, mesh_id); + boost::hash_combine(hash, max_lod); } } - LLUUID curr_rigging_info_key = hash.digest(); - // Check for key change, which indicates some change in volume composition or LOD. - if (curr_rigging_info_key == mLastRiggingInfoKey) + if (hash == mLastRiggingInfoKey) { return; } // Something changed. Update. - mLastRiggingInfoKey = curr_rigging_info_key; + mLastRiggingInfoKey = hash; } mJointRiggingInfoTab.clear(); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index ff1cbc34fc..dd1725c322 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -226,7 +226,7 @@ public: // virtual void updateRiggingInfo(); // This encodes mesh id and LOD, so we can see whether display is up-to-date. - LLUUID mLastRiggingInfoKey; + size_t mLastRiggingInfoKey; std::set<LLUUID> mActiveOverrideMeshes; virtual void onActiveOverrideMeshesChanged(); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 67adcbb244..fdd39a0e30 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -729,7 +729,6 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) } } - buffer->unmapBuffer(); mFaceList.clear(); } diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 8f792c1042..ec32a79829 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -54,63 +54,6 @@ void LLVOPartGroup::initClass() void LLVOPartGroup::restoreGL() { - //TODO: optimize out binormal mask here. Specular and normal coords as well. -#if 0 - sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2); - U32 count = LL_MAX_PARTICLE_COUNT; - if (!sVB->allocateBuffer(count*4, count*6)) - { - LL_WARNS() << "Failed to allocate Vertex Buffer to " - << count*4 << " vertices and " - << count * 6 << " indices" << LL_ENDL; - // we are likelly to crash at following getTexCoord0Strider(), so unref and return - sVB = NULL; - return; - } - - //indices and texcoords are always the same, set once - LLStrider<U16> indicesp; - - LLStrider<LLVector4a> verticesp; - - sVB->getIndexStrider(indicesp); - sVB->getVertexStrider(verticesp); - - LLVector4a v; - v.set(0,0,0,0); - - - U16 vert_offset = 0; - - for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) - { - *indicesp++ = vert_offset + 0; - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 2; - - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 3; - *indicesp++ = vert_offset + 2; - - *verticesp++ = v; - - vert_offset += 4; - } - - LLStrider<LLVector2> texcoordsp; - sVB->getTexCoord0Strider(texcoordsp); - - for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) - { - *texcoordsp++ = LLVector2(0.f, 1.f); - *texcoordsp++ = LLVector2(0.f, 0.f); - *texcoordsp++ = LLVector2(1.f, 1.f); - *texcoordsp++ = LLVector2(1.f, 0.f); - } - - sVB->unmapBuffer(); -#endif - } //static @@ -955,7 +898,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) } } - buffer->unmapBuffer(); mFaceList.clear(); } diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index fdccf34e6a..294d36b0a9 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -1078,7 +1078,6 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group) gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, indices, region_width); } - buffer->unmapBuffer(); mFaceList.clear(); } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 13dfd48643..33683416a2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3731,6 +3731,7 @@ void LLPipeline::postSort(LLCamera &camera) } } + LLVertexBuffer::flushBuffers(); // LLSpatialGroup::sNoDelete = false; LL_PUSH_CALLSTACKS(); } -- cgit v1.2.3 From fd843d514a4e28f8e4a5d5595bba21ccad195e72 Mon Sep 17 00:00:00 2001 From: Dave Parks <davep@lindenlab.com> Date: Tue, 17 Sep 2024 13:07:01 -0500 Subject: Mac pass (#2587) --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 532a87bbd1..1f214344ff 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3900,6 +3900,7 @@ void LLMeshRepository::notifyLoadedMeshes() for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;) { auto copy_iter = iter++; + LLUUID id = copy_iter->first; //skinbytes += U64Bytes(sizeof(LLMeshSkinInfo)); //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string)); @@ -3913,7 +3914,6 @@ void LLMeshRepository::notifyLoadedMeshes() } // erase from background thread - LLUUID id = iter->first; mThread->mWorkQueue.post([=]() { mThread->mSkinMap.erase(id); -- cgit v1.2.3 From 9241fb80588304f89c035e9811af96172982a8c2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Tue, 17 Sep 2024 15:26:22 -0400 Subject: Increment viewer version to 7.1.11 following promotion of secondlife/viewer #2367: 2024.08 DeltaFPS --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 346a7e3aa1..e0eaaa0bbc 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.10 +7.1.11 -- cgit v1.2.3 From 0a617904f98ab5960379099822e4891a08137e68 Mon Sep 17 00:00:00 2001 From: Dave Parks <davep@lindenlab.com> Date: Tue, 17 Sep 2024 18:14:22 -0500 Subject: #2590 Fix for horrible FPS on Intel Mac (#2591) * Work around for GHA mac runners not playing nice with Tracy * Delay VBO deletion for a few frames * Enable multithreaded GL driver and multithreaded media textures on Apple silicon --- indra/newview/featuretable_mac.txt | 14 ++++++++++++-- indra/newview/llfeaturemanager.cpp | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 2e220d2b1c..06ad730a40 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -1,4 +1,4 @@ -version 60 +version 61 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -68,7 +68,8 @@ RenderFSAASamples 1 3 RenderMaxTextureIndex 1 16 RenderGLContextCoreProfile 1 1 RenderGLMultiThreadedTextures 1 0 -RenderGLMultiThreadedMedia 1 0 +RenderGLMultiThreadedMedia 1 1 +RenderAppleUseMultGL 1 1 RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 2 RenderScreenSpaceReflections 1 1 @@ -381,6 +382,15 @@ list Intel RenderAnisotropic 1 0 RenderFSAASamples 1 0 +// AppleGPU and NonAppleGPU can be thought of as Apple silicon vs Intel Mac +list AppleGPU +RenderGLMultiThreadedMedia 1 1 +RenderAppleUseMultGL 1 1 + +list NonAppleGPU +RenderGLMultiThreadedMedia 1 0 +RenderAppleUseMultGL 1 0 + list GL3 RenderFSAASamples 0 0 RenderReflectionProbeDetail 0 0 diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index aa04221f4b..3259ea249b 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -656,6 +656,14 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("Intel"); } + if (gGLManager.mIsApple) + { + maskFeatures("AppleGPU"); + } + else + { + maskFeatures("NonAppleGPU"); + } if (gGLManager.mGLVersion < 3.f) { maskFeatures("OpenGLPre30"); -- cgit v1.2.3 From 55f2103adc36db0d3f068a31a144e15465226e13 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 13 Sep 2024 20:50:19 +0300 Subject: viewer#2565 Optimize LLFolderViewItem::draw() --- indra/newview/llconversationview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index b19b6f8dec..a1f627c8cc 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -313,7 +313,7 @@ void LLConversationViewSession::draw() { // update the rotation angle of open folder arrow updateLabelRotation(); - drawOpenFolderArrow(default_params, sFgColor); + drawOpenFolderArrow(); } LLView::draw(); } -- cgit v1.2.3 From 83cf25af8d05897986cfbcf27224bf69fe7544c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pantera=20P=C3=B3=C5=82nocy?= <panterapolnocy@gmail.com> Date: Wed, 18 Sep 2024 15:26:32 +0200 Subject: Tiny argument names correction (tittle -> title) (#2594) --- indra/newview/llfloatergltfasseteditor.cpp | 8 ++++---- indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp index d2cf24f1dd..a127f5d43e 100644 --- a/indra/newview/llfloatergltfasseteditor.cpp +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -209,7 +209,7 @@ void LLFloaterGLTFAssetEditor::loadFromNode(S32 node_id, LLFolderViewFolder* par std::string name = node.mName; if (node.mName.empty()) { - name = getString("node_tittle"); + name = getString("node_title"); } else { @@ -243,7 +243,7 @@ void LLFloaterGLTFAssetEditor::loadFromNode(S32 node_id, LLFolderViewFolder* par std::string name = mAsset->mMeshes[node.mMesh].mName; if (name.empty()) { - name = getString("mesh_tittle"); + name = getString("mesh_title"); } loadItem(node.mMesh, name, LLGLTFFolderItem::TYPE_MESH, view); } @@ -253,7 +253,7 @@ void LLFloaterGLTFAssetEditor::loadFromNode(S32 node_id, LLFolderViewFolder* par std::string name = mAsset->mSkins[node.mSkin].mName; if (name.empty()) { - name = getString("skin_tittle"); + name = getString("skin_title"); } loadItem(node.mSkin, name, LLGLTFFolderItem::TYPE_SKIN, view); } @@ -306,7 +306,7 @@ void LLFloaterGLTFAssetEditor::loadFromSelection() std::string name = scene.mName; if (scene.mName.empty()) { - name = getString("scene_tittle"); + name = getString("scene_title"); } else { diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml index b17d0aa5b6..025d537804 100644 --- a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml +++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml @@ -11,10 +11,10 @@ name="gltf asset editor" title="[OBJECT_NAME]"> <floater.string name="floater_title" value="GLTF Scene Editor"/> - <floater.string name="scene_tittle" value="Scene"/> - <floater.string name="node_tittle" value="Node"/> - <floater.string name="mesh_tittle" value="Mesh"/> - <floater.string name="skin_tittle" value="Skin"/> + <floater.string name="scene_title" value="Scene"/> + <floater.string name="node_title" value="Node"/> + <floater.string name="mesh_title" value="Mesh"/> + <floater.string name="skin_title" value="Skin"/> <layout_stack name="main_layout" -- cgit v1.2.3 From d9da5bbb33ce70e3bc799ba6696c8b10de0e5f04 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:09:51 +0200 Subject: Remove quads rendering mode entirely (#2593) --- indra/newview/llbox.cpp | 25 ++++++++----- indra/newview/llfloaterbvhpreview.cpp | 7 +++- indra/newview/llfloaterimagepreview.cpp | 30 ++++++++++----- indra/newview/llfloatermodelpreview.cpp | 15 +++++--- indra/newview/llglsandbox.cpp | 61 ++++++++++++++++--------------- indra/newview/llhudeffectblob.cpp | 11 +++++- indra/newview/llhudicon.cpp | 7 +++- indra/newview/lljoystickbutton.cpp | 28 ++++++++++---- indra/newview/llmanipscale.cpp | 35 ++++-------------- indra/newview/llmediactrl.cpp | 14 ++++++- indra/newview/llnetmap.cpp | 18 ++++++++- indra/newview/llsnapshotlivepreview.cpp | 37 +++++++++++++++---- indra/newview/lltoolmorph.cpp | 7 +++- indra/newview/llviewerjointattachment.cpp | 8 +++- indra/newview/llvoavatar.cpp | 33 ++++++++--------- indra/newview/llworldmapview.cpp | 25 +++++++++++-- indra/newview/pipeline.cpp | 15 +++++--- 17 files changed, 244 insertions(+), 132 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llbox.cpp b/indra/newview/llbox.cpp index dd12a02907..d0787a3902 100644 --- a/indra/newview/llbox.cpp +++ b/indra/newview/llbox.cpp @@ -76,16 +76,23 @@ void LLBox::renderface(S32 which_face) {7, 4, 0, 3} }; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { //gGL.normal3fv(&normals[which_face][0]); - gGL.texCoord2f(1,0); - gGL.vertex3fv(&mVertex[ faces[which_face][0] ][0]); - gGL.texCoord2f(1,1); - gGL.vertex3fv(&mVertex[ faces[which_face][1] ][0]); - gGL.texCoord2f(0,1); - gGL.vertex3fv(&mVertex[ faces[which_face][2] ][0]); - gGL.texCoord2f(0,0); - gGL.vertex3fv(&mVertex[ faces[which_face][3] ][0]); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv(&mVertex[faces[which_face][0]][0]); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3fv(&mVertex[faces[which_face][1]][0]); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv(&mVertex[faces[which_face][2]][0]); + + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv(&mVertex[faces[which_face][0]][0]); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv(&mVertex[faces[which_face][2]][0]); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3fv(&mVertex[faces[which_face][3]][0]); + } gGL.end(); } diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 3d81d01e16..b94c31ec04 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -406,7 +406,7 @@ void LLFloaterBvhPreview::draw() gGL.getTexUnit(0)->bind(mAnimPreview); - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); @@ -414,6 +414,11 @@ void LLFloaterBvhPreview::draw() gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 0.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); } diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 711c33e73d..236725bd45 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -285,16 +285,21 @@ void LLFloaterImagePreview::draw() } gGL.color3f(1.f, 1.f, 1.f); - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop); - gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mBottom); - gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + + gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mTop); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); } gGL.end(); @@ -317,16 +322,21 @@ void LLFloaterImagePreview::draw() gGL.getTexUnit(0)->bind(mAvatarPreview); } - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); } gGL.end(); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 5ca727cf66..8332a430e6 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -782,16 +782,21 @@ void LLFloaterModelPreview::draw3dPreview() gGL.getTexUnit(0)->bind(mModelPreview); - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft+1, mPreviewRect.mTop-1); + gGL.vertex2i(mPreviewRect.mLeft + 1, mPreviewRect.mTop - 1); gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft+1, mPreviewRect.mBottom+1); + gGL.vertex2i(mPreviewRect.mLeft + 1, mPreviewRect.mBottom + 1); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom+1); + gGL.vertex2i(mPreviewRect.mRight - 1, mPreviewRect.mBottom + 1); + + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight - 1, mPreviewRect.mBottom + 1); gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); + gGL.vertex2i(mPreviewRect.mRight - 1, mPreviewRect.mTop - 1); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft + 1, mPreviewRect.mTop - 1); } gGL.end(); diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 0248f5710f..731e711cd1 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -338,28 +338,19 @@ void LLViewerParcelMgr::renderRect(const LLVector3d &west_south_bottom_global, gGL.end(); gGL.color4f(1.f, 1.f, 0.f, 0.2f); - gGL.begin(LLRender::QUADS); - - gGL.vertex3f(west, north, nw_bottom); - gGL.vertex3f(west, north, nw_top); - gGL.vertex3f(east, north, ne_top); - gGL.vertex3f(east, north, ne_bottom); - - gGL.vertex3f(east, north, ne_bottom); - gGL.vertex3f(east, north, ne_top); - gGL.vertex3f(east, south, se_top); - gGL.vertex3f(east, south, se_bottom); - - gGL.vertex3f(east, south, se_bottom); - gGL.vertex3f(east, south, se_top); - gGL.vertex3f(west, south, sw_top); - gGL.vertex3f(west, south, sw_bottom); - - gGL.vertex3f(west, south, sw_bottom); - gGL.vertex3f(west, south, sw_top); - gGL.vertex3f(west, north, nw_top); - gGL.vertex3f(west, north, nw_bottom); - + gGL.begin(LLRender::TRIANGLE_STRIP); + { + gGL.vertex3f(west, north, nw_bottom); + gGL.vertex3f(west, north, nw_top); + gGL.vertex3f(east, north, ne_bottom); + gGL.vertex3f(east, north, ne_top); + gGL.vertex3f(east, south, se_bottom); + gGL.vertex3f(east, south, se_top); + gGL.vertex3f(west, south, sw_top); + gGL.vertex3f(west, south, sw_bottom); + gGL.vertex3f(west, north, nw_top); + gGL.vertex3f(west, north, nw_bottom); + } gGL.end(); LLUI::setLineWidth(1.f); @@ -493,6 +484,10 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei gGL.vertex3f(x2, y2, z2); + gGL.vertex3f(x1, y1, z); + + gGL.vertex3f(x2, y2, z2); + z = z2+height; gGL.vertex3f(x2, y2, z); } @@ -523,18 +518,24 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei } - gGL.texCoord2f(tex_coord1*0.5f+0.5f, z1*0.5f); + gGL.texCoord2f(tex_coord1 * 0.5f + 0.5f, z1 * 0.5f); gGL.vertex3f(x1, y1, z1); - gGL.texCoord2f(tex_coord2*0.5f+0.5f, z2*0.5f); + gGL.texCoord2f(tex_coord2 * 0.5f + 0.5f, z2 * 0.5f); gGL.vertex3f(x2, y2, z2); // top edge stairsteps - z = llmax(z2+height, z1+height); - gGL.texCoord2f(tex_coord2*0.5f+0.5f, z*0.5f); + z = llmax(z2 + height, z1 + height); + gGL.texCoord2f(tex_coord2 * 0.5f + 0.5f, z * 0.5f); + gGL.vertex3f(x2, y2, z); + + gGL.texCoord2f(tex_coord1 * 0.5f + 0.5f, z1 * 0.5f); + gGL.vertex3f(x1, y1, z1); + + gGL.texCoord2f(tex_coord2 * 0.5f + 0.5f, z * 0.5f); gGL.vertex3f(x2, y2, z); - gGL.texCoord2f(tex_coord1*0.5f+0.5f, z*0.5f); + gGL.texCoord2f(tex_coord1 * 0.5f + 0.5f, z * 0.5f); gGL.vertex3f(x1, y1, z); } } @@ -575,7 +576,7 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi if (!has_segments) { has_segments = true; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); } renderOneSegment(x1, y1, x2, y2, PARCEL_POST_HEIGHT, SOUTH_MASK, regionp); } @@ -591,7 +592,7 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi if (!has_segments) { has_segments = true; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); } renderOneSegment(x1, y1, x2, y2, PARCEL_POST_HEIGHT, WEST_MASK, regionp); } @@ -647,7 +648,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, bool use_pass, LLV gGL.getTexUnit(0)->bind(mBlockedImage); } - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); for (y = 0; y < STRIDE; y++) { diff --git a/indra/newview/llhudeffectblob.cpp b/indra/newview/llhudeffectblob.cpp index b476226d05..bdb21fd96e 100644 --- a/indra/newview/llhudeffectblob.cpp +++ b/indra/newview/llhudeffectblob.cpp @@ -78,16 +78,23 @@ void LLHUDEffectBlob::render() LLVector3 u_scale = pixel_right * (F32)mPixelSize; LLVector3 v_scale = pixel_up * (F32)mPixelSize; - { gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { gGL.texCoord2f(0.f, 1.f); gGL.vertex3fv((v_scale - u_scale).mV); gGL.texCoord2f(0.f, 0.f); gGL.vertex3fv((-v_scale - u_scale).mV); gGL.texCoord2f(1.f, 0.f); gGL.vertex3fv((-v_scale + u_scale).mV); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv((v_scale - u_scale).mV); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv((-v_scale + u_scale).mV); gGL.texCoord2f(1.f, 1.f); gGL.vertex3fv((v_scale + u_scale).mV); - } gGL.end(); + } + gGL.end(); } gGL.popMatrix(); } diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp index 8fa4118a40..1a4af470bd 100644 --- a/indra/newview/llhudicon.cpp +++ b/indra/newview/llhudicon.cpp @@ -152,7 +152,7 @@ void LLHUDIcon::render() gGL.getTexUnit(0)->bind(mImagep); } - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(0.f, 1.f); gGL.vertex3fv(upper_left.mV); @@ -160,6 +160,11 @@ void LLHUDIcon::render() gGL.vertex3fv(lower_left.mV); gGL.texCoord2f(1.f, 0.f); gGL.vertex3fv(lower_right.mV); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv(upper_left.mV); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv(lower_right.mV); gGL.texCoord2f(1.f, 1.f); gGL.vertex3fv(upper_right.mV); } diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp index 4eaf69c39d..10a1cd6b71 100644 --- a/indra/newview/lljoystickbutton.cpp +++ b/indra/newview/lljoystickbutton.cpp @@ -637,18 +637,24 @@ void LLJoystickCameraRotate::drawRotatedImage( LLPointer<LLUIImage> image, S32 r gGL.color4fv(UI_VERTEX_COLOR.mV); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { - gGL.texCoord2fv( uv[ (rotations + 0) % 4]); - gGL.vertex2i(width, height ); + gGL.texCoord2fv(uv[(rotations + 0) % 4]); + gGL.vertex2i(width, height); + + gGL.texCoord2fv(uv[(rotations + 1) % 4]); + gGL.vertex2i(0, height); - gGL.texCoord2fv( uv[ (rotations + 1) % 4]); - gGL.vertex2i(0, height ); + gGL.texCoord2fv(uv[(rotations + 2) % 4]); + gGL.vertex2i(0, 0); + + gGL.texCoord2fv(uv[(rotations + 0) % 4]); + gGL.vertex2i(width, height); - gGL.texCoord2fv( uv[ (rotations + 2) % 4]); + gGL.texCoord2fv(uv[(rotations + 2) % 4]); gGL.vertex2i(0, 0); - gGL.texCoord2fv( uv[ (rotations + 3) % 4]); + gGL.texCoord2fv(uv[(rotations + 3) % 4]); gGL.vertex2i(width, 0); } gGL.end(); @@ -909,7 +915,7 @@ void LLJoystickQuaternion::drawRotatedImage(LLPointer<LLUIImage> image, S32 rota gGL.color4fv(UI_VERTEX_COLOR.mV); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2fv(uv[(rotations + 0) % 4]); gGL.vertex2i(width, height); @@ -920,6 +926,12 @@ void LLJoystickQuaternion::drawRotatedImage(LLPointer<LLUIImage> image, S32 rota gGL.texCoord2fv(uv[(rotations + 2) % 4]); gGL.vertex2i(0, 0); + gGL.texCoord2fv(uv[(rotations + 0) % 4]); + gGL.vertex2i(width, height); + + gGL.texCoord2fv(uv[(rotations + 1) % 4]); + gGL.vertex2i(0, height); + gGL.texCoord2fv(uv[(rotations + 3) % 4]); gGL.vertex2i(width, 0); } diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 19868f3c3e..9966a8eedb 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -618,43 +618,22 @@ void LLManipScale::renderFaces( const LLBBox& bbox ) { gGL.color4fv( default_normal_color.mV ); LLGLDepthTest gls_depth(GL_FALSE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { - // Face 0 - gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); - gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); - gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); - - // Face 1 - gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); + gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); + gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); - - // Face 2 gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); - - // Face 3 - gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); - gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); - - // Face 4 - gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); - gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); - gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); - - // Face 5 - gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); - gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); - gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); + gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); } gGL.end(); } diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b39a976ebd..202008f7f9 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -843,7 +843,7 @@ void LLMediaCtrl::draw() calcOffsetsAndSize(&x_offset, &y_offset, &width, &height); // draw the browser - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); if (! media_plugin->getTextureCoordsOpenGL()) { // render using web browser reported width and height, instead of trying to invert GL scale @@ -856,6 +856,12 @@ void LLMediaCtrl::draw() gGL.texCoord2f( 0.f, max_v ); gGL.vertex2i( x_offset, y_offset ); + gGL.texCoord2f(max_u, 0.f); + gGL.vertex2i(x_offset + width, y_offset + height); + + gGL.texCoord2f(0.f, max_v); + gGL.vertex2i(x_offset, y_offset); + gGL.texCoord2f( max_u, max_v ); gGL.vertex2i( x_offset + width, y_offset ); } @@ -871,6 +877,12 @@ void LLMediaCtrl::draw() gGL.texCoord2f( 0.f, 0.f ); gGL.vertex2i( x_offset, y_offset ); + gGL.texCoord2f(max_u, max_v); + gGL.vertex2i(x_offset + width, y_offset + height); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(x_offset, y_offset); + gGL.texCoord2f( max_u, 0.f ); gGL.vertex2i( x_offset + width, y_offset ); } diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 3f370b1ab5..af472c4259 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -298,15 +298,22 @@ void LLNetMap::draw() // Draw using texture. gGL.getTexUnit(0)->bind(regionp->getLand().getSTexture()); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { gGL.texCoord2f(0.f, 1.f); gGL.vertex2f(left, top); gGL.texCoord2f(0.f, 0.f); gGL.vertex2f(left, bottom); gGL.texCoord2f(1.f, 0.f); gGL.vertex2f(right, bottom); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2f(left, top); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(right, bottom); gGL.texCoord2f(1.f, 1.f); gGL.vertex2f(right, top); + } gGL.end(); gGL.flush(); @@ -347,15 +354,22 @@ void LLNetMap::draw() F32 image_half_width = 0.5f*mObjectMapPixels; F32 image_half_height = 0.5f*mObjectMapPixels; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { gGL.texCoord2f(0.f, 1.f); gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]); gGL.texCoord2f(0.f, 0.f); gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height); gGL.texCoord2f(1.f, 0.f); gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height); gGL.texCoord2f(1.f, 1.f); gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]); + } gGL.end(); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 0b73aa493c..e996cc87fc 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -295,13 +295,20 @@ void LLSnapshotLivePreview::draw() gGL.pushMatrix(); { gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom + TOP_PANEL_HEIGHT, 0.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(uv_width, uv_height); - gGL.vertex2i(rect.getWidth(), rect.getHeight() ); + gGL.vertex2i(rect.getWidth(), rect.getHeight()); gGL.texCoord2f(0.f, uv_height); - gGL.vertex2i(0, rect.getHeight() ); + gGL.vertex2i(0, rect.getHeight()); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(0, 0); + + + gGL.texCoord2f(uv_width, uv_height); + gGL.vertex2i(rect.getWidth(), rect.getHeight()); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(0, 0); @@ -357,13 +364,18 @@ void LLSnapshotLivePreview::draw() S32 y2 = gViewerWindow->getWindowHeightScaled() + TOP_PANEL_HEIGHT; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.color4f(1.f, 1.f, 1.f, 0.f); gGL.vertex2i(x1, y1); gGL.vertex2i(x1 + gViewerWindow->getWindowWidthScaled(), y2); gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); + + gGL.color4f(1.f, 1.f, 1.f, 0.f); + gGL.vertex2i(x1, y1); + gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); + gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); gGL.vertex2i(x2, y1); gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); @@ -371,6 +383,11 @@ void LLSnapshotLivePreview::draw() gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); gGL.color4f(1.f, 1.f, 1.f, 0.f); gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2); + + gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); + gGL.vertex2i(x2, y1); + gGL.color4f(1.f, 1.f, 1.f, 0.f); + gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2); gGL.vertex2i(x3, y1); } gGL.end(); @@ -406,13 +423,19 @@ void LLSnapshotLivePreview::draw() LLRect& rect = mImageRect[old_image_index]; gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - ll_round(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f); gGL.rotatef(-45.f * fall_interp, 0.f, 0.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(uv_width, uv_height); - gGL.vertex2i(rect.getWidth(), rect.getHeight() ); + gGL.vertex2i(rect.getWidth(), rect.getHeight()); gGL.texCoord2f(0.f, uv_height); - gGL.vertex2i(0, rect.getHeight() ); + gGL.vertex2i(0, rect.getHeight()); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(0, 0); + + gGL.texCoord2f(uv_width, uv_height); + gGL.vertex2i(rect.getWidth(), rect.getHeight()); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(0, 0); diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 24cfca5eee..8ce9a8b632 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -285,7 +285,7 @@ void LLVisualParamHint::draw(F32 alpha) gGL.color4f(1.f, 1.f, 1.f, alpha); LLGLSUIDefault gls_ui; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2i(0, 1); gGL.vertex2i(0, mFullHeight); @@ -293,6 +293,11 @@ void LLVisualParamHint::draw(F32 alpha) gGL.vertex2i(0, 0); gGL.texCoord2i(1, 0); gGL.vertex2i(mFullWidth, 0); + + gGL.texCoord2i(0, 1); + gGL.vertex2i(0, mFullHeight); + gGL.texCoord2i(1, 0); + gGL.vertex2i(mFullWidth, 0); gGL.texCoord2i(1, 1); gGL.vertex2i(mFullWidth, mFullHeight); } diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index e733dafcae..511fac9788 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -86,13 +86,17 @@ U32 LLViewerJointAttachment::drawShape( F32 pixelArea, bool first_pass, bool is_ LLGLDisable cull_face(GL_CULL_FACE); gGL.color4f(1.f, 1.f, 1.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { gGL.vertex3f(-0.1f, 0.1f, 0.f); gGL.vertex3f(-0.1f, -0.1f, 0.f); gGL.vertex3f(0.1f, -0.1f, 0.f); + + gGL.vertex3f(-0.1f, 0.1f, 0.f); + gGL.vertex3f(0.1f, -0.1f, 0.f); gGL.vertex3f(0.1f, 0.1f, 0.f); - }gGL.end(); + } + gGL.end(); } return 0; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b6a2dac1e9..7bc9d06f9a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -5424,14 +5424,6 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) gGL.setSceneBlendType(LLRender::BT_ADD); gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); - // gGL.begin(LLRender::QUADS); - // gGL.vertex3fv((pos+left-up).mV); - // gGL.vertex3fv((pos-left-up).mV); - // gGL.vertex3fv((pos-left+up).mV); - // gGL.vertex3fv((pos+left+up).mV); - // gGL.end(); - - gGL.begin(LLRender::LINES); gGL.color4f(1.f,1.f,1.f,1.f); F32 thickness = llmax(F32(5.0f-5.0f*(gFrameTimeSeconds-mLastImpostorUpdateFrameTime)),1.0f); @@ -5452,15 +5444,22 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) gGL.color4ubv(color.mV); gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0,0); - gGL.vertex3fv((pos+left-up).mV); - gGL.texCoord2f(1,0); - gGL.vertex3fv((pos-left-up).mV); - gGL.texCoord2f(1,1); - gGL.vertex3fv((pos-left+up).mV); - gGL.texCoord2f(0,1); - gGL.vertex3fv((pos+left+up).mV); + gGL.begin(LLRender::TRIANGLES); + { + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3fv((pos + left - up).mV); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv((pos - left - up).mV); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3fv((pos - left + up).mV); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3fv((pos + left - up).mV); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3fv((pos - left + up).mV); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv((pos + left + up).mV); + } gGL.end(); gGL.flush(); } diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index ca854ac7f7..6b2bd3e6fb 100755 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -462,11 +462,16 @@ void LLWorldMapView::draw() gGL.color4f(0.2f, 0.0f, 0.0f, 0.4f); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { gGL.vertex2f(left, top); gGL.vertex2f(left, bottom); gGL.vertex2f(right, bottom); + + gGL.vertex2f(left, top); + gGL.vertex2f(right, bottom); gGL.vertex2f(right, top); + } gGL.end(); } else if (show_for_sale && (level <= DRAW_LANDFORSALE_THRESHOLD)) @@ -483,15 +488,22 @@ void LLWorldMapView::draw() { gGL.getTexUnit(0)->bind(overlayimage); gGL.color4f(1.f, 1.f, 1.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { gGL.texCoord2f(0.f, 1.f); gGL.vertex3f(left, top, -0.5f); gGL.texCoord2f(0.f, 0.f); gGL.vertex3f(left, bottom, -0.5f); gGL.texCoord2f(1.f, 0.f); gGL.vertex3f(right, bottom, -0.5f); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3f(left, top, -0.5f); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3f(right, bottom, -0.5f); gGL.texCoord2f(1.f, 1.f); gGL.vertex3f(right, top, -0.5f); + } gGL.end(); } } @@ -737,15 +749,22 @@ bool LLWorldMapView::drawMipmapLevel(S32 width, S32 height, S32 level, bool load gGL.color4f(1.f, 1.0f, 1.0f, 1.0f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); + { gGL.texCoord2f(0.f, 1.f); gGL.vertex3f(left, top, 0.f); gGL.texCoord2f(0.f, 0.f); gGL.vertex3f(left, bottom, 0.f); gGL.texCoord2f(1.f, 0.f); gGL.vertex3f(right, bottom, 0.f); + + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3f(left, top, 0.f); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3f(right, bottom, 0.f); gGL.texCoord2f(1.f, 1.f); gGL.vertex3f(right, top, 0.f); + } gGL.end(); #if DEBUG_DRAW_TILE drawTileOutline(level, top, left, bottom, right); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 33683416a2..14a15eb59f 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -10897,11 +10897,16 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar, bool gGL.diffuseColor4fv(LLColor4::pink.mV ); } - gGL.begin(LLRender::QUADS); - gGL.vertex3f(-1, -1, clip_plane); - gGL.vertex3f(1, -1, clip_plane); - gGL.vertex3f(1, 1, clip_plane); - gGL.vertex3f(-1, 1, clip_plane); + gGL.begin(LLRender::TRIANGLES); + { + gGL.vertex3f(-1.f, -1.f, clip_plane); + gGL.vertex3f(1.f, -1.f, clip_plane); + gGL.vertex3f(1.f, 1.f, clip_plane); + + gGL.vertex3f(-1.f, -1.f, clip_plane); + gGL.vertex3f(1.f, 1.f, clip_plane); + gGL.vertex3f(-1.f, 1.f, clip_plane); + } gGL.end(); gGL.flush(); -- cgit v1.2.3 From 27b8e6d576346e3174760087a15811478a90459e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Wed, 18 Sep 2024 11:44:03 +0200 Subject: #2408 The long covenant with emojis significantly slows down some operations in the viewer --- indra/newview/llchatmsgbox.cpp | 10 ++++++++++ indra/newview/llexpandabletextbox.cpp | 8 ++++++++ indra/newview/llfloaterbuyland.cpp | 25 ++++++++++++++++++++++++ indra/newview/llfloaterbuyland.h | 2 ++ indra/newview/llfloaterland.cpp | 10 ++++++++++ indra/newview/llfloaterland.h | 2 ++ indra/newview/llfloaterregioninfo.cpp | 10 ++++++++++ indra/newview/llfloaterregioninfo.h | 1 + indra/newview/llpanelplaceprofile.cpp | 5 +++++ indra/newview/llpanelplaceprofile.h | 2 ++ indra/newview/llviewermessage.cpp | 36 +++++++++++++++++++++++++---------- indra/newview/llviewertexteditor.cpp | 10 ++++++++++ 12 files changed, 111 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp index b70b3eac95..eacbb4366d 100644 --- a/indra/newview/llchatmsgbox.cpp +++ b/indra/newview/llchatmsgbox.cpp @@ -41,6 +41,16 @@ public: mEditor(NULL) {} + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const + { + ChatSeparator* copy = new ChatSeparator(mStart, mEnd); + if (mEditor) + { + copy->mEditor = ⌖ + } + return copy; + } + /*virtual*/ void linkToDocument(class LLTextBase* editor) { mEditor = editor; diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 748e10160c..5c46eb9d80 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -44,6 +44,14 @@ public: mExpanderLabel(utf8str_to_wstring(more_text)) {} + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const + { + LLStyleSP sp(cloneStyle(target, mStyle)); + LLExpanderSegment* copy = new LLExpanderSegment(sp, mStart, mEnd, LLStringUtil::null, target); + copy->mExpanderLabel = mExpanderLabel; + return copy; + } + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { // more label always spans width of text box diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 11505e3047..a38cc94328 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -163,6 +163,7 @@ public: void updateParcelInfo(); void updateCovenantInfo(); static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data); + void updateFloaterCovenant(const LLTextBase* source, const LLUUID &asset_id); void updateFloaterCovenantText(const std::string& string, const LLUUID &asset_id); void updateFloaterEstateName(const std::string& name); void updateFloaterLastModified(const std::string& text); @@ -201,6 +202,8 @@ public: void onVisibilityChanged ( const LLSD& new_visibility ); +private: + void onCovenantTextUpdated(const LLUUID& asset_id); }; // static @@ -221,6 +224,15 @@ void LLFloaterBuyLand::buyLand( } } +// static +void LLFloaterBuyLand::updateCovenant(const LLTextBase* source, const LLUUID& asset_id) +{ + if (LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land")) + { + floater->updateFloaterCovenant(source, asset_id); + } +} + // static void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id) { @@ -560,11 +572,24 @@ void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data) } } +void LLFloaterBuyLandUI::updateFloaterCovenant(const LLTextBase* source, const LLUUID& asset_id) +{ + LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("covenant_editor"); + editor->copyContents(source); + + onCovenantTextUpdated(asset_id); +} + void LLFloaterBuyLandUI::updateFloaterCovenantText(const std::string &string, const LLUUID& asset_id) { LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("covenant_editor"); editor->setText(string); + onCovenantTextUpdated(asset_id); +} + +void LLFloaterBuyLandUI::onCovenantTextUpdated(const LLUUID& asset_id) +{ LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant"); LLTextBox* box = getChild<LLTextBox>("covenant_text"); if (asset_id.isNull()) diff --git a/indra/newview/llfloaterbuyland.h b/indra/newview/llfloaterbuyland.h index f750a4017a..732312f10f 100644 --- a/indra/newview/llfloaterbuyland.h +++ b/indra/newview/llfloaterbuyland.h @@ -27,6 +27,7 @@ #ifndef LL_LLFLOATERBUYLAND_H #define LL_LLFLOATERBUYLAND_H +class LLTextBase; class LLFloater; class LLViewerRegion; class LLParcelSelection; @@ -37,6 +38,7 @@ public: static void buyLand(LLViewerRegion* region, LLSafeHandle<LLParcelSelection> parcel, bool is_for_group); + static void updateCovenant(const LLTextBase* source, const LLUUID& asset_id); static void updateCovenantText(const std::string& string, const LLUUID& asset_id); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index bec76fe5e4..52a3e78d04 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -3123,6 +3123,16 @@ void LLPanelLandCovenant::refresh() } } +// static +void LLPanelLandCovenant::updateCovenant(const LLTextBase* source) +{ + if (LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant()) + { + LLViewerTextEditor* editor = self->getChild<LLViewerTextEditor>("covenant_editor"); + editor->copyContents(source); + } +} + // static void LLPanelLandCovenant::updateCovenantText(const std::string &string) { diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 95f6a44a94..8af0caab33 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -50,6 +50,7 @@ class LLRadioGroup; class LLParcelSelectionObserver; class LLSpinCtrl; class LLTabContainer; +class LLTextBase; class LLTextBox; class LLTextEditor; class LLTextureCtrl; @@ -416,6 +417,7 @@ public: virtual ~LLPanelLandCovenant(); virtual bool postBuild(); void refresh(); + static void updateCovenant(const LLTextBase* source); static void updateCovenantText(const std::string& string); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 8070284e32..efeee1ad3c 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2819,6 +2819,16 @@ void LLPanelEstateCovenant::setEstateName(const std::string& name) mEstateNameText->setText(name); } +// static +void LLPanelEstateCovenant::updateCovenant(const LLTextBase* source, const LLUUID& asset_id) +{ + if (LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant()) + { + panelp->mEditor->copyContents(source); + panelp->setCovenantID(asset_id); + } +} + // static void LLPanelEstateCovenant::updateCovenantText(const std::string& string, const LLUUID& asset_id) { diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index b604a28fc3..65c1291728 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -382,6 +382,7 @@ public: void* user_data, S32 status, LLExtStat ext_status); // Accessor functions + static void updateCovenant(const LLTextBase* source, const LLUUID& asset_id); static void updateCovenantText(const std::string& string, const LLUUID& asset_id); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 18588514f8..87f05f2028 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -629,6 +629,11 @@ void LLPanelPlaceProfile::updateCovenantText(const std::string &text) mCovenantText->setText(text); } +void LLPanelPlaceProfile::updateCovenant(const LLTextBase* source) +{ + mCovenantText->copyContents(source); +} + void LLPanelPlaceProfile::onForSaleBannerClick() { LLViewerParcelMgr* mgr = LLViewerParcelMgr::getInstance(); diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h index 45a20fb86a..f562be0f5d 100644 --- a/indra/newview/llpanelplaceprofile.h +++ b/indra/newview/llpanelplaceprofile.h @@ -31,6 +31,7 @@ class LLAccordionCtrl; class LLIconCtrl; +class LLTextBase; class LLTextEditor; class LLPanelPlaceProfile : public LLPanelPlaceInfo @@ -60,6 +61,7 @@ public: void updateEstateName(const std::string& name); void updateEstateOwnerName(const std::string& name); void updateCovenantText(const std::string &text); + void updateCovenant(const LLTextBase* source); private: void onForSaleBannerClick(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 0861b439eb..1d4828fd33 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -6739,7 +6739,8 @@ void onCovenantLoadComplete(const LLUUID& asset_uuid, { LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; std::string covenant_text; - if(0 == status) + std::unique_ptr<LLViewerTextEditor> editorp; + if (0 == status) { LLFileSystem file(asset_uuid, type, LLFileSystem::READ); @@ -6760,13 +6761,13 @@ void onCovenantLoadComplete(const LLUUID& asset_uuid, { LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; covenant_text = "Problem importing estate covenant."; + delete editor; } else { // Version 0 (just text, doesn't include version number) - covenant_text = editor->getText(); + editorp.reset(editor); // Use covenant from editorp; } - delete editor; } else { @@ -6792,17 +6793,32 @@ void onCovenantLoadComplete(const LLUUID& asset_uuid, LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL; } - LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); - LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile"); - if (panel) + if (editorp) { - panel->updateCovenantText(covenant_text); + LLPanelEstateCovenant::updateCovenant(editorp.get(), asset_uuid); + LLPanelLandCovenant::updateCovenant(editorp.get()); + LLFloaterBuyLand::updateCovenant(editorp.get(), asset_uuid); + } + else + { + LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); + LLPanelLandCovenant::updateCovenantText(covenant_text); + LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); } -} + if (LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile")) + { + if (editorp) + { + panel->updateCovenant(editorp.get()); + } + else + { + panel->updateCovenantText(covenant_text); + } + } +} void process_feature_disabled_message(LLMessageSystem* msg, void**) { diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 5793a28b80..210cd62d6f 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -179,6 +179,16 @@ public: mToolTip = inv_item->getName() + '\n' + inv_item->getDescription(); } + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const + { + LLTextEditor* editor = dynamic_cast<LLTextEditor*>(&target); + llassert(editor); + if (!editor) + return nullptr; + + return new LLEmbeddedItemSegment(mStart, mImage, mItem, *editor); + } + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { if (num_chars == 0) -- cgit v1.2.3 From f037cde7f4d5d55dc0a71eb867f5b2bfcaf5631f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 11 Sep 2024 12:29:18 -0400 Subject: Make Develop->Render Tests->Frame Profile dump JSON to a file too. Make `LLGLSLShader::finishProfile()` accept a string pathname instead of a bool and, in addition to logging statistics to the viewer log, output statistics to that file as JSON. The calls that used to pass `emit_report=false` now pass `report_name=std::string()`. Make llviewerdisplay.cpp's `display()` function synthesize a profile filename in the viewer's logs directory, and pass that filename to `LLGLSLShader::finishProfile()`. (cherry picked from commit d5712689d36a1ee1af32242706901fde7229b08d) --- indra/newview/llfeaturemanager.cpp | 2 +- indra/newview/llglsandbox.cpp | 2 +- indra/newview/llviewerdisplay.cpp | 102 ++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 27 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 3259ea249b..b5d8f70c2e 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -393,7 +393,7 @@ F32 logExceptionBenchmark() __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) { // HACK - ensure that profiling is disabled - LLGLSLShader::finishProfile(false); + LLGLSLShader::finishProfile(); // convert to C++ styled exception char integer_string[32]; diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 731e711cd1..b0f136fb93 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -924,7 +924,7 @@ struct ShaderProfileHelper } ~ShaderProfileHelper() { - LLGLSLShader::finishProfile(false); + LLGLSLShader::finishProfile(); } }; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 301ea5c5f6..fdfe477a6c 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -28,58 +28,69 @@ #include "llviewerdisplay.h" -#include "llgl.h" -#include "llrender.h" -#include "llglheaders.h" -#include "llgltfmateriallist.h" +#include "fsyspath.h" +#include "hexdump.h" #include "llagent.h" #include "llagentcamera.h" -#include "llviewercontrol.h" +#include "llappviewer.h" #include "llcoord.h" #include "llcriticaldamp.h" +#include "llcubemap.h" #include "lldir.h" -#include "lldynamictexture.h" #include "lldrawpoolalpha.h" +#include "lldrawpoolbump.h" +#include "lldrawpoolwater.h" +#include "lldynamictexture.h" +#include "llenvironment.h" +#include "llfasttimer.h" #include "llfeaturemanager.h" -//#include "llfirstuse.h" +#include "llfloatertools.h" +#include "llfocusmgr.h" +#include "llgl.h" +#include "llglheaders.h" +#include "llgltfmateriallist.h" #include "llhudmanager.h" #include "llimagepng.h" +#include "llmachineid.h" #include "llmemory.h" +#include "llparcel.h" +#include "llperfstats.h" +#include "llpostprocess.h" +#include "llrender.h" +#include "llscenemonitor.h" #include "llselectmgr.h" #include "llsky.h" +#include "llspatialpartition.h" #include "llstartup.h" +#include "llstartup.h" +#include "lltooldraganddrop.h" #include "lltoolfocus.h" #include "lltoolmgr.h" -#include "lltooldraganddrop.h" #include "lltoolpie.h" #include "lltracker.h" #include "lltrans.h" #include "llui.h" +#include "lluuid.h" +#include "llversioninfo.h" #include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewernetwork.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llvograss.h" #include "llworld.h" #include "pipeline.h" -#include "llspatialpartition.h" -#include "llappviewer.h" -#include "llstartup.h" -#include "llviewershadermgr.h" -#include "llfasttimer.h" -#include "llfloatertools.h" -#include "llviewertexturelist.h" -#include "llfocusmgr.h" -#include "llcubemap.h" -#include "llviewerregion.h" -#include "lldrawpoolwater.h" -#include "lldrawpoolbump.h" -#include "llpostprocess.h" -#include "llscenemonitor.h" -#include "llenvironment.h" -#include "llperfstats.h" +#include <boost/json.hpp> + +#include <filesystem> +#include <iomanip> +#include <sstream> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> @@ -127,6 +138,8 @@ void render_ui_3d(); void render_ui_2d(); void render_disconnected_background(); +std::string getProfileStatsFilename(); + void display_startup() { if ( !gViewerWindow @@ -1027,10 +1040,49 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) if (gShaderProfileFrame) { gShaderProfileFrame = false; - LLGLSLShader::finishProfile(); + LLGLSLShader::finishProfile(getProfileStatsFilename()); } } +std::string getProfileStatsFilename() +{ + std::ostringstream basebuff; + // viewer build + basebuff << "profile.v" << LLVersionInfo::instance().getBuild(); + // machine ID: zero-initialize unique_id in case LLMachineID fails + unsigned char unique_id[MAC_ADDRESS_BYTES]{}; + LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); + basebuff << ".m" << LL::hexdump(unique_id, sizeof(unique_id)); + // region ID + LLViewerRegion *region = gAgent.getRegion(); + basebuff << ".r" << (region? region->getRegionID() : LLUUID()); + // local parcel ID + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + basebuff << ".p" << (parcel? parcel->getLocalID() : 0); + // date/time -- omit seconds for now + auto now = LLDate::now(); + basebuff << ".t" << LLDate::now().toHTTPDateString("%Y-%m-%dT%H-%M-"); + // put this candidate file in our logs directory + auto base = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, basebuff.str()); + S32 sec; + now.split(nullptr, nullptr, nullptr, nullptr, nullptr, &sec); + // Loop over finished filename, incrementing sec until we find one that + // doesn't yet exist. Should rarely loop (only if successive calls within + // same second), may produce (e.g.) sec==61, but avoids collisions and + // preserves chronological filename sort order. + std::string name; + std::error_code ec; + do + { + // base + missing 2-digit seconds, append ".json" + // post-increment sec in case we have to try again + name = stringize(base, std::setw(2), std::setfill('0'), sec++, ".json"); + } while (std::filesystem::exists(fsyspath(name), ec)); + // Ignoring ec means we might potentially return a name that does already + // exist -- but if we can't check its existence, what more can we do? + return name; +} + // WIP simplified copy of display() that does minimal work void display_cube_face() { -- cgit v1.2.3 From e6d0138a6a1ce6dd285fbfedbcf8532bc6aaa29b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 16 Sep 2024 17:25:48 -0400 Subject: Add LLFloaterAbout info (esp. GPU info) to Frame Profile stats dump With the About info added, `getProfileStatsContext()` need not redundantly add `"channel"`, `"version"` or `"region"`. Slightly improve the efficiency of `LlsdToJson()` and `LlsdFromJson()` by preallocating the known size of the source array or map. (Unfortunately the C++ `LLSD` class offers us no way to preallocate a map.) In `LLAppViewer::getViewerInfo()`, avoid immediate successive calls to `gAgent.getRegion()`. (cherry picked from commit f4b65638879c10c832b3bb8448f82001106ffd11) --- indra/newview/llappviewer.cpp | 4 ++-- indra/newview/llviewerdisplay.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 764e52accb..093314a9f1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3285,10 +3285,10 @@ LLSD LLAppViewer::getViewerInfo() const LLVector3d pos = gAgent.getPositionGlobal(); info["POSITION"] = ll_sd_from_vector3d(pos); info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); + info["REGION"] = region->getName(); boost::regex regex("\\.(secondlife|lindenlab)\\..*"); - info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); + info["HOSTNAME"] = boost::regex_replace(region->getSimHostName(), regex, ""); info["SERVER_VERSION"] = gLastVersionChannel; LLSLURL slurl; LLAgentUI::buildSLURL(slurl); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index fdfe477a6c..ae0579f5f7 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -58,6 +58,7 @@ #include "llpostprocess.h" #include "llrender.h" #include "llscenemonitor.h" +#include "llsdjson.h" #include "llselectmgr.h" #include "llsky.h" #include "llspatialpartition.h" @@ -1044,6 +1045,31 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) } } +void getProfileStatsContext(boost::json::object& stats) +{ + // populate the context with info from LLFloaterAbout + auto contextit = stats.emplace("context", + LlsdToJson(LLAppViewer::instance()->getViewerInfo())).first; + auto& context = contextit->value().as_object(); + + // then add a few more things + unsigned char unique_id[MAC_ADDRESS_BYTES]{}; + LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); + context.emplace("machine", stringize(LL::hexdump(unique_id, sizeof(unique_id)))); + context.emplace("grid", LLGridManager::instance().getGrid()); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + context.emplace("regionid", stringize(region->getRegionID())); + } + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + if (parcel) + { + context.emplace("parcel", parcel->getName()); + context.emplace("parcelid", parcel->getLocalID()); + } +} + std::string getProfileStatsFilename() { std::ostringstream basebuff; -- cgit v1.2.3 From d6e10ba4b0e08c29b16ea62e0f8b7d1835418903 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 25 Mar 2024 15:50:47 +0200 Subject: viewer#1016 Incorrect behavior of Physics Shapes rendering --- indra/newview/llphysicsshapebuilderutil.cpp | 385 +++++++++++++++------------- indra/newview/llphysicsshapebuilderutil.h | 2 + 2 files changed, 211 insertions(+), 176 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp index 37534feadc..a79cc984c1 100644 --- a/indra/newview/llphysicsshapebuilderutil.cpp +++ b/indra/newview/llphysicsshapebuilderutil.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llphysicsshapebuilder.cpp * @brief Generic system to convert LL(Physics)VolumeParams to physics shapes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,194 +28,227 @@ #include "llphysicsshapebuilderutil.h" -/* static */ -void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut) -{ - const LLProfileParams& profile_params = volume_params.getProfileParams(); - const LLPathParams& path_params = volume_params.getPathParams(); - - specOut.mScale = scale; - - const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f; +#include "llmeshrepository.h" - // count the scale elements that are small - S32 min_size_counts = 0; - for (S32 i = 0; i < 3; ++i) +bool LLPhysicsVolumeParams::hasDecomposition() const + { + if (!isMeshSculpt()) { - if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) - { - ++min_size_counts; - } + return false; } - const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && - ( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); - - const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && - ( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); - - const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale ) - && ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) - && ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) - && ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() ); - - if (simple_params && profile_complete) + LLUUID mesh_id = getSculptID(); + if (mesh_id.isNull()) { - // Try to create an implicit shape or convexified - bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) - && ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ); - - bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale ) - && ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale); - - // Box - if( - ( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE ) - && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) - && no_taper - && no_twist - ) - { - specOut.mType = PhysicsShapeSpecification::BOX; - if ( path_complete ) - { - return; - } - else - { - // Side lengths - specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); - specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); - specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + return false; + } - specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) ); - return; - } - } + LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); - // Sphere - if( path_complete - && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF ) - && ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE ) - && ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) - && no_twist - ) - { - if ( ( scale[VX] == scale[VZ] ) - && ( scale[VY] == scale[VZ] ) ) - { - // perfect sphere - specOut.mType = PhysicsShapeSpecification::SPHERE; - specOut.mScale = scale; - return; - } - else if (min_size_counts > 1) - { - // small or narrow sphere -- we can boxify - for (S32 i=0; i<3; ++i) - { - if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) - { - // reduce each small dimension size to split the approximation errors - specOut.mScale[i] *= 0.75f; - } - } - specOut.mType = PhysicsShapeSpecification::BOX; - return; - } - } + return decomp != NULL; +} - // Cylinder - if( (scale[VX] == scale[VY]) - && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE ) - && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) - && ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) - && ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ) - && no_taper +/* static */ +void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut) +{ + const LLProfileParams& profile_params = volume_params.getProfileParams(); + const LLPathParams& path_params = volume_params.getPathParams(); + + specOut.mScale = scale; + + const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f; + + // count the scale elements that are small + S32 min_size_counts = 0; + for (S32 i = 0; i < 3; ++i) + { + if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) + { + ++min_size_counts; + } + } + + const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && + ( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); + + const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && + ( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); + + const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale ) + && ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) + && ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) + && ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() ); + + if (simple_params && profile_complete) + { + // Try to create an implicit shape or convexified + bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) + && ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ); + + bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale ) + && ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale); + + // Box + if( + ( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE ) + && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) + && no_taper + && no_twist + ) + { + specOut.mType = PhysicsShapeSpecification::BOX; + if ( path_complete ) + { + return; + } + else + { + // Side lengths + specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + + specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) ); + return; + } + } + + // Sphere + if( path_complete + && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF ) + && ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE ) + && ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) + && no_twist + ) + { + if ( ( scale[VX] == scale[VZ] ) + && ( scale[VY] == scale[VZ] ) ) + { + // perfect sphere + specOut.mType = PhysicsShapeSpecification::SPHERE; + specOut.mScale = scale; + return; + } + else if (min_size_counts > 1) + { + // small or narrow sphere -- we can boxify + for (S32 i=0; i<3; ++i) + { + if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) + { + // reduce each small dimension size to split the approximation errors + specOut.mScale[i] *= 0.75f; + } + } + specOut.mType = PhysicsShapeSpecification::BOX; + return; + } + } + + // Cylinder + if( (scale[VX] == scale[VY]) + && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE ) + && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) + && ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) + && ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ) + && no_taper + ) + { + if (min_size_counts > 1) + { + // small or narrow sphere -- we can boxify + for (S32 i=0; i<3; ++i) + { + if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) + { + // reduce each small dimension size to split the approximation errors + specOut.mScale[i] *= 0.75f; + } + } + + specOut.mType = PhysicsShapeSpecification::BOX; + } + else + { + specOut.mType = PhysicsShapeSpecification::CYLINDER; + F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ]; + + specOut.mScale[VY] = specOut.mScale[VX]; + specOut.mScale[VZ] = length; + // The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1. + specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] ); + } + + return; + } + } + + if ( (min_size_counts == 3 ) + // Possible dead code here--who wants to take it out? + || (path_complete + && profile_complete + && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) + && (min_size_counts > 1 ) ) + ) + { + // it isn't simple but + // we might be able to convexify this shape if the path and profile are complete + // or the path is linear and both path and profile are complete --> we can boxify it + specOut.mType = PhysicsShapeSpecification::BOX; + specOut.mScale = scale; + return; + } + + // Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE + if (min_size_counts == 1 // One dimension is small + && avgScale > 3.f) // ... but others are fairly large + { + for (S32 i = 0; i < 3; ++i) + { + specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE ); + } + } + + if ( volume_params.shouldForceConvex() ) + { + // Server distinguishes between convex of a prim vs isSculpt, but we don't care. + specOut.mType = PhysicsShapeSpecification::USER_CONVEX; + } + // Make a simpler convex shape if we can. + else if (volume_params.isConvex() // is convex + || min_size_counts > 1 ) // two or more small dimensions + { + specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; + } + else if (volume_params.isMeshSculpt()) + { + // Check overall dimensions, not individual triangles. + if (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE + || scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE + || scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE ) { - if (min_size_counts > 1) + if (volume_params.hasDecomposition()) { - // small or narrow sphere -- we can boxify - for (S32 i=0; i<3; ++i) - { - if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) - { - // reduce each small dimension size to split the approximation errors - specOut.mScale[i] *= 0.75f; - } - } - - specOut.mType = PhysicsShapeSpecification::BOX; + specOut.mType = PhysicsShapeSpecification::USER_MESH; } else { - specOut.mType = PhysicsShapeSpecification::CYLINDER; - F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ]; - - specOut.mScale[VY] = specOut.mScale[VX]; - specOut.mScale[VZ] = length; - // The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1. - specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] ); + // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't. + specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; } - - return; } - } - - if ( (min_size_counts == 3 ) - // Possible dead code here--who wants to take it out? - || (path_complete - && profile_complete - && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) - && (min_size_counts > 1 ) ) - ) - { - // it isn't simple but - // we might be able to convexify this shape if the path and profile are complete - // or the path is linear and both path and profile are complete --> we can boxify it - specOut.mType = PhysicsShapeSpecification::BOX; - specOut.mScale = scale; - return; - } - - // Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE - if (min_size_counts == 1 // One dimension is small - && avgScale > 3.f) // ... but others are fairly large - { - for (S32 i = 0; i < 3; ++i) + else { - specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE ); + specOut.mType = PhysicsShapeSpecification::USER_MESH; } } - - if ( volume_params.shouldForceConvex() ) - { - // Server distinguishes between convex of a prim vs isSculpt, but we don't care. - specOut.mType = PhysicsShapeSpecification::USER_CONVEX; - } - // Make a simpler convex shape if we can. - else if (volume_params.isConvex() // is convex - || min_size_counts > 1 ) // two or more small dimensions - { - specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; - } - else if (volume_params.isMeshSculpt() && - // Check overall dimensions, not individual triangles. - (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE || - scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE || - scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE - ) ) - { - // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't. - specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; - } - else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy) - { - specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT; - } - else // Resort to mesh - { - specOut.mType = PhysicsShapeSpecification::PRIM_MESH; - } + else if ( volume_params.isSculpt() ) + { + specOut.mType = PhysicsShapeSpecification::SCULPT; + } + else // Resort to mesh + { + specOut.mType = PhysicsShapeSpecification::PRIM_MESH; + } } diff --git a/indra/newview/llphysicsshapebuilderutil.h b/indra/newview/llphysicsshapebuilderutil.h index 33c2d0a8b6..01c173523b 100644 --- a/indra/newview/llphysicsshapebuilderutil.h +++ b/indra/newview/llphysicsshapebuilderutil.h @@ -79,6 +79,8 @@ public: bool shouldForceConvex() const { return mForceConvex; } + bool hasDecomposition() const; + private: bool mForceConvex; }; -- cgit v1.2.3 From 5370a6d323e14d7b4e32a3f41ef78f7744e361c5 Mon Sep 17 00:00:00 2001 From: Brad Linden <brad@lindenlab.com> Date: Wed, 18 Sep 2024 12:23:14 -0700 Subject: fix whitespace --- indra/newview/llphysicsshapebuilderutil.cpp | 360 ++++++++++++++-------------- 1 file changed, 180 insertions(+), 180 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp index a79cc984c1..eb0df1194e 100644 --- a/indra/newview/llphysicsshapebuilderutil.cpp +++ b/indra/newview/llphysicsshapebuilderutil.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llphysicsshapebuilder.cpp * @brief Generic system to convert LL(Physics)VolumeParams to physics shapes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,175 +51,175 @@ bool LLPhysicsVolumeParams::hasDecomposition() const /* static */ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut) { - const LLProfileParams& profile_params = volume_params.getProfileParams(); - const LLPathParams& path_params = volume_params.getPathParams(); - - specOut.mScale = scale; - - const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f; - - // count the scale elements that are small - S32 min_size_counts = 0; - for (S32 i = 0; i < 3; ++i) - { - if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) - { - ++min_size_counts; - } - } - - const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && - ( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); - - const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && - ( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); - - const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale ) - && ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) - && ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) - && ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() ); - - if (simple_params && profile_complete) - { - // Try to create an implicit shape or convexified - bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) - && ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ); - - bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale ) - && ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale); - - // Box - if( - ( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE ) - && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) - && no_taper - && no_twist - ) - { - specOut.mType = PhysicsShapeSpecification::BOX; - if ( path_complete ) - { - return; - } - else - { - // Side lengths - specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); - specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); - specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); - - specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) ); - return; - } - } - - // Sphere - if( path_complete - && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF ) - && ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE ) - && ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) - && no_twist - ) - { - if ( ( scale[VX] == scale[VZ] ) - && ( scale[VY] == scale[VZ] ) ) - { - // perfect sphere - specOut.mType = PhysicsShapeSpecification::SPHERE; - specOut.mScale = scale; - return; - } - else if (min_size_counts > 1) - { - // small or narrow sphere -- we can boxify - for (S32 i=0; i<3; ++i) - { - if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) - { - // reduce each small dimension size to split the approximation errors - specOut.mScale[i] *= 0.75f; - } - } - specOut.mType = PhysicsShapeSpecification::BOX; - return; - } - } - - // Cylinder - if( (scale[VX] == scale[VY]) - && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE ) - && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) - && ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) - && ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ) - && no_taper - ) - { - if (min_size_counts > 1) - { - // small or narrow sphere -- we can boxify - for (S32 i=0; i<3; ++i) - { - if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) - { - // reduce each small dimension size to split the approximation errors - specOut.mScale[i] *= 0.75f; - } - } - - specOut.mType = PhysicsShapeSpecification::BOX; - } - else - { - specOut.mType = PhysicsShapeSpecification::CYLINDER; - F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ]; - - specOut.mScale[VY] = specOut.mScale[VX]; - specOut.mScale[VZ] = length; - // The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1. - specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] ); - } - - return; - } - } - - if ( (min_size_counts == 3 ) - // Possible dead code here--who wants to take it out? - || (path_complete - && profile_complete - && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) - && (min_size_counts > 1 ) ) - ) - { - // it isn't simple but - // we might be able to convexify this shape if the path and profile are complete - // or the path is linear and both path and profile are complete --> we can boxify it - specOut.mType = PhysicsShapeSpecification::BOX; - specOut.mScale = scale; - return; - } - - // Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE - if (min_size_counts == 1 // One dimension is small - && avgScale > 3.f) // ... but others are fairly large - { - for (S32 i = 0; i < 3; ++i) - { - specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE ); - } - } - - if ( volume_params.shouldForceConvex() ) - { + const LLProfileParams& profile_params = volume_params.getProfileParams(); + const LLPathParams& path_params = volume_params.getPathParams(); + + specOut.mScale = scale; + + const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f; + + // count the scale elements that are small + S32 min_size_counts = 0; + for (S32 i = 0; i < 3; ++i) + { + if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) + { + ++min_size_counts; + } + } + + const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && + ( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); + + const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && + ( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ); + + const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale ) + && ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) + && ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale ) + && ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() ); + + if (simple_params && profile_complete) + { + // Try to create an implicit shape or convexified + bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) + && ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ); + + bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale ) + && ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale); + + // Box + if( + ( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE ) + && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) + && no_taper + && no_twist + ) + { + specOut.mType = PhysicsShapeSpecification::BOX; + if ( path_complete ) + { + return; + } + else + { + // Side lengths + specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE ); + + specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) ); + return; + } + } + + // Sphere + if( path_complete + && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF ) + && ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE ) + && ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale ) + && no_twist + ) + { + if ( ( scale[VX] == scale[VZ] ) + && ( scale[VY] == scale[VZ] ) ) + { + // perfect sphere + specOut.mType = PhysicsShapeSpecification::SPHERE; + specOut.mScale = scale; + return; + } + else if (min_size_counts > 1) + { + // small or narrow sphere -- we can boxify + for (S32 i=0; i<3; ++i) + { + if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) + { + // reduce each small dimension size to split the approximation errors + specOut.mScale[i] *= 0.75f; + } + } + specOut.mType = PhysicsShapeSpecification::BOX; + return; + } + } + + // Cylinder + if( (scale[VX] == scale[VY]) + && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE ) + && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) + && ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) + && ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) ) + && no_taper + ) + { + if (min_size_counts > 1) + { + // small or narrow sphere -- we can boxify + for (S32 i=0; i<3; ++i) + { + if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE) + { + // reduce each small dimension size to split the approximation errors + specOut.mScale[i] *= 0.75f; + } + } + + specOut.mType = PhysicsShapeSpecification::BOX; + } + else + { + specOut.mType = PhysicsShapeSpecification::CYLINDER; + F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ]; + + specOut.mScale[VY] = specOut.mScale[VX]; + specOut.mScale[VZ] = length; + // The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1. + specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] ); + } + + return; + } + } + + if ( (min_size_counts == 3 ) + // Possible dead code here--who wants to take it out? + || (path_complete + && profile_complete + && ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) + && (min_size_counts > 1 ) ) + ) + { + // it isn't simple but + // we might be able to convexify this shape if the path and profile are complete + // or the path is linear and both path and profile are complete --> we can boxify it + specOut.mType = PhysicsShapeSpecification::BOX; + specOut.mScale = scale; + return; + } + + // Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE + if (min_size_counts == 1 // One dimension is small + && avgScale > 3.f) // ... but others are fairly large + { + for (S32 i = 0; i < 3; ++i) + { + specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE ); + } + } + + if ( volume_params.shouldForceConvex() ) + { // Server distinguishes between convex of a prim vs isSculpt, but we don't care. - specOut.mType = PhysicsShapeSpecification::USER_CONVEX; - } - // Make a simpler convex shape if we can. - else if (volume_params.isConvex() // is convex - || min_size_counts > 1 ) // two or more small dimensions - { - specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; - } + specOut.mType = PhysicsShapeSpecification::USER_CONVEX; + } + // Make a simpler convex shape if we can. + else if (volume_params.isConvex() // is convex + || min_size_counts > 1 ) // two or more small dimensions + { + specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; + } else if (volume_params.isMeshSculpt()) { // Check overall dimensions, not individual triangles. @@ -243,12 +243,12 @@ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumePara specOut.mType = PhysicsShapeSpecification::USER_MESH; } } - else if ( volume_params.isSculpt() ) - { + else if ( volume_params.isSculpt() ) + { specOut.mType = PhysicsShapeSpecification::SCULPT; - } - else // Resort to mesh - { - specOut.mType = PhysicsShapeSpecification::PRIM_MESH; - } + } + else // Resort to mesh + { + specOut.mType = PhysicsShapeSpecification::PRIM_MESH; + } } -- cgit v1.2.3 From 52091a6097cd4e68f3fc1b0972080867ceb09122 Mon Sep 17 00:00:00 2001 From: Roxie Linden <roxie@lindenlab.com> Date: Wed, 18 Sep 2024 13:01:43 -0700 Subject: Mute other / set volume level for other is not working. As part of the boost::json conversion, the json that mutes and sets peer gain was not being formed correctly. Also, tweaked the peer gain default. --- indra/newview/llvoicewebrtc.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 3d684e5a1b..aabf897050 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -87,6 +87,8 @@ namespace { const F32 SPEAKING_AUDIO_LEVEL = 0.30; + const uint32_t PEER_GAIN_CONVERSION_FACTOR = 220; + static const std::string REPORTED_VOICE_SERVER_TYPE = "Secondlife WebRTC Gateway"; // Don't send positional updates more frequently than this: @@ -2443,7 +2445,7 @@ void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume) void LLVoiceWebRTCConnection::setUserVolume(const LLUUID& id, F32 volume) { - boost::json::object root = {{"ug", {id.asString(), (uint32_t) (volume * 200)}}}; + boost::json::object root = { { "ug", { { id.asString(), (uint32_t)(volume * PEER_GAIN_CONVERSION_FACTOR) } } } }; std::string json_data = boost::json::serialize(root); if (mWebRTCDataInterface) { @@ -2453,7 +2455,7 @@ void LLVoiceWebRTCConnection::setUserVolume(const LLUUID& id, F32 volume) void LLVoiceWebRTCConnection::setUserMute(const LLUUID& id, bool mute) { - boost::json::object root = {{"m", {id.asString(), mute}}}; + boost::json::object root = { { "m", { { id.asString(), mute } } } }; std::string json_data = boost::json::serialize(root); if (mWebRTCDataInterface) { -- cgit v1.2.3 From b31fd167c00a288656ea82d239a9ce379f382c22 Mon Sep 17 00:00:00 2001 From: Dave Parks <davep@lindenlab.com> Date: Wed, 18 Sep 2024 15:23:20 -0500 Subject: Fix for particles not loading textures (#2598) Also fix assert while prepping GLTF assets --- indra/newview/gltfscenemanager.cpp | 59 ++++++++++++++++++++------------------ indra/newview/llface.cpp | 8 ++++++ 2 files changed, 39 insertions(+), 28 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index ce54fa4c12..ed66753267 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -371,43 +371,46 @@ void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) //static void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status) { - LLViewerObject* obj = (LLViewerObject*)user_data; - llassert(asset_type == LLAssetType::AT_GLTF_BIN); - - if (status == LL_ERR_NOERR) - { - if (obj) + LLAppViewer::instance()->postToMainCoro([=]() { - // find the Buffer with the given id in the asset - if (obj->mGLTFAsset) - { - obj->mGLTFAsset->mPendingBuffers--; - + LLViewerObject* obj = (LLViewerObject*)user_data; + llassert(asset_type == LLAssetType::AT_GLTF_BIN); - if (obj->mGLTFAsset->mPendingBuffers == 0) + if (status == LL_ERR_NOERR) + { + if (obj) { - if (obj->mGLTFAsset->prep()) + // find the Buffer with the given id in the asset + if (obj->mGLTFAsset) { - GLTFSceneManager& mgr = GLTFSceneManager::instance(); - if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end()) + obj->mGLTFAsset->mPendingBuffers--; + + + if (obj->mGLTFAsset->mPendingBuffers == 0) { - GLTFSceneManager::instance().mObjects.push_back(obj); + if (obj->mGLTFAsset->prep()) + { + GLTFSceneManager& mgr = GLTFSceneManager::instance(); + if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end()) + { + GLTFSceneManager::instance().mObjects.push_back(obj); + } + } + else + { + LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL; + obj->mGLTFAsset = nullptr; + } } } - else - { - LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL; - obj->mGLTFAsset = nullptr; - } } } - } - } - else - { - LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; - obj->unref(); - } + else + { + LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; + obj->unref(); + } + }); } //static diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index ce68474211..297661effd 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -2268,6 +2268,14 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) center.mul(0.5f); size.setSub(mRiggedExtents[1], mRiggedExtents[0]); } + else if (mDrawablep && mVObjp.notNull() && mVObjp->getPartitionType() == LLViewerRegion::PARTITION_PARTICLE && mDrawablep->getSpatialGroup()) + { // use box of spatial group for particles (over approximates size, but we don't actually have a good size per particle) + LLSpatialGroup* group = mDrawablep->getSpatialGroup(); + const LLVector4a* extents = group->getExtents(); + size.setSub(extents[1], extents[0]); + center.setAdd(extents[1], extents[0]); + center.mul(0.5f); + } else { center.load3(getPositionAgent().mV); -- cgit v1.2.3 From 743a1a6d8eabf069d95777c96e5b657cb8702593 Mon Sep 17 00:00:00 2001 From: Roxie Linden <roxie@lindenlab.com> Date: Wed, 18 Sep 2024 14:14:26 -0700 Subject: fix trailing whitespace --- indra/newview/llvoicewebrtc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index aabf897050..ad8f6927ed 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2445,7 +2445,7 @@ void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume) void LLVoiceWebRTCConnection::setUserVolume(const LLUUID& id, F32 volume) { - boost::json::object root = { { "ug", { { id.asString(), (uint32_t)(volume * PEER_GAIN_CONVERSION_FACTOR) } } } }; + boost::json::object root = { { "ug", { { id.asString(), (uint32_t)(volume * PEER_GAIN_CONVERSION_FACTOR) } } } }; std::string json_data = boost::json::serialize(root); if (mWebRTCDataInterface) { -- cgit v1.2.3 From 9fa95dd0b21f323b7d8f60a826bcc128ad4e7ef2 Mon Sep 17 00:00:00 2001 From: Brad Linden <46733234+brad-linden@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:53:36 -0700 Subject: Fix crash in LLImProcessing when message comes in before region is fully init (#2604) secondlife/viewer#2603 --- indra/newview/llimprocessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index c1e68e0288..590cd09a31 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -488,7 +488,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, case IM_NOTHING_SPECIAL: // p2p IM // Don't show dialog, just do IM if (!gAgent.isGodlike() - && gAgent.getRegion()->isPrelude() + && gAgent.inPrelude() && to_id.isNull()) { // do nothing -- don't distract newbies in -- cgit v1.2.3 From 2fd18ee162824e449dc893c66d7dd8c56518ee7c Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:21:22 +0200 Subject: Fix copy&paste error in llfloaterimagepreview.cpp (#2596) --- indra/newview/llfloaterimagepreview.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 236725bd45..989e1d8d04 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -288,18 +288,18 @@ void LLFloaterImagePreview::draw() gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mBottom); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); - gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mTop); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); } gGL.end(); @@ -325,18 +325,18 @@ void LLFloaterImagePreview::draw() gGL.begin(LLRender::TRIANGLES); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); } gGL.end(); -- cgit v1.2.3 From ee3645ac961aec171cc56ec962723ac5fd28cf38 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:22:48 +0200 Subject: Fix possible dereferencing of nullptr in llglsandbox.cpp (#2597) --- indra/newview/llglsandbox.cpp | 120 ++++++------------------------------------ 1 file changed, 17 insertions(+), 103 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 731e711cd1..af025d5879 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -68,7 +68,7 @@ #include <vector> // Height of the yellow selection highlight posts for land -const F32 PARCEL_POST_HEIGHT = 0.666f; +constexpr F32 PARCEL_POST_HEIGHT = 0.666f; // Returns true if you got at least one object void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) @@ -178,27 +178,27 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) { std::vector<LLDrawable*> potentials; - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + for (LLViewerRegion* region : LLWorld::getInstance()->getRegionList()) { - LLViewerRegion* region = *iter; for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) + if (LLSpatialPartition* part = region->getSpatialPartition(i)) { part->cull(*LLViewerCamera::getInstance(), &potentials, true); } } } - for (std::vector<LLDrawable*>::iterator iter = potentials.begin(); - iter != potentials.end(); iter++) + for (LLDrawable* drawable : potentials) { - LLDrawable* drawable = *iter; + if (!drawable) + { + continue; + } + LLViewerObject* vobjp = drawable->getVObj(); - if (!drawable || !vobjp || + if (!vobjp || vobjp->getPCode() != LL_PCODE_VOLUME || vobjp->isAttachment() || (deselect && !vobjp->isSelected())) @@ -244,7 +244,7 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) gViewerWindow->setup3DRender(); } -const F32 WIND_RELATIVE_ALTITUDE = 25.f; +constexpr F32 WIND_RELATIVE_ALTITUDE = 25.f; void LLWind::renderVectors() { @@ -266,14 +266,14 @@ void LLWind::renderVectors() x = mVelX[i + j*mSize] * WIND_SCALE_HACK; y = mVelY[i + j*mSize] * WIND_SCALE_HACK; gGL.pushMatrix(); - gGL.translatef((F32)i * region_width_meters/mSize, (F32)j * region_width_meters/mSize, 0.0); - gGL.color3f(0,1,0); + gGL.translatef((F32)i * region_width_meters/mSize, (F32)j * region_width_meters/mSize, 0.f); + gGL.color3f(0.f, 1.f, 0.f); gGL.begin(LLRender::POINTS); - gGL.vertex3f(0,0,0); + gGL.vertex3f(0.f, 0.f, 0.f); gGL.end(); - gGL.color3f(1,0,0); + gGL.color3f(1.f, 0.f, 0.f); gGL.begin(LLRender::LINES); - gGL.vertex3f(x * 0.1f, y * 0.1f ,0.f); + gGL.vertex3f(x * 0.1f, y * 0.1f, 0.f); gGL.vertex3f(x, y, 0.f); gGL.end(); gGL.popMatrix(); @@ -287,7 +287,7 @@ void LLWind::renderVectors() // Used by lltoolselectland void LLViewerParcelMgr::renderRect(const LLVector3d &west_south_bottom_global, - const LLVector3d &east_north_top_global ) + const LLVector3d &east_north_top_global) { LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -356,92 +356,6 @@ void LLViewerParcelMgr::renderRect(const LLVector3d &west_south_bottom_global, LLUI::setLineWidth(1.f); } -/* -void LLViewerParcelMgr::renderParcel(LLParcel* parcel ) -{ - S32 i; - S32 count = parcel->getBoxCount(); - for (i = 0; i < count; i++) - { - const LLParcelBox& box = parcel->getBox(i); - - F32 west = box.mMin.mV[VX]; - F32 south = box.mMin.mV[VY]; - - F32 east = box.mMax.mV[VX]; - F32 north = box.mMax.mV[VY]; - - // HACK: At edge of last region of world, we need to make sure the region - // resolves correctly so we can get a height value. - const F32 FUDGE = 0.01f; - - F32 sw_bottom = LLWorld::getInstance()->resolveLandHeightAgent( LLVector3( west, south, 0.f ) ); - F32 se_bottom = LLWorld::getInstance()->resolveLandHeightAgent( LLVector3( east-FUDGE, south, 0.f ) ); - F32 ne_bottom = LLWorld::getInstance()->resolveLandHeightAgent( LLVector3( east-FUDGE, north-FUDGE, 0.f ) ); - F32 nw_bottom = LLWorld::getInstance()->resolveLandHeightAgent( LLVector3( west, north-FUDGE, 0.f ) ); - - // little hack to make nearby lines not Z-fight - east -= 0.1f; - north -= 0.1f; - - F32 sw_top = sw_bottom + POST_HEIGHT; - F32 se_top = se_bottom + POST_HEIGHT; - F32 ne_top = ne_bottom + POST_HEIGHT; - F32 nw_top = nw_bottom + POST_HEIGHT; - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest gls_depth(GL_TRUE); - - LLUI::setLineWidth(2.f); - gGL.color4f(0.f, 1.f, 1.f, 1.f); - - // Cheat and give this the same pick-name as land - gGL.begin(LLRender::LINES); - - gGL.vertex3f(west, north, nw_bottom); - gGL.vertex3f(west, north, nw_top); - - gGL.vertex3f(east, north, ne_bottom); - gGL.vertex3f(east, north, ne_top); - - gGL.vertex3f(east, south, se_bottom); - gGL.vertex3f(east, south, se_top); - - gGL.vertex3f(west, south, sw_bottom); - gGL.vertex3f(west, south, sw_top); - - gGL.end(); - - gGL.color4f(0.f, 1.f, 1.f, 0.2f); - gGL.begin(LLRender::QUADS); - - gGL.vertex3f(west, north, nw_bottom); - gGL.vertex3f(west, north, nw_top); - gGL.vertex3f(east, north, ne_top); - gGL.vertex3f(east, north, ne_bottom); - - gGL.vertex3f(east, north, ne_bottom); - gGL.vertex3f(east, north, ne_top); - gGL.vertex3f(east, south, se_top); - gGL.vertex3f(east, south, se_bottom); - - gGL.vertex3f(east, south, se_bottom); - gGL.vertex3f(east, south, se_top); - gGL.vertex3f(west, south, sw_top); - gGL.vertex3f(west, south, sw_bottom); - - gGL.vertex3f(west, south, sw_bottom); - gGL.vertex3f(west, south, sw_top); - gGL.vertex3f(west, north, nw_top); - gGL.vertex3f(west, north, nw_bottom); - - gGL.end(); - - LLUI::setLineWidth(1.f); - } -} -*/ - // north = a wall going north/south. Need that info to set up texture // coordinates correctly. -- cgit v1.2.3 From 6d842ac0af814a088c56f437dc885e4ce58b61a8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 18 Sep 2024 17:11:03 +0300 Subject: Expose LLVector4a in LLRender Avoid using a bunch of allocators. Make sure we use LLVector4a's SSE logic instead of LLVector3's. Some minor optimizations. --- indra/newview/llviewermedia.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9739cac311..4e7416bb63 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -688,10 +688,10 @@ void LLViewerMedia::updateMedia(void *dummy_arg) static LLCachedControl<bool> inworld_media_enabled(gSavedSettings, "AudioStreamingMedia", true); static LLCachedControl<bool> inworld_audio_enabled(gSavedSettings, "AudioStreamingMusic", true); - U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); - U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); - U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); - F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + static LLCachedControl<U32> max_instances(gSavedSettings, "PluginInstancesTotal", 8); + static LLCachedControl<U32> max_normal(gSavedSettings, "PluginInstancesNormal", 2); + static LLCachedControl<U32> max_low(gSavedSettings, "PluginInstancesLow", 4); + static LLCachedControl<F32> max_cpu(gSavedSettings, "PluginInstancesCPULimit", 0.9); // Setting max_cpu to 0.0 disables CPU usage checking. bool check_cpu_usage = (max_cpu != 0.0f); @@ -829,7 +829,8 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } else { - if(gAudiop && LLViewerMedia::hasParcelAudio() && restore_parcel_audio && gSavedSettings.getBOOL("MediaTentativeAutoPlay")) + static LLCachedControl<bool> auto_play(gSavedSettings, "MediaTentativeAutoPlay", true); + if(gAudiop && LLViewerMedia::hasParcelAudio() && restore_parcel_audio && auto_play()) { LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getParcelAudioURL()); restore_parcel_audio = false; @@ -880,7 +881,8 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } } - if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) + static LLCachedControl<bool> perf_debug(gSavedSettings, "MediaPerformanceManagerDebug", false); + if(perf_debug()) { // Give impls the same ordering as the priority list // they're already in the right order for this. -- cgit v1.2.3 From 8c40e6f0a9e211ec22331385dc66b5ff5233859c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 19 Sep 2024 11:46:08 -0400 Subject: Reapply commit f4b6563 -- cherry-picking lost parts of it?! --- indra/newview/llviewerdisplay.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index ae0579f5f7..f722d0bd1d 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -139,6 +139,7 @@ void render_ui_3d(); void render_ui_2d(); void render_disconnected_background(); +void getProfileStatsContext(boost::json::object& stats); std::string getProfileStatsFilename(); void display_startup() @@ -1041,7 +1042,21 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) if (gShaderProfileFrame) { gShaderProfileFrame = false; - LLGLSLShader::finishProfile(getProfileStatsFilename()); + boost::json::value stats{ boost::json::object_kind }; + getProfileStatsContext(stats.as_object()); + LLGLSLShader::finishProfile(stats); + + auto report_name = getProfileStatsFilename(); + std::ofstream outf(report_name); + if (! outf) + { + LL_WARNS() << "Couldn't write to " << std::quoted(report_name) << LL_ENDL; + } + else + { + outf << stats; + LL_INFOS() << "(also dumped to " << std::quoted(report_name) << ")" << LL_ENDL; + } } } @@ -1068,6 +1083,7 @@ void getProfileStatsContext(boost::json::object& stats) context.emplace("parcel", parcel->getName()); context.emplace("parcelid", parcel->getLocalID()); } + context.emplace("time", LLDate::now().toHTTPDateString("%Y-%m-%dT%H:%M:%S")); } std::string getProfileStatsFilename() -- cgit v1.2.3 From 7e4cdc30f3af701eb34306c124f1ce32f60c14ef Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Thu, 19 Sep 2024 20:34:33 +0300 Subject: Don't keep updating snapshot preview when the floater is closed --- indra/newview/llfloatersnapshot.cpp | 3 ++- indra/newview/llsnapshotlivepreview.cpp | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 1f52f1d180..fb4537f22a 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1297,7 +1297,8 @@ bool LLFloaterSnapshotBase::ImplBase::updatePreviewList(bool initialized) void LLFloaterSnapshotBase::ImplBase::updateLivePreview() { - if (ImplBase::updatePreviewList(true) && mFloater) + // don't update preview for hidden floater + if (mFloater && mFloater->isInVisibleChain() && ImplBase::updatePreviewList(true)) { LL_DEBUGS() << "changed" << LL_ENDL; updateControls(mFloater); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index e996cc87fc..0d0c025db0 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -690,18 +690,25 @@ bool LLSnapshotLivePreview::onIdle( void* snapshot_preview ) return false; } + static LLCachedControl<bool> auto_snapshot(gSavedSettings, "AutoSnapshot", false); + static LLCachedControl<bool> freeze_time(gSavedSettings, "FreezeTime", false); + static LLCachedControl<bool> use_freeze_frame(gSavedSettings, "UseFreezeFrame", false); + static LLCachedControl<bool> render_ui(gSavedSettings, "RenderUIInSnapshot", false); + static LLCachedControl<bool> render_hud(gSavedSettings, "RenderHUDInSnapshot", false); + static LLCachedControl<bool> render_no_post(gSavedSettings, "RenderSnapshotNoPost", false); + // If we're in freeze-frame and/or auto update mode and camera has moved, update snapshot. LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin(); LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion(); if (previewp->mForceUpdateSnapshot || - (((gSavedSettings.getBOOL("AutoSnapshot") && LLView::isAvailable(previewp->mViewContainer)) || - (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview)) && + (((auto_snapshot && LLView::isAvailable(previewp->mViewContainer)) || + (freeze_time && previewp->mAllowFullScreenPreview)) && (new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f))) { previewp->mCameraPos = new_camera_pos; previewp->mCameraRot = new_camera_rot; // request a new snapshot whenever the camera moves, with a time delay - bool new_snapshot = gSavedSettings.getBOOL("AutoSnapshot") || previewp->mForceUpdateSnapshot; + bool new_snapshot = auto_snapshot || previewp->mForceUpdateSnapshot; LL_DEBUGS("Snapshot") << "camera moved, updating thumbnail" << LL_ENDL; previewp->updateSnapshot( new_snapshot, // whether a new snapshot is needed or merely invalidate the existing one @@ -739,10 +746,10 @@ bool LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->getHeight(), previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), previewp->getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE, - previewp->mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), - gSavedSettings.getBOOL("RenderHUDInSnapshot"), + previewp->mAllowRenderUI && render_ui, + render_hud, false, - gSavedSettings.getBOOL("RenderSnapshotNoPost"), + render_no_post, previewp->mSnapshotBufferType, previewp->getMaxImageSize())) { @@ -754,7 +761,7 @@ bool LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->estimateDataSize(); // Full size preview is set: get the decoded image result and save it for animation - if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview) + if (use_freeze_frame && previewp->mAllowFullScreenPreview) { previewp->prepareFreezeFrame(); } @@ -767,7 +774,7 @@ bool LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->generateThumbnailImage(true) ; } previewp->getWindow()->decBusyCount(); - previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode + previewp->setVisible(use_freeze_frame && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode previewp->mSnapshotActive = false; LL_DEBUGS("Snapshot") << "done creating snapshot" << LL_ENDL; } -- cgit v1.2.3 From 25969b330e4dc69f6eb39a487b171ccc07a5df14 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 19 Sep 2024 20:11:17 +0300 Subject: viewer#2608 Crash at LLSnapshotLivePreview::getFormattedImage --- indra/newview/llsnapshotlivepreview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 0d0c025db0..ea95d71b27 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -894,7 +894,9 @@ LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage() else { // Update mFormattedImage if necessary - getFormattedImage(); + lock.unlock(); + getFormattedImage(); // will apply filters to mPreviewImage with a lock + lock.lock(); if (getSnapshotFormat() == LLSnapshotModel::SNAPSHOT_FORMAT_BMP) { // BMP hack : copy instead of decode otherwise decode will crash. -- cgit v1.2.3 From 50513bab2d6b1823f983c145553b8a6af44c2f28 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Thu, 19 Sep 2024 15:00:37 -0400 Subject: Make login.lua enhance plain grid='agni' to required form. --- indra/newview/scripts/lua/require/login.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/require/login.lua b/indra/newview/scripts/lua/require/login.lua index 919434f3a5..37c9093a21 100644 --- a/indra/newview/scripts/lua/require/login.lua +++ b/indra/newview/scripts/lua/require/login.lua @@ -18,16 +18,25 @@ local function ensure_login_state(op) end end +local function fullgrid(grid) + if string.find(grid, '.', 1, true) then + return grid + else + return `util.{grid}.secondlife.com` + end +end + function login.login(...) ensure_login_state('login') local args = mapargs('username,grid,slurl', ...) args.op = 'login' + args.grid = fullgrid(args.grid) return leap.request('LLPanelLogin', args) end function login.savedLogins(grid) ensure_login_state('savedLogins') - return leap.request('LLPanelLogin', {op='savedLogins', grid=grid})['logins'] + return leap.request('LLPanelLogin', {op='savedLogins', grid=fullgrid(grid)})['logins'] end return login -- cgit v1.2.3 From 71fcf45584d7f418f60047eb212ed2a474b39861 Mon Sep 17 00:00:00 2001 From: Brad Linden <brad@lindenlab.com> Date: Thu, 19 Sep 2024 12:05:27 -0700 Subject: Incremented viewer version after release/2024.09-ExtraFPS branch creation --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index e0eaaa0bbc..0f9f025fe4 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.11 +7.1.12 -- cgit v1.2.3 From cae279b6e1019319f9186c2cea1127b9df149a7b Mon Sep 17 00:00:00 2001 From: Cosmic Linden <cosmic@lindenlab.com> Date: Wed, 11 Sep 2024 17:10:48 -0700 Subject: secondlife/viewer#2462: Optimize unloading of prims --- indra/newview/llmeshrepository.cpp | 81 ++++++++++++++++++++++++++++++++++-- indra/newview/llmeshrepository.h | 7 +++- indra/newview/llviewerobjectlist.cpp | 5 +++ indra/newview/llvovolume.cpp | 27 +++++++++++- indra/newview/llvovolume.h | 1 + 5 files changed, 116 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 26e2d8f319..2ca94390e5 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3651,20 +3651,95 @@ S32 LLMeshRepository::update() return static_cast<S32>(size); } -void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) +#ifdef SHOW_ASSERT +// Brute-force remove the object from all loading queues. Returns true if +// something was removed. +// This function is used in a debug assert to ensure unregisterMesh and +// unregisterSkinInfo are called as intended. +// *TODO: Consider removing at some point if we feel confident about the code +// working as intended. +bool LLMeshRepository::forceUnregisterMesh(LLVOVolume* vobj) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + bool found = false; + for (auto& lod : mLoadingMeshes) { for (auto& param : lod) { - vector_replace_with_last(param.second, vobj); + llassert(std::find(param.second.begin(), param.second.end(), vobj) == param.second.end()); + found = found || vector_replace_with_last(param.second, vobj); } } for (auto& skin_pair : mLoadingSkins) { - vector_replace_with_last(skin_pair.second, vobj); + llassert(std::find(skin_pair.second.begin(), skin_pair.second.end(), vobj) == skin_pair.second.end()); + found = found || vector_replace_with_last(skin_pair.second, vobj); + } + + return found; +} +#endif + +void LLMeshRepository::unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + llassert((mesh_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH); + llassert(mesh_params.getSculptID().notNull()); + auto& lod = mLoadingMeshes[detail]; + auto param_iter = lod.find(mesh_params.getSculptID()); + if (param_iter != lod.end()) + { + vector_replace_with_last(param_iter->second, vobj); + llassert(!vector_replace_with_last(param_iter->second, vobj)); + if (param_iter->second.empty()) + { + lod.erase(param_iter); + } + } +} + +void LLMeshRepository::unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + llassert(mesh_id.notNull()); + auto skin_pair_iter = mLoadingSkins.find(mesh_id); + if (skin_pair_iter != mLoadingSkins.end()) + { + vector_replace_with_last(skin_pair_iter->second, vobj); + llassert(!vector_replace_with_last(skin_pair_iter->second, vobj)); + if (skin_pair_iter->second.empty()) + { + mLoadingSkins.erase(skin_pair_iter); + } + } +} + +// Lots of dead objects make expensive calls to +// LLMeshRepository::unregisterMesh which may delay shutdown. Avoid this by +// preemptively unregistering all meshes. +// We can also do this safely if all objects are confirmed dead for some other +// reason. +void LLMeshRepository::unregisterAllMeshes() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + // The size of mLoadingMeshes and mLoadingSkins may be large and thus + // expensive to iterate over in LLVOVolume::~LLVOVolume. + // This is unnecessary during shutdown, so we ignore the referenced objects in the + // least expensive way which is still safe: by clearing these containers. + // Clear now and not in LLMeshRepository::shutdown because + // LLMeshRepository::notifyLoadedMeshes could (depending on invocation + // order) reference a pointer to an object after it has been deleted. + for (auto& lod : mLoadingMeshes) + { + lod.clear(); } + mLoadingSkins.clear(); } S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index b850ade0bb..b8bec7f233 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -632,10 +632,15 @@ public: LLMeshRepository(); void init(); + void unregisterAllMeshes(); void shutdown(); S32 update(); - void unregisterMesh(LLVOVolume* volume); +#ifdef SHOW_ASSERT + bool forceUnregisterMesh(LLVOVolume* volume); +#endif + void unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail); + void unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj); //mesh management functions S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 9e1d86faac..6167129077 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -65,6 +65,7 @@ #include "lltoolmgr.h" #include "lltoolpie.h" #include "llkeyboard.h" +#include "llmeshrepository.h" #include "u64.h" #include "llviewertexturelist.h" #include "lldatapacker.h" @@ -1419,6 +1420,10 @@ void LLViewerObjectList::cleanDeadObjects(bool use_timer) // No dead objects, don't need to scan object list. return; } + if ((LLApp::isExiting()) || (mNumDeadObjects == (S32)mObjects.size())) + { + gMeshRepo.unregisterAllMeshes(); + } LL_PROFILE_ZONE_SCOPED; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 7da4358f86..2f2054355a 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -250,10 +250,13 @@ LLVOVolume::~LLVOVolume() delete mVolumeImpl; mVolumeImpl = NULL; - gMeshRepo.unregisterMesh(this); + unregisterOldMeshAndSkin(); + llassert(!gMeshRepo.forceUnregisterMesh(this)); if(!mMediaImplList.empty()) { + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("delete volume media list"); + for(U32 i = 0 ; i < mMediaImplList.size() ; i++) { if(mMediaImplList[i].notNull()) @@ -998,6 +1001,28 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) return mDrawable; } +// Inverse of gMeshRepo.loadMesh and gMeshRepo.getSkinInfo, combined into one function +// Assume a Collada mesh never changes after being set. +void LLVOVolume::unregisterOldMeshAndSkin() +{ + if (mVolumep) + { + const LLVolumeParams& params = mVolumep->getParams(); + if ((params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { + // object is being deleted, so it will no longer need to request + // meshes. + for (S32 lod = 0; lod != LLVolumeLODGroup::NUM_LODS; ++lod) + { + gMeshRepo.unregisterMesh(this, params, lod); + } + // This volume may or may not have a skin + gMeshRepo.unregisterSkinInfo(params.getSculptID(), this); + } + } +} + + bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 6241bf42d6..dfd75aa7d0 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -227,6 +227,7 @@ public: void setTexture(const S32 face); S32 getIndexInTex(U32 ch) const {return mIndexInTex[ch];} + void unregisterOldMeshAndSkin(); /*virtual*/ bool setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false) override; void updateSculptTexture(); void setIndexInTex(U32 ch, S32 index) { mIndexInTex[ch] = index ;} -- cgit v1.2.3 From 89106b98a104afc0fb68412cfdf00f8e3e008fd0 Mon Sep 17 00:00:00 2001 From: Cosmic Linden <cosmic@lindenlab.com> Date: Thu, 19 Sep 2024 17:34:28 -0700 Subject: secondlife/viewer#2623: Remove assert --- indra/newview/llmeshrepository.cpp | 32 -------------------------------- indra/newview/llmeshrepository.h | 3 --- indra/newview/llvovolume.cpp | 1 - 3 files changed, 36 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2ca94390e5..61ccd355a1 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3651,38 +3651,6 @@ S32 LLMeshRepository::update() return static_cast<S32>(size); } -#ifdef SHOW_ASSERT -// Brute-force remove the object from all loading queues. Returns true if -// something was removed. -// This function is used in a debug assert to ensure unregisterMesh and -// unregisterSkinInfo are called as intended. -// *TODO: Consider removing at some point if we feel confident about the code -// working as intended. -bool LLMeshRepository::forceUnregisterMesh(LLVOVolume* vobj) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - - bool found = false; - - for (auto& lod : mLoadingMeshes) - { - for (auto& param : lod) - { - llassert(std::find(param.second.begin(), param.second.end(), vobj) == param.second.end()); - found = found || vector_replace_with_last(param.second, vobj); - } - } - - for (auto& skin_pair : mLoadingSkins) - { - llassert(std::find(skin_pair.second.begin(), skin_pair.second.end(), vobj) == skin_pair.second.end()); - found = found || vector_replace_with_last(skin_pair.second, vobj); - } - - return found; -} -#endif - void LLMeshRepository::unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index b8bec7f233..6e10493e90 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -636,9 +636,6 @@ public: void shutdown(); S32 update(); -#ifdef SHOW_ASSERT - bool forceUnregisterMesh(LLVOVolume* volume); -#endif void unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail); void unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj); //mesh management functions diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2f2054355a..e1eface4e8 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -251,7 +251,6 @@ LLVOVolume::~LLVOVolume() mVolumeImpl = NULL; unregisterOldMeshAndSkin(); - llassert(!gMeshRepo.forceUnregisterMesh(this)); if(!mMediaImplList.empty()) { -- cgit v1.2.3 From c3215c1bb07adee2ff6a546e97d4e42165e74b60 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 20 Sep 2024 00:01:25 +0300 Subject: viewer#2576 Crash baning a resident --- indra/newview/llpanelgroupbulk.cpp | 32 +++++++++++--------------------- indra/newview/llpanelgroupbulkban.cpp | 33 ++++++++++++--------------------- indra/newview/llpanelgroupbulkimpl.h | 3 ++- 3 files changed, 25 insertions(+), 43 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp index 433db74cda..8032e207cd 100644 --- a/indra/newview/llpanelgroupbulk.cpp +++ b/indra/newview/llpanelgroupbulk.cpp @@ -56,6 +56,7 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) : mGroupID(group_id), mBulkAgentList(NULL), mOKButton(NULL), + mAddButton(nullptr), mRemoveButton(NULL), mGroupName(NULL), mLoadingText(), @@ -79,29 +80,18 @@ LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl() } } -// static -void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata) +void LLPanelGroupBulkImpl::callbackClickAdd(LLPanelGroupBulk* panelp) { - if (LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata) - { - // Right now this is hard coded with some knowledge that it is part - // of a floater since the avatar picker needs to be added as a dependent - // floater to the parent floater. - // Soon the avatar picker will be embedded into this panel - // instead of being it's own separate floater. But that is next week. - // This will do for now. -jwolk May 10, 2006 - LLView* button = panelp->findChild<LLButton>("add_button"); - LLFloater* root_floater = gFloaterView->getParentFloater(panelp); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( - [&](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&) - { - panelp->mImplementation->addUsers(agent_ids); - }, true, false, false, root_floater->getName(), button); - if (picker) + LLFloater* root_floater = gFloaterView->getParentFloater(panelp); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( + [this](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&) { - root_floater->addDependentFloater(picker); - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(panelp->mImplementation->mGroupID); - } + addUsers(agent_ids); + }, true, false, false, root_floater->getName(), mAddButton); + if (picker) + { + root_floater->addDependentFloater(picker); + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); } } diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp index 3c764887a6..1d3edad0f3 100644 --- a/indra/newview/llpanelgroupbulkban.cpp +++ b/indra/newview/llpanelgroupbulkban.cpp @@ -68,35 +68,26 @@ bool LLPanelGroupBulkBan::postBuild() mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation); } - LLButton* button = getChild<LLButton>("add_button", recurse); - if ( button ) + mImplementation->mAddButton = getChild<LLButton>("add_button", recurse); + // default to opening avatarpicker automatically + mImplementation->mAddButton->setClickedCallback( + [this](LLUICtrl* ctrl, const LLSD& param) { - // default to opening avatarpicker automatically - // (*impl::callbackClickAdd)((void*)this); - button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this); - } + mImplementation->callbackClickAdd(this); + }); mImplementation->mRemoveButton = getChild<LLButton>("remove_button", recurse); - if ( mImplementation->mRemoveButton ) - { - mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); - mImplementation->mRemoveButton->setEnabled(false); - } + mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); + mImplementation->mRemoveButton->setEnabled(false); mImplementation->mOKButton = getChild<LLButton>("ban_button", recurse); - if ( mImplementation->mOKButton ) - { - mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this); - mImplementation->mOKButton->setEnabled(false); - } + mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this); + mImplementation->mOKButton->setEnabled(false); - button = getChild<LLButton>("cancel_button", recurse); - if ( button ) - { - button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); - } + LLButton* button = getChild<LLButton>("cancel_button", recurse); + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); mImplementation->mTooManySelected = getString("ban_selection_too_large"); mImplementation->mBanNotPermitted = getString("ban_not_permitted"); diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h index 5a479f8117..5515bd6d9a 100644 --- a/indra/newview/llpanelgroupbulkimpl.h +++ b/indra/newview/llpanelgroupbulkimpl.h @@ -44,7 +44,7 @@ public: LLPanelGroupBulkImpl(const LLUUID& group_id); ~LLPanelGroupBulkImpl(); - static void callbackClickAdd(void* userdata); + void callbackClickAdd(LLPanelGroupBulk* panelp); static void callbackClickRemove(void* userdata); static void callbackClickCancel(void* userdata); @@ -70,6 +70,7 @@ public: LLNameListCtrl* mBulkAgentList; LLButton* mOKButton; + LLButton* mAddButton; LLButton* mRemoveButton; LLTextBox* mGroupName; -- cgit v1.2.3 From 4f5d58dd036d06c88c552b8d8ac57dbb1e0b45ac Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Thu, 19 Sep 2024 19:30:05 +0200 Subject: #1519 ObjectGrab message includes invalid SurfaceInfo data when in mouselook mode --- indra/newview/lltoolselect.cpp | 9 ++++----- indra/newview/llviewerwindow.cpp | 16 ++++++++-------- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index 5ccda7d4eb..3bd459f5b0 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -55,17 +55,17 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite ) : LLTool( std::string("Select"), composite ), mIgnoreGroup( false ) { - } +} // True if you selected an object. bool LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask) { // do immediate pick query bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); - bool pick_transparent = gSavedSettings.getBOOL("SelectInvisibleObjects"); - bool pick_reflection_probe = gSavedSettings.getBOOL("SelectReflectionProbes"); + static LLCachedControl<bool> select_invisible_objects(gSavedSettings, "SelectInvisibleObjects"); + static LLCachedControl<bool> select_reflection_probes(gSavedSettings, "SelectReflectionProbes"); - mPick = gViewerWindow->pickImmediate(x, y, pick_transparent, pick_rigged, false, true, pick_reflection_probe); + mPick = gViewerWindow->pickImmediate(x, y, select_invisible_objects, pick_rigged, false, true, select_reflection_probes); // Pass mousedown to agent LLTool::handleMouseDown(x, y, mask); @@ -73,7 +73,6 @@ bool LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask) return mPick.getObject().notNull(); } - // static LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pick, bool ignore_group, bool temp_select, bool select_root) { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 0e7d82fd90..acb2c85ef8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4255,15 +4255,15 @@ void LLViewerWindow::pickAsync( S32 x, bool pick_unselectable, bool pick_reflection_probes) { + static LLCachedControl<bool> select_invisible_objects(gSavedSettings, "SelectInvisibleObjects"); // "Show Debug Alpha" means no object actually transparent bool in_build_mode = LLFloaterReg::instanceVisible("build"); - if (LLDrawPoolAlpha::sShowDebugAlpha - || (in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects"))) + if (LLDrawPoolAlpha::sShowDebugAlpha || (in_build_mode && select_invisible_objects)) { pick_transparent = true; } - LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, pick_unselectable, true, callback); + LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, true, pick_unselectable, callback); schedulePick(pick_info); } @@ -4287,7 +4287,6 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info) mWindow->delayInputProcessing(); } - void LLViewerWindow::performPick() { if (!mPicks.empty()) @@ -4321,8 +4320,9 @@ void LLViewerWindow::returnEmptyPicks() // Performs the GL object/land pick. LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transparent, bool pick_rigged, bool pick_particle, bool pick_unselectable, bool pick_reflection_probe) { + static LLCachedControl<bool> select_invisible_objects(gSavedSettings, "SelectInvisibleObjects"); bool in_build_mode = LLFloaterReg::instanceVisible("build"); - if ((in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")) || LLDrawPoolAlpha::sShowDebugAlpha) + if ((in_build_mode && select_invisible_objects) || LLDrawPoolAlpha::sShowDebugAlpha) { // build mode allows interaction with all transparent objects // "Show Debug Alpha" means no object actually transparent @@ -4330,7 +4330,7 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transp } // shortcut queueing in mPicks and just update mLastPick in place - MASK key_mask = gKeyboard->currentMask(true); + MASK key_mask = gKeyboard->currentMask(true); mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_rigged, pick_particle, pick_reflection_probe, true, false, NULL); mLastPick.fetchResults(); @@ -6050,14 +6050,14 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, bool pick_rigged, bool pick_particle, bool pick_reflection_probe, - bool pick_uv_coords, + bool pick_surface_info, bool pick_unselectable, void (*pick_callback)(const LLPickInfo& pick_info)) : mMousePt(mouse_pos), mKeyMask(keyboard_mask), mPickCallback(pick_callback), mPickType(PICK_INVALID), - mWantSurfaceInfo(pick_uv_coords), + mWantSurfaceInfo(pick_surface_info), mObjectFace(-1), mUVCoords(-1.f, -1.f), mSTCoords(-1.f, -1.f), -- cgit v1.2.3 From fad8b11f480a7e7fc8cae38e0f76de2109a46a99 Mon Sep 17 00:00:00 2001 From: Rye Cogtail <rye@lindenlab.com> Date: Fri, 20 Sep 2024 12:10:06 -0400 Subject: Fix sky settings with reflection probe ambiance of 0 still receiving tonemapping --- indra/newview/pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 14a15eb59f..fe02742aac 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7070,7 +7070,7 @@ void LLPipeline::tonemap(LLRenderTarget* src, LLRenderTarget* dst) LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - bool no_post = gSnapshotNoPost || (buildNoPost && gFloaterTools->isAvailable()); + bool no_post = gSnapshotNoPost || psky->getReflectionProbeAmbiance(should_auto_adjust) == 0.f || (buildNoPost && gFloaterTools->isAvailable()); LLGLSLShader& shader = no_post ? gNoPostTonemapProgram : gDeferredPostTonemapProgram; shader.bind(); -- cgit v1.2.3 From 0e33882b15e0c970e216d1cca4b93a7702e5113b Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Fri, 20 Sep 2024 19:07:02 +0200 Subject: Restore option to change location of existing pick (#2622) --- indra/newview/llpanelprofilepicks.cpp | 42 ++++++++++++++++++++++ indra/newview/llpanelprofilepicks.h | 10 +++++- .../skins/default/xui/en/panel_profile_pick.xml | 20 +++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 08f3d3af5a..11a10ebd2c 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -246,6 +246,8 @@ void LLPanelProfilePicks::onClickNewBtn() select_tab(true). label(pick_panel->getPickName())); updateButtons(); + + pick_panel->addLocationChangedCallbacks(); } void LLPanelProfilePicks::onClickDelete() @@ -571,10 +573,12 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id) { mPickName->setEnabled(true); mPickDescription->setEnabled(true); + mSetCurrentLocationButton->setVisible(true); } else { mSnapshotCtrl->setEnabled(false); + mSetCurrentLocationButton->setVisible(false); } } @@ -585,6 +589,7 @@ bool LLPanelProfilePick::postBuild() mSaveButton = getChild<LLButton>("save_changes_btn"); mCreateButton = getChild<LLButton>("create_changes_btn"); mCancelButton = getChild<LLButton>("cancel_changes_btn"); + mSetCurrentLocationButton = getChild<LLButton>("set_to_curr_location_btn"); mSnapshotCtrl = getChild<LLTextureCtrl>("pick_snapshot"); mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this)); @@ -597,6 +602,7 @@ bool LLPanelProfilePick::postBuild() mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); mCreateButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); mCancelButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickCancel, this)); + mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this)); mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL); mPickName->setEnabled(false); @@ -759,6 +765,32 @@ bool LLPanelProfilePick::isDirty() const return false; } +void LLPanelProfilePick::onClickSetLocation() +{ + // Save location for later use. + setPosGlobal(gAgent.getPositionGlobal()); + + std::string parcel_name, region_name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + mParcelId = parcel->getID(); + parcel_name = parcel->getName(); + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal())); + + mLocationChanged = true; + enableSaveButton(true); +} + void LLPanelProfilePick::onClickSave() { if (mRegionCallbackConnection.connected()) @@ -769,6 +801,10 @@ void LLPanelProfilePick::onClickSave() { mParcelCallbackConnection.disconnect(); } + if (mLocationChanged) + { + onClickSetLocation(); + } sendUpdate(); mLocationChanged = false; @@ -816,6 +852,12 @@ void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data) } } +void LLPanelProfilePick::addLocationChangedCallbacks() +{ + mRegionCallbackConnection = gAgent.addRegionChangedCallback([this]() { onClickSetLocation(); }); + mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onClickSetLocation(); }); +} + void LLPanelProfilePick::sendUpdate() { LLPickData pick_data; diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index e3f50f5576..5e5d4ff81e 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -138,6 +138,8 @@ public: void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; } void setErrorStatus(S32 status, const std::string& reason) override {}; + void addLocationChangedCallbacks(); + protected: /** @@ -199,6 +201,11 @@ public: */ void resetDirty() override; + /** + * Callback for "Set Location" button click + */ + void onClickSetLocation(); + /** * Callback for "Save" and "Create" button click */ @@ -221,6 +228,7 @@ protected: LLTextureCtrl* mSnapshotCtrl; LLLineEditor* mPickName; LLTextEditor* mPickDescription; + LLButton* mSetCurrentLocationButton; LLButton* mSaveButton; LLButton* mCreateButton; LLButton* mCancelButton; @@ -236,7 +244,7 @@ protected: bool mLocationChanged; bool mNewPick; - bool mIsEditing; + bool mIsEditing; void onDescriptionFocusReceived(); }; diff --git a/indra/newview/skins/default/xui/en/panel_profile_pick.xml b/indra/newview/skins/default/xui/en/panel_profile_pick.xml index 024120931f..4f441b9b49 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_pick.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_pick.xml @@ -198,6 +198,26 @@ /> </layout_panel> + <layout_panel + follows="all" + layout="bottomleft" + left_pad="2" + name="set_to_curr_location_btn_lp" + auto_resize="false" + width="100"> + <button + name="set_to_curr_location_btn" + label="Set Location" + tool_tip="Set to Current Location" + left="0" + top="0" + height="23" + width="100" + follows="left|top" + layout="topleft" + /> + </layout_panel> + <layout_panel follows="all" layout="topleft" -- cgit v1.2.3 From 6d29beb91b019e1995cdb7c4aaf7a043de4bf053 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 20 Sep 2024 15:13:43 -0400 Subject: Add ability to pass command-line arguments to a Lua script. Introduce `ScriptCommand` class that parses a command line into a script name and optional args, using bash-like quoting and escaping. `ScriptCommand` searches for a file with that script name on a passed list of directories; the directories may be specified relative to a particular base directory. `ScriptCommand` supports the special case of a script name containing unescaped spaces. It guarantees that either the returned script file exists, or its `error()` string is non-empty. Replace `LLLeap::create()` logic, from which `ScriptCommand` was partly derived, with a `ScriptCommand` instance. Make `LLLUAmanager::runScriptFile()` use a `ScriptCommand` instance to parse the passed command line. Subsume `LLAppViewer::init()` script-path-searching logic for `--luafile` into `ScriptCommand`. In fact that lambda now simply calls `LLLUAmanager::runScriptFile()`. Make `lluau::dostring()` accept an optional vector of script argument strings. Following PUC-Rio Lua convention, pass these arguments into a Lua script as the predefined global `arg`, and also as the script's `...` argument. `LuaState::expr()` also accepts and passes through script argument strings. Change the log tag for the Lua script interruption message: if we want it, we can still enable it, but we don't necessarily want it along with all other "Lua" DEBUG messages. Remove `LuaState::script_finished_fn`, which isn't used any more. Also remove the corresponding `LLLUAmanager::script_finished_fn`. This allows us to simplify `~LuaState()` slightly, as well as the parameter signatures for `LLLUAmanager::runScriptFile()` and `runScriptLine()`. --- indra/newview/llappviewer.cpp | 26 +++---------- indra/newview/llluamanager.cpp | 83 ++++++++++++------------------------------ indra/newview/llluamanager.h | 22 +++++++---- 3 files changed, 44 insertions(+), 87 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 789aaab70d..a9ac48ac88 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1234,23 +1234,8 @@ bool LLAppViewer::init() "--luafile", "LuaScript", [](const LLSD& script) { - LLSD paths(gSavedSettings.getLLSD("LuaCommandPath")); - LL_DEBUGS("Lua") << "LuaCommandPath = " << paths << LL_ENDL; - for (const auto& path : llsd::inArray(paths)) - { - // if script path is already absolute, operator/() preserves it - auto abspath(fsyspath(gDirUtilp->getAppRODataDir()) / path.asString()); - auto absscript{ (abspath / script.asString()) }; - std::error_code ec; - if (std::filesystem::exists(absscript, ec)) - { - // no completion callback: we don't need to know - LLLUAmanager::runScriptFile(absscript.u8string()); - return; // from lambda - } - } - LL_WARNS("Lua") << "--luafile " << std::quoted(script.asString()) - << " not found on " << paths << LL_ENDL; + // no completion callback: we don't need to know + LLLUAmanager::runScriptFile(script); }); processComposeSwitch( "LuaAutorunPath", "LuaAutorunPath", @@ -1259,15 +1244,16 @@ bool LLAppViewer::init() // each directory can be relative to the viewer's install // directory -- if directory is already absolute, operator/() // preserves it - auto abspath(fsyspath(gDirUtilp->getAppRODataDir()) / directory.asString()); - std::string absdir(abspath.string()); + fsyspath abspath(fsyspath(gDirUtilp->getAppRODataDir()) / + fsyspath(directory.asString())); + std::string absdir(fsyspath(abspath).string()); LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << LL_ENDL; LLDirIterator scripts(absdir, "*.lua"); std::string script; while (scripts.next(script)) { LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << ": " << script << LL_ENDL; - LLLUAmanager::runScriptFile((abspath / script).string(), true); + LLLUAmanager::runScriptFile(fsyspath(abspath / fsyspath(script)).string(), true); } }); diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c4ce07e492..046526ac3c 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -186,75 +186,41 @@ LLLUAmanager::script_result LLLUAmanager::waitScriptFile(const std::string& file } void LLLUAmanager::runScriptFile(const std::string &filename, bool autorun, - script_result_fn result_cb, script_finished_fn finished_cb) + script_result_fn result_cb) { // A script_result_fn will be called when LuaState::expr() completes. - LLCoros::instance().launch(filename, [filename, autorun, result_cb, finished_cb]() + LLCoros::instance().launch(filename, [filename, autorun, result_cb]() { ScriptObserver observer(LLCoros::getName(), filename); - // Use LLStringUtil::getTokens() to parse the script command line - auto tokens = LLStringUtil::getTokens(filename, - " \t\r\n", // drop_delims - "", // no keep_delims - "\"'", // either kind of quotes - "\\"); // backslash escape - -#error Under construction - // TODO: - // - Move this either/or file existence logic to LuaCommand() - // - Accept LuaCommand in all LLLUAmanager::mumbleScriptFile() methods - // - Update all existing mumbleScriptFile() callers - - llifstream in_file; - in_file.open(tokens[0]); - if (in_file.is_open()) - { - // The first token is in fact the script filename. Now that the - // script file is open, we've consumed that token. The rest are - // command-line arguments. - tokens.erase(tokens.begin()); - } - else + LLSD paths(gSavedSettings.getLLSD("LuaCommandPath")); + LL_DEBUGS("Lua") << "LuaCommandPath = " << paths << LL_ENDL; + // allow LuaCommandPath to be specified relative to install dir + ScriptCommand command(filename, paths, gDirUtilp->getAppRODataDir()); + auto error = command.error(); + if (! error.empty()) { - // Parsing the command line produced a script file path we can't - // open. Maybe that's because there are spaces in the original - // pathname that were neither quoted nor escaped? See if we can - // open the whole original command line string. - in_file.open(filename); - if (! in_file.is_open()) + if (result_cb) { - std::ostringstream msgstream; - msgstream << "Can't open script file " << std::quoted(tokens[0]); - if (filename != tokens[0]) - { - msgstream << " or " << std::quoted(filename); - } - auto msg = msgstream.str(); - LL_WARNS("Lua") << msg << LL_ENDL; - if (result_cb) - { - result_cb(-1, msg); - } - return; + result_cb(-1, error); } - // Here we do have in_file open, using the whole input command - // line as its pathname. Discard any parts of it we mistook for - // command-line arguments. - tokens.clear(); - } + return; + } - // Here in_file is open. + llifstream in_file; + in_file.open(command.script); + // At this point, since ScriptCommand did not report an error, we + // should be able to assume that 'script' exists. If we can't open it, + // something else is wrong?! + llassert(in_file.is_open()); if (autorun) { sAutorunScriptCount++; } sScriptCount++; - // A script_finished_fn is used to initialize the LuaState. - // It will be called when the LuaState is destroyed. - LuaState L(finished_cb); + LuaState L; std::string text{std::istreambuf_iterator<char>(in_file), {}}; - auto [count, result] = L.expr(filename, text, tokens); + auto [count, result] = L.expr(command.script, text, command.args); if (result_cb) { result_cb(count, result); @@ -279,8 +245,7 @@ LLLUAmanager::script_result LLLUAmanager::waitScriptLine(const std::string& chun return startScriptLine(chunk).get(); } -void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn result_cb, - script_finished_fn finished_cb) +void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn result_cb) { // find a suitable abbreviation for the chunk string std::string shortchunk{ chunk }; @@ -292,11 +257,9 @@ void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn resu shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); std::string desc{ "lua: " + shortchunk }; - LLCoros::instance().launch(desc, [desc, chunk, result_cb, finished_cb]() + LLCoros::instance().launch(desc, [desc, chunk, result_cb]() { - // A script_finished_fn is used to initialize the LuaState. - // It will be called when the LuaState is destroyed. - LuaState L(finished_cb); + LuaState L; auto [count, result] = L.expr(desc, chunk); if (result_cb) { diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index df76ddd3e2..b98b5d4ef6 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -44,9 +44,6 @@ class LLLUAmanager friend class ScriptObserver; public: - // Pass a callback with this signature to obtain the error message, if - // any, from running a script or source string. Empty msg means success. - typedef std::function<void(std::string msg)> script_finished_fn; // Pass a callback with this signature to obtain the result, if any, of // running a script or source string. // count < 0 means error, and result.asString() is the error message. @@ -58,20 +55,31 @@ public: // same semantics as script_result_fn parameters typedef std::pair<int, LLSD> script_result; - static void runScriptFile(const std::string &filename, bool autorun = false, script_result_fn result_cb = {}, - script_finished_fn finished_cb = {}); + // Run the script specified by the command line passed as @a filename. + // This can be followed by some number of command-line arguments, which + // a Lua script can view using either '...' or predefined global 'arg'. + // The script pathname or its arguments can be quoted using 'single + // quotes' or "double quotes", or special characters can be \escaped. + // runScriptFile() recognizes the case in which the whole 'filename' + // string is a path containing spaces; if so no arguments are permitted. + // In either form, if the script pathname isn't absolute, it is sought on + // LuaCommandPath. + // If autorun is true, statistics will count this as an autorun script. + static void runScriptFile(const std::string &filename, bool autorun = false, + script_result_fn result_cb = {}); // Start running a Lua script file, returning an LLCoros::Future whose // get() method will pause the calling coroutine until it can deliver the // (count, result) pair described above. Between startScriptFile() and // Future::get(), the caller and the Lua script coroutine will run // concurrently. + // @a filename is as described for runScriptFile(). static LLCoros::Future<script_result> startScriptFile(const std::string& filename); // Run a Lua script file, and pause the calling coroutine until it completes. // The return value is the (count, result) pair described above. + // @a filename is as described for runScriptFile(). static script_result waitScriptFile(const std::string& filename); - static void runScriptLine(const std::string &chunk, script_result_fn result_cb = {}, - script_finished_fn finished_cb = {}); + static void runScriptLine(const std::string &chunk, script_result_fn result_cb = {}); // Start running a Lua chunk, returning an LLCoros::Future whose // get() method will pause the calling coroutine until it can deliver the // (count, result) pair described above. Between startScriptLine() and -- cgit v1.2.3 From 65379a3b1784209193fda64fa6e99cfb9b87c340 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Fri, 20 Sep 2024 16:39:13 -0400 Subject: Fix trailing spaces. --- indra/newview/llluamanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 046526ac3c..7fe5c1ece0 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -204,7 +204,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, bool autorun, result_cb(-1, error); } return; - } + } llifstream in_file; in_file.open(command.script); -- cgit v1.2.3 From c0739e04d484d039e7c154b9303a92aa0abe42e9 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Sat, 21 Sep 2024 02:29:49 +0200 Subject: Improve inventory finder floater performance: Don't parse XUI tree each frame (#2640) --- indra/newview/llinventoryfilter.cpp | 6 +- indra/newview/llinventoryfilter.h | 2 +- indra/newview/llpanelmaininventory.cpp | 248 ++++++++++++++++++--------------- 3 files changed, 140 insertions(+), 116 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 5c0905af3c..01f2c6c525 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -959,7 +959,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) boost::char_separator<char> sep("+"); tokenizer tokens(filter_sub_string_new, sep); - for (auto token_iter : tokens) + for (const auto& token_iter : tokens) { mFilterTokens.push_back(token_iter); } @@ -1025,7 +1025,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) } // Cancel out UUID once the search string is modified - if (mFilterOps.mFilterTypes == FILTERTYPE_UUID) + if (mFilterOps.mFilterTypes & FILTERTYPE_UUID) { mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; mFilterOps.mFilterUUID = LLUUID::null; @@ -1707,7 +1707,7 @@ std::string LLInventoryFilter::getEmptyLookupMessage(bool is_empty_folder) const } } -bool LLInventoryFilter::areDateLimitsSet() +bool LLInventoryFilter::areDateLimitsSet() const { return mFilterOps.mMinDate != time_min() || mFilterOps.mMaxDate != time_max() diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 7e64a03e73..612a161ba2 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -341,7 +341,7 @@ public: bool checkAgainstFilterThumbnails(const LLUUID& object_id) const; private: - bool areDateLimitsSet(); + bool areDateLimitsSet() const; bool checkAgainstFilterSubString(const std::string& desc) const; bool checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const; bool checkAgainstFilterType(const LLInventoryItem* item) const; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 377af4384a..de6358666b 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -78,9 +78,9 @@ static LLPanelInjector<LLPanelMainInventory> t_inventory("panel_main_inventory") class LLFloaterInventoryFinder : public LLFloater { public: - LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view); - virtual void draw(); - /*virtual*/ bool postBuild(); + LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view); + void draw(); + bool postBuild(); void changeFilter(LLInventoryFilter* filter); void updateElementsFromFilter(); bool getCheckShowEmpty(); @@ -90,17 +90,35 @@ public: void onCreatorSelfFilterCommit(); void onCreatorOtherFilterCommit(); - static void onTimeAgo(LLUICtrl*, void *); - static void onCloseBtn(void* user_data); - static void selectAllTypes(void* user_data); - static void selectNoTypes(void* user_data); + void onTimeAgo(); + void onCloseBtn(); + void selectAllTypes(); + void selectNoTypes(); private: - LLPanelMainInventory* mPanelMainInventory; - LLSpinCtrl* mSpinSinceDays; - LLSpinCtrl* mSpinSinceHours; - LLCheckBoxCtrl* mCreatorSelf; - LLCheckBoxCtrl* mCreatorOthers; - LLInventoryFilter* mFilter; + LLPanelMainInventory* mPanelMainInventory{ nullptr }; + LLSpinCtrl* mSpinSinceDays{ nullptr }; + LLSpinCtrl* mSpinSinceHours{ nullptr }; + LLCheckBoxCtrl* mCreatorSelf{ nullptr }; + LLCheckBoxCtrl* mCreatorOthers{ nullptr }; + LLInventoryFilter* mFilter{ nullptr }; + + LLCheckBoxCtrl* mCheckAnimation{ nullptr }; + LLCheckBoxCtrl* mCheckCallingCard{ nullptr }; + LLCheckBoxCtrl* mCheckClothing{ nullptr }; + LLCheckBoxCtrl* mCheckGesture{ nullptr }; + LLCheckBoxCtrl* mCheckLandmark{ nullptr }; + LLCheckBoxCtrl* mCheckMaterial{ nullptr }; + LLCheckBoxCtrl* mCheckNotecard{ nullptr }; + LLCheckBoxCtrl* mCheckObject{ nullptr }; + LLCheckBoxCtrl* mCheckScript{ nullptr }; + LLCheckBoxCtrl* mCheckSounds{ nullptr }; + LLCheckBoxCtrl* mCheckTexture{ nullptr }; + LLCheckBoxCtrl* mCheckSnapshot{ nullptr }; + LLCheckBoxCtrl* mCheckSettings{ nullptr }; + LLCheckBoxCtrl* mCheckShowEmpty{ nullptr }; + LLCheckBoxCtrl* mCheckSinceLogoff{ nullptr }; + + LLRadioGroup* mRadioDateSearchDirection{ nullptr }; }; ///---------------------------------------------------------------------------- @@ -734,7 +752,6 @@ bool LLPanelMainInventory::filtersVisible(void* user_data) void LLPanelMainInventory::onClearSearch() { bool initially_active = false; - LLFloater *finder = getFinder(); if (mActivePanel && (getActivePanel() != mWornItemsPanel)) { initially_active = mActivePanel->getFilter().isNotDefault(); @@ -743,9 +760,9 @@ void LLPanelMainInventory::onClearSearch() mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS); } - if (finder) + if (LLFloaterInventoryFinder* finder = getFinder()) { - LLFloaterInventoryFinder::selectAllTypes(finder); + finder->selectAllTypes(); } // re-open folders that were initially open in case filter was active @@ -1145,36 +1162,53 @@ bool LLFloaterInventoryFinder::postBuild() const LLRect& viewrect = mPanelMainInventory->getRect(); setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); - childSetAction("All", selectAllTypes, this); - childSetAction("None", selectNoTypes, this); + childSetAction("All", [this](LLUICtrl*, const LLSD&) { selectAllTypes(); }); + childSetAction("None", [this](LLUICtrl*, const LLSD&) { selectNoTypes(); }); mSpinSinceHours = getChild<LLSpinCtrl>("spin_hours_ago"); - childSetCommitCallback("spin_hours_ago", onTimeAgo, this); + mSpinSinceHours->setCommitCallback([this](LLUICtrl*, const LLSD&) { onTimeAgo(); }); mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago"); - childSetCommitCallback("spin_days_ago", onTimeAgo, this); + mSpinSinceDays->setCommitCallback([this](LLUICtrl*, const LLSD&) { onTimeAgo(); }); mCreatorSelf = getChild<LLCheckBoxCtrl>("check_created_by_me"); mCreatorOthers = getChild<LLCheckBoxCtrl>("check_created_by_others"); mCreatorSelf->setCommitCallback(boost::bind(&LLFloaterInventoryFinder::onCreatorSelfFilterCommit, this)); mCreatorOthers->setCommitCallback(boost::bind(&LLFloaterInventoryFinder::onCreatorOtherFilterCommit, this)); - childSetAction("Close", onCloseBtn, this); + mCheckAnimation = getChild<LLCheckBoxCtrl>("check_animation"); + mCheckCallingCard = getChild<LLCheckBoxCtrl>("check_calling_card"); + mCheckClothing = getChild<LLCheckBoxCtrl>("check_clothing"); + mCheckGesture = getChild<LLCheckBoxCtrl>("check_gesture"); + mCheckLandmark = getChild<LLCheckBoxCtrl>("check_landmark"); + mCheckMaterial = getChild<LLCheckBoxCtrl>("check_material"); + mCheckNotecard = getChild<LLCheckBoxCtrl>("check_notecard"); + mCheckObject = getChild<LLCheckBoxCtrl>("check_object"); + mCheckScript = getChild<LLCheckBoxCtrl>("check_script"); + mCheckSounds = getChild<LLCheckBoxCtrl>("check_sound"); + mCheckTexture = getChild<LLCheckBoxCtrl>("check_texture"); + mCheckSnapshot = getChild<LLCheckBoxCtrl>("check_snapshot"); + mCheckSettings = getChild<LLCheckBoxCtrl>("check_settings"); + mCheckShowEmpty = getChild<LLCheckBoxCtrl>("check_show_empty"); + mCheckSinceLogoff = getChild<LLCheckBoxCtrl>("check_since_logoff"); + + mRadioDateSearchDirection = getChild<LLRadioGroup>("date_search_direction"); + + childSetAction("Close", [this](LLUICtrl*, const LLSD&) { onCloseBtn(); }); updateElementsFromFilter(); + return true; } -void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) -{ - LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; - if (!self) return; - if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) +void LLFloaterInventoryFinder::onTimeAgo() +{ + if (mSpinSinceDays->get() || mSpinSinceHours->get()) { - self->getChild<LLUICtrl>("check_since_logoff")->setValue(false); + mCheckSinceLogoff->setValue(false); - U32 days = (U32)self->mSpinSinceDays->get(); - U32 hours = (U32)self->mSpinSinceHours->get(); + U32 days = (U32)mSpinSinceDays->get(); + U32 hours = (U32)mSpinSinceHours->get(); if (hours >= 24) { // Try to handle both cases of spinner clicking and text input in a sensible fashion as best as possible. @@ -1190,11 +1224,11 @@ void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) days = hours / 24; } hours = (U32)hours % 24; - self->mSpinSinceHours->setFocus(false); - self->mSpinSinceDays->setFocus(false); - self->mSpinSinceDays->set((F32)days); - self->mSpinSinceHours->set((F32)hours); - self->mSpinSinceHours->setFocus(true); + mSpinSinceHours->setFocus(false); + mSpinSinceDays->setFocus(false); + mSpinSinceDays->set((F32)days); + mSpinSinceHours->set((F32)hours); + mSpinSinceHours->setFocus(true); } } } @@ -1223,29 +1257,28 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() // update the ui elements setTitle(mFilter->getName()); - getChild<LLUICtrl>("check_animation")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); - - getChild<LLUICtrl>("check_calling_card")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); - getChild<LLUICtrl>("check_clothing")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); - getChild<LLUICtrl>("check_gesture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); - getChild<LLUICtrl>("check_landmark")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); - getChild<LLUICtrl>("check_material")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL)); - getChild<LLUICtrl>("check_notecard")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); - getChild<LLUICtrl>("check_object")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); - getChild<LLUICtrl>("check_script")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); - getChild<LLUICtrl>("check_sound")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); - getChild<LLUICtrl>("check_texture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); - getChild<LLUICtrl>("check_snapshot")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); - getChild<LLUICtrl>("check_settings")->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS)); - getChild<LLUICtrl>("check_show_empty")->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); - - getChild<LLUICtrl>("check_created_by_me")->setValue(show_created_by_me); - getChild<LLUICtrl>("check_created_by_others")->setValue(show_created_by_others); - - getChild<LLUICtrl>("check_since_logoff")->setValue(mFilter->isSinceLogoff()); + mCheckAnimation->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); + mCheckCallingCard->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); + mCheckClothing->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); + mCheckGesture->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); + mCheckLandmark->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); + mCheckMaterial->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL)); + mCheckNotecard->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); + mCheckObject->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); + mCheckScript->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); + mCheckSounds->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); + mCheckTexture->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); + mCheckSnapshot->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); + mCheckSettings->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS)); + mCheckShowEmpty->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); + + mCreatorSelf->setValue(show_created_by_me); + mCreatorOthers->setValue(show_created_by_others); + + mCheckSinceLogoff->setValue(mFilter->isSinceLogoff()); mSpinSinceHours->set((F32)(hours % 24)); mSpinSinceDays->set((F32)(hours / 24)); - getChild<LLRadioGroup>("date_search_direction")->setSelectedIndex(date_search_direction); + mRadioDateSearchDirection->setSelectedIndex(date_search_direction); } void LLFloaterInventoryFinder::draw() @@ -1253,80 +1286,80 @@ void LLFloaterInventoryFinder::draw() U64 filter = 0xffffffffffffffffULL; bool filtered_by_all_types = true; - if (!getChild<LLUICtrl>("check_animation")->getValue()) + if (!mCheckAnimation->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_calling_card")->getValue()) + if (!mCheckCallingCard->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_clothing")->getValue()) + if (!mCheckClothing->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_gesture")->getValue()) + if (!mCheckGesture->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_GESTURE); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_landmark")->getValue()) + if (!mCheckLandmark->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_material")->getValue()) + if (!mCheckMaterial->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_MATERIAL); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_notecard")->getValue()) + if (!mCheckNotecard->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_object")->getValue()) + if (!mCheckObject->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_OBJECT); filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_script")->getValue()) + if (!mCheckScript->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_LSL); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_sound")->getValue()) + if (!mCheckSounds->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_SOUND); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_texture")->getValue()) + if (!mCheckTexture->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_snapshot")->getValue()) + if (!mCheckSnapshot->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); filtered_by_all_types = false; } - if (!getChild<LLUICtrl>("check_settings")->getValue()) + if (!mCheckSettings->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_SETTINGS); filtered_by_all_types = false; @@ -1444,65 +1477,56 @@ void LLFloaterInventoryFinder::onCreatorOtherFilterCommit() bool LLFloaterInventoryFinder::getCheckShowEmpty() { - return getChild<LLUICtrl>("check_show_empty")->getValue(); + return mCheckShowEmpty->getValue(); } bool LLFloaterInventoryFinder::getCheckSinceLogoff() { - return getChild<LLUICtrl>("check_since_logoff")->getValue(); + return mCheckSinceLogoff->getValue(); } U32 LLFloaterInventoryFinder::getDateSearchDirection() { - return getChild<LLRadioGroup>("date_search_direction")->getSelectedIndex(); + return mRadioDateSearchDirection->getSelectedIndex(); } -void LLFloaterInventoryFinder::onCloseBtn(void* user_data) +void LLFloaterInventoryFinder::onCloseBtn() { - LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; - finderp->closeFloater(); + closeFloater(); } -// static -void LLFloaterInventoryFinder::selectAllTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - self->getChild<LLUICtrl>("check_animation")->setValue(true); - self->getChild<LLUICtrl>("check_calling_card")->setValue(true); - self->getChild<LLUICtrl>("check_clothing")->setValue(true); - self->getChild<LLUICtrl>("check_gesture")->setValue(true); - self->getChild<LLUICtrl>("check_landmark")->setValue(true); - self->getChild<LLUICtrl>("check_material")->setValue(true); - self->getChild<LLUICtrl>("check_notecard")->setValue(true); - self->getChild<LLUICtrl>("check_object")->setValue(true); - self->getChild<LLUICtrl>("check_script")->setValue(true); - self->getChild<LLUICtrl>("check_sound")->setValue(true); - self->getChild<LLUICtrl>("check_texture")->setValue(true); - self->getChild<LLUICtrl>("check_snapshot")->setValue(true); - self->getChild<LLUICtrl>("check_settings")->setValue(true); +void LLFloaterInventoryFinder::selectAllTypes() +{ + mCheckAnimation->setValue(true); + mCheckCallingCard->setValue(true); + mCheckClothing->setValue(true); + mCheckGesture->setValue(true); + mCheckLandmark->setValue(true); + mCheckMaterial->setValue(true); + mCheckNotecard->setValue(true); + mCheckObject->setValue(true); + mCheckScript->setValue(true); + mCheckSounds->setValue(true); + mCheckTexture->setValue(true); + mCheckSnapshot->setValue(true); + mCheckSettings->setValue(true); } -//static -void LLFloaterInventoryFinder::selectNoTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - self->getChild<LLUICtrl>("check_animation")->setValue(false); - self->getChild<LLUICtrl>("check_calling_card")->setValue(false); - self->getChild<LLUICtrl>("check_clothing")->setValue(false); - self->getChild<LLUICtrl>("check_gesture")->setValue(false); - self->getChild<LLUICtrl>("check_landmark")->setValue(false); - self->getChild<LLUICtrl>("check_material")->setValue(false); - self->getChild<LLUICtrl>("check_notecard")->setValue(false); - self->getChild<LLUICtrl>("check_object")->setValue(false); - self->getChild<LLUICtrl>("check_script")->setValue(false); - self->getChild<LLUICtrl>("check_sound")->setValue(false); - self->getChild<LLUICtrl>("check_texture")->setValue(false); - self->getChild<LLUICtrl>("check_snapshot")->setValue(false); - self->getChild<LLUICtrl>("check_settings")->setValue(false); +void LLFloaterInventoryFinder::selectNoTypes() +{ + mCheckAnimation->setValue(false); + mCheckCallingCard->setValue(false); + mCheckClothing->setValue(false); + mCheckGesture->setValue(false); + mCheckLandmark->setValue(false); + mCheckMaterial->setValue(false); + mCheckNotecard->setValue(false); + mCheckObject->setValue(false); + mCheckScript->setValue(false); + mCheckSounds->setValue(false); + mCheckTexture->setValue(false); + mCheckSnapshot->setValue(false); + mCheckSettings->setValue(false); } ////////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From fa4ea5b47967739ec7e7201609b4be57cb1130a5 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Sat, 21 Sep 2024 19:54:02 +0200 Subject: #2618 Roles and Members tab is a mess (fix XML indents for readability) --- .../skins/default/xui/en/panel_group_roles.xml | 1187 ++++++++++---------- 1 file changed, 593 insertions(+), 594 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 02e135a2c7..33f98b37ea 100644 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -18,7 +18,7 @@ <panel.string name="help_text" /> <tab_container - border="false" + border="false" follows="left|top|right" height="552" halign="center" @@ -65,16 +65,16 @@ clicking on their names. name="power_partial_icon" translate="false"> Checkbox_Off </panel.string> - <filter_editor - layout="topleft" - top="5" - left="5" - right="-5" - height="22" - search_button_visible="false" - follows="left|top|right" - label="Filter Members" - name="filter_input" /> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Members" + name="filter_input" /> <name_list column_padding="2" draw_heading="true" @@ -90,11 +90,11 @@ clicking on their names. <name_list.columns label="Member" name="name" - relative_width="0.44" /> + relative_width="0.44" /> <name_list.columns label="Donation" name="donated" - relative_width="0.2" /> + relative_width="0.2" /> <name_list.columns label="Status" name="online" @@ -118,13 +118,13 @@ clicking on their names. left_pad="10" name="member_eject" width="100" /> - <button - height="23" - label="Ban Member(s)" - follows="top|left" - left_pad="10" - name="member_ban" - width="100" /> + <button + height="23" + label="Ban Member(s)" + follows="top|left" + left_pad="10" + name="member_ban" + width="100" /> </panel> <panel border="false" @@ -136,7 +136,7 @@ clicking on their names. help_topic="roles_roles_tab" name="roles_sub_tab" class="panel_group_roles_subtab"> - <!-- <button + <!--<button enabled="false" height="20" label="Show All" @@ -145,411 +145,410 @@ clicking on their names. right="-5" name="show_all_button" width="100" />--> - <panel.string - name="help_text"> - Roles have a title and an allowed list of Abilities - that Members can perform. Members can belong to - one or more Roles. A group can have up to 10 Roles, - including the Everyone and Owner Roles. - </panel.string> - <panel.string - name="cant_delete_role"> - The 'Everyone' and 'Owners' Roles are special and can't be deleted. - </panel.string> - <panel.string - name="power_folder_icon" translate="false"> - Inv_FolderClosed - </panel.string> - <panel.string - name="power_all_have_icon" translate="false"> - Checkbox_On - </panel.string> - <panel.string - name="power_partial_icon" translate="false"> - Checkbox_Off - </panel.string> - <filter_editor - layout="topleft" - top="5" - left="5" - right="-5" - height="22" - search_button_visible="false" - follows="left|top|right" - label="Filter Roles" - name="filter_input" /> - <scroll_list - column_padding="0" - draw_heading="true" - draw_stripes="false" - heading_height="23" - height="132" - layout="topleft" - search_column="1" - left="0" - follows="left|top|right" - right="-1" - name="role_list" - top_pad="2" - width="310"> - <scroll_list.columns - label="Role" - name="name" - relative_width="0.45" /> - <scroll_list.columns - label="Title" - name="title" - relative_width="0.45" /> - <scroll_list.columns - label="#" - name="members" - relative_width="0.15" /> - </scroll_list> - <button - follows="top|left" - height="23" - label="New Role" - layout="topleft" - left="0" - name="role_create" - width="100" /> - <button - follows="top|left" - height="23" - label="Copy Role" - layout="topleft" - left_pad="10" - name="role_copy" - width="100" /> - <button - height="23" - follows="top|left" - label="Delete Role" - layout="topleft" - left_pad="10" - name="role_delete" - width="100" /> - </panel> + <panel.string + name="help_text"> + Roles have a title and an allowed list of Abilities +that Members can perform. Members can belong to +one or more Roles. A group can have up to 10 Roles, +including the Everyone and Owner Roles. + </panel.string> + <panel.string + name="cant_delete_role"> + The 'Everyone' and 'Owners' Roles are special and can't be deleted. + </panel.string> + <panel.string + name="power_folder_icon" translate="false"> + Inv_FolderClosed + </panel.string> + <panel.string + name="power_all_have_icon" translate="false"> + Checkbox_On + </panel.string> + <panel.string + name="power_partial_icon" translate="false"> + Checkbox_Off + </panel.string> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Roles" + name="filter_input" /> + <scroll_list + column_padding="0" + draw_heading="true" + draw_stripes="false" + heading_height="23" + height="132" + layout="topleft" + search_column="1" + left="0" + follows="left|top|right" + right="-1" + name="role_list" + top_pad="2" + width="310"> + <scroll_list.columns + label="Role" + name="name" + relative_width="0.45" /> + <scroll_list.columns + label="Title" + name="title" + relative_width="0.45" /> + <scroll_list.columns + label="#" + name="members" + relative_width="0.15" /> + </scroll_list> + <button + follows="top|left" + height="23" + label="New Role" + layout="topleft" + left="0" + name="role_create" + width="100" /> + <button + follows="top|left" + height="23" + label="Copy Role" + layout="topleft" + left_pad="10" + name="role_copy" + width="100" /> + <button + height="23" + follows="top|left" + label="Delete Role" + layout="topleft" + left_pad="10" + name="role_delete" + width="100" /> + </panel> + <panel + border="false" + height="303" + label="ABILITIES" + layout="topleft" + left="0" + right="-1" + help_topic="roles_actions_tab" + name="actions_sub_tab" + class="panel_group_actions_subtab" + tool_tip="You can view an Ability's Description and which Roles and Members can execute the Ability." + width="310"> + <panel.string + name="help_text"> + Abilities allow Members in Roles to do specific +things in this group. There's a broad variety of Abilities. + </panel.string> + <panel.string + name="power_folder_icon" translate="false"> + Inv_FolderClosed + </panel.string> + <panel.string + name="power_all_have_icon" translate="false"> + Checkbox_On + </panel.string> + <panel.string + name="power_partial_icon" translate="false"> + Checkbox_Off + </panel.string> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Abilities" + name="filter_input" /> + <scroll_list + column_padding="0" + draw_stripes="true" + height="200" + follows="left|top|right" + layout="topleft" + left="0" + right="-1" + name="action_list" + search_column="2" + tool_tip="Select an Ability to view more details" + top_pad="5" + width="300"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" /> + </scroll_list> + </panel> + <panel + border="false" + height="303" + label="BANNED RESIDENTS" + layout="topleft" + left="0" + right="-1" + help_topic="roles_banlist_tab" + name="banlist_sub_tab" + class="panel_group_banlist_subtab" + tool_tip="View the banned residents from this group." + width="310"> + <panel.string + name="help_text"> + Any resident on the ban list will be unable to join the group. + </panel.string> + <panel.string + name="ban_count_template"> + Ban count: [COUNT]/[LIMIT] + </panel.string> + <name_list + column_padding="0" + draw_heading="true" + height="400" + follows="left|top|right" + layout="topleft" + left="0" + right="-1" + multi_select="true" + name="ban_list" + short_names="false" + top_pad="5"> + <name_list.columns + label="Resident" + name="name" + font.name="SANSSERIF_SMALL" + font.style="NORMAL" + relative_width="0.7" /> + <name_list.columns + label="Date Banned" + name="ban_date" + relative_width="0.3" /> + </name_list> + <button + follows="top|left" + height="23" + label="Ban Resident(s)" + layout="topleft" + left="3" + name="ban_create" + tool_tip="Ban residents from your group" + width="120" /> + <button + follows="top|left" + height="23" + label="Remove Ban(s)" + layout="topleft" + left_pad="5" + name="ban_delete" + tool_tip="Unban selected residents from your group" + width="120" /> + <button + follows="top|left" + height="23" + width="23" + image_overlay="Refresh_Off" + layout="topleft" + left_pad="5" + name="ban_refresh" + tool_tip="Refresh the ban list" /> + <text + type="string" + height="18" + left_pad="5" + follows="top|left" + layout="topleft" + name="ban_count" + width="100"> + </text> + </panel> + </tab_container> <panel - border="false" - height="303" - label="ABILITIES" + height="350" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" layout="topleft" + follows="top|left|right" left="0" right="-1" - help_topic="roles_actions_tab" - name="actions_sub_tab" - class="panel_group_actions_subtab" - tool_tip="You can view an Ability's Description and which Roles and Members can execute the Ability." - width="310"> - <panel.string - name="help_text"> - Abilities allow Members in Roles to do specific - things in this group. There's a broad variety of Abilities. - </panel.string> - <panel.string - name="power_folder_icon" translate="false"> - Inv_FolderClosed - </panel.string> - <panel.string - name="power_all_have_icon" translate="false"> - Checkbox_On - </panel.string> - <panel.string - name="power_partial_icon" translate="false"> - Checkbox_Off - </panel.string> - <filter_editor - layout="topleft" - top="5" - left="5" - right="-5" - height="22" - search_button_visible="false" - follows="left|top|right" - label="Filter Abilities" - name="filter_input" /> - <scroll_list - column_padding="0" - draw_stripes="true" - height="200" - follows="left|top|right" - layout="topleft" - left="0" - right="-1" - name="action_list" - search_column="2" - tool_tip="Select an Ability to view more details" - top_pad="5" - width="300"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" /> - </scroll_list> + width="313" + mouse_opaque="false" + name="members_footer" + top="325" + visible="false"> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top="8" + text_color="EmphasisColor" + name="static" + width="300"> + Assigned Roles + </text> + <scroll_list + draw_stripes="true" + follows="left|top|right" + height="150" + layout="topleft" + left="0" + right="-1" + name="member_assigned_roles" + top_pad="0"> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="role" + width="270" /> + </scroll_list> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top_pad="5" + text_color="EmphasisColor" + name="static2" + width="285"> + Allowed Abilities + </text> + <scroll_list + draw_stripes="true" + follows="left|top|right" + height="150" + layout="topleft" + left="0" + right="-1" + name="member_allowed_actions" + search_column="2" + tool_tip="For details of each allowed ability see the abilities tab" + top_pad="0"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> </panel> <panel - border="false" - height="303" - label="BANNED RESIDENTS" + height="90" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" layout="topleft" + follows="top|left|right" left="0" right="-1" - help_topic="roles_banlist_tab" - name="banlist_sub_tab" - class="panel_group_banlist_subtab" - tool_tip="View the banned residents from this group." - width="310"> - <panel.string - name="help_text"> - Any resident on the ban list will be unable to join the group. - </panel.string> - <panel.string - name="ban_count_template"> - Ban count: [COUNT]/[LIMIT] - </panel.string> - <name_list - column_padding="0" - draw_heading="true" - height="400" - follows="left|top|right" - layout="topleft" - left="0" - right="-1" - multi_select="true" - name="ban_list" - short_names="false" - top_pad="5"> - <name_list.columns - label="Resident" - name="name" - font.name="SANSSERIF_SMALL" - font.style="NORMAL" - relative_width="0.7" /> - <name_list.columns - label="Date Banned" - name="ban_date" - relative_width="0.3" /> - </name_list> - <button - follows="top|left" - height="23" - label="Ban Resident(s)" - layout="topleft" - left="3" - name="ban_create" - tool_tip="Ban residents from your group" - width="120" /> - <button - follows="top|left" - height="23" - label="Remove Ban(s)" - layout="topleft" - left_pad="5" - name="ban_delete" - tool_tip="Unban selected residents from your group" - width="120" /> - <button - follows="top|left" - height="23" - width="23" - image_overlay="Refresh_Off" - layout="topleft" - left_pad="5" - name="ban_refresh" - tool_tip="Refresh the ban list" - /> - <text - type="string" - height="18" - left_pad="5" - follows="top|left" - layout="topleft" - name="ban_count" - width="100"> - </text> + width="313" + mouse_opaque="false" + name="members_header" + top_pad="3" + visible="false"> + <text_editor + bg_readonly_color="Transparent" + text_readonly_color="EmphasisColor" + font="SansSerifSmall" + type="string" + enabled="false" + halign="left" + layout="topleft" + top_pad="0" + follows="left|top|right" + left="0" + right="-1" + height="90" + max_length="512" + name="member_action_description" + word_wrap="true"> + This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. + </text_editor> </panel> - </tab_container> - <panel - height="350" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" - layout="topleft" - follows="top|left|right" - left="0" - right="-1" - width="313" - mouse_opaque="false" - name="members_footer" - top="325" - visible="false"> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top="8" - text_color="EmphasisColor" - name="static" - width="300"> - Assigned Roles - </text> - <scroll_list - draw_stripes="true" - follows="left|top|right" - height="150" + <panel + height="460" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" layout="topleft" + follows="top|left|right" left="0" right="-1" - name="member_assigned_roles" - top_pad="0"> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="role" - width="270" /> - </scroll_list> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top_pad="5" - text_color="EmphasisColor" - name="static2" - width="285"> - Allowed Abilities - </text> - <scroll_list - draw_stripes="true" + width="313" + mouse_opaque="false" + name="roles_footer" + top_delta="0" + top="209" + visible="false"> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top="5" + name="static" + width="300"> + Role Name + </text> + <line_editor + type="string" + height="20" + layout="topleft" + left="0" follows="left|top|right" - height="150" - layout="topleft" - left="0" - right="-1" - name="member_allowed_actions" - search_column="2" - tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> - </panel> - <panel - height="90" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" - layout="topleft" - follows="top|left|right" - left="0" - right="-1" - width="313" - mouse_opaque="false" - name="members_header" - top_pad="3" - visible="false"> - <text_editor - bg_readonly_color="Transparent" - text_readonly_color="EmphasisColor" - font="SansSerifSmall" - type="string" - enabled="false" - halign="left" - layout="topleft" - top_pad="0" - follows="left|top|right" - left="0" - right="-1" - height="90" - max_length="512" - name="member_action_description" - word_wrap="true"> - This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. - </text_editor> - </panel> - <panel - height="460" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" - layout="topleft" - follows="top|left|right" - left="0" - right="-1" - width="313" - mouse_opaque="false" - name="roles_footer" - top_delta="0" - top="209" - visible="false"> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top="5" - name="static" - width="300"> - Role Name - </text> - <line_editor - type="string" - height="20" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length_bytes="20" - name="role_name" - top_pad="0" - width="300"> - </line_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static3" - top_pad="5" - width="300"> - Role Title - </text> - <line_editor - type="string" - height="20" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length_bytes="20" - name="role_title" - top_pad="0" - width="300"> - </line_editor> - <text + right="-1" + max_length_bytes="20" + name="role_name" + top_pad="0" + width="300"> + </line_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static3" + top_pad="5" + width="300"> + Role Title + </text> + <line_editor + type="string" + height="20" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length_bytes="20" + name="role_title" + top_pad="0" + width="300"> + </line_editor> + <text type="string" height="16" layout="topleft" @@ -558,192 +557,192 @@ clicking on their names. name="static2" top_pad="5" width="200"> - Description - </text> - <text_editor - type="string" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length="295" - height="35" - name="role_description" - top_pad="0" - width="300" - word_wrap="true"> - </text_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - text_color="EmphasisColor" - name="static4" - top_pad="5" - width="300"> - Assigned Members - </text> - <name_list - draw_stripes="true" - height="128" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - name="role_assigned_members" - top_pad="0" - width="300" /> - <check_box - height="15" - label="Reveal members" - left="5" - layout="topleft" - name="role_visible_in_list" - tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group." - top_pad="4" - width="300" /> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - text_color="EmphasisColor" - name="static5" - top_pad="2" - width="300"> - Allowed Abilities - </text> - <scroll_list - draw_stripes="true" - height="140" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - name="role_allowed_actions" - search_column="2" - tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0" - width="300"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" /> - </scroll_list> - </panel> - <panel - height="90" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" - layout="topleft" - follows="top|left|right" - left="0" - right="-1" - width="313" - mouse_opaque="false" - name="roles_header" - top_pad="3" - visible="false"> - <text_editor - bg_readonly_color="Transparent" - text_readonly_color="EmphasisColor" - font="SansSerifSmall" - type="string" - enabled="false" - halign="left" - layout="topleft" - top_pad="0" - follows="left|top|right" - left="0" - right="-1" + Description + </text> + <text_editor + type="string" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length="295" + height="35" + name="role_description" + top_pad="0" + width="300" + word_wrap="true"> + </text_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + text_color="EmphasisColor" + name="static4" + top_pad="5" + width="300"> + Assigned Members + </text> + <name_list + draw_stripes="true" + height="128" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + name="role_assigned_members" + top_pad="0" + width="300" /> + <check_box + height="15" + label="Reveal members" + left="5" + layout="topleft" + name="role_visible_in_list" + tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group." + top_pad="4" + width="300" /> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + text_color="EmphasisColor" + name="static5" + top_pad="2" + width="300"> + Allowed Abilities + </text> + <scroll_list + draw_stripes="true" + height="140" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + name="role_allowed_actions" + search_column="2" + tool_tip="For details of each allowed ability see the abilities tab" + top_pad="0" + width="300"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" /> + </scroll_list> + </panel> + <panel height="90" - max_length="512" - name="role_action_description" - word_wrap="true"> - This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. - </text_editor> - </panel> - <panel - height="424" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" - layout="topleft" - follows="top|left|right" - left="0" - right="-1" - width="313" - mouse_opaque="false" - name="actions_footer" - top_delta="0" - top="255" - visible="false"> - <text_editor - bg_readonly_color="Transparent" - text_readonly_color="EmphasisColor" - font="SansSerifSmall" - type="string" - enabled="false" - halign="left" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" layout="topleft" - follows="left|top|right" + follows="top|left|right" left="0" right="-1" - height="90" - max_length="512" - name="action_description" - top="0" - word_wrap="true"> - This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. - </text_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static2" - top_pad="1" - width="300"> - Roles with this ability - </text> - <scroll_list - height="172" - layout="topleft" - follows="left|top|right" - left="5" - right="-1" - name="action_roles" - top_pad="0" - width="300" /> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static3" - top_pad="5" - width="300"> - Members with this ability - </text> - <name_list - height="122" - follows="left|top|right" + width="313" + mouse_opaque="false" + name="roles_header" + top_pad="3" + visible="false"> + <text_editor + bg_readonly_color="Transparent" + text_readonly_color="EmphasisColor" + font="SansSerifSmall" + type="string" + enabled="false" + halign="left" + layout="topleft" + top_pad="0" + follows="left|top|right" + left="0" + right="-1" + height="90" + max_length="512" + name="role_action_description" + word_wrap="true"> + This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. + </text_editor> + </panel> + <panel + height="424" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" layout="topleft" - left="5" + follows="top|left|right" + left="0" right="-1" - name="action_members" - top_pad="0" - width="300" /> - </panel> + width="313" + mouse_opaque="false" + name="actions_footer" + top_delta="0" + top="255" + visible="false"> + <text_editor + bg_readonly_color="Transparent" + text_readonly_color="EmphasisColor" + font="SansSerifSmall" + type="string" + enabled="false" + halign="left" + layout="topleft" + follows="left|top|right" + left="0" + right="-1" + height="90" + max_length="512" + name="action_description" + top="0" + word_wrap="true"> + This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. + </text_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static2" + top_pad="1" + width="300"> + Roles with this ability + </text> + <scroll_list + height="172" + layout="topleft" + follows="left|top|right" + left="5" + right="-1" + name="action_roles" + top_pad="0" + width="300" /> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static3" + top_pad="5" + width="300"> + Members with this ability + </text> + <name_list + height="122" + follows="left|top|right" + layout="topleft" + left="5" + right="-1" + name="action_members" + top_pad="0" + width="300" /> + </panel> </panel> -- cgit v1.2.3 From 06b6d5ed37943ea330c7f7f2a1a3a43e951c9f8b Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Sun, 22 Sep 2024 08:22:04 +0200 Subject: #2618 Roles and Members tab is a mess --- .../skins/default/xui/en/panel_group_roles.xml | 72 ++++++---------------- 1 file changed, 19 insertions(+), 53 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 33f98b37ea..868d54401e 100644 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel - height="750" + height="770" label="Members & Roles" layout="topleft" left="0" @@ -20,7 +20,7 @@ <tab_container border="false" follows="left|top|right" - height="552" + height="770" halign="center" layout="topleft" left="0" @@ -29,16 +29,10 @@ tab_position="top" tab_height="22" tab_min_width="90" - top="0" - width="304"> + top="0"> <panel border="false" - follows="all" - height="303" label="MEMBERS" - layout="topleft" - left="0" - right="-1" help_topic="roles_members_tab" name="members_sub_tab" tool_tip="Members" @@ -128,11 +122,7 @@ clicking on their names. </panel> <panel border="false" - height="303" label="ROLES" - layout="topleft" - left="0" - right="-1" help_topic="roles_roles_tab" name="roles_sub_tab" class="panel_group_roles_subtab"> @@ -183,15 +173,14 @@ including the Everyone and Owner Roles. draw_heading="true" draw_stripes="false" heading_height="23" - height="132" + height="138" layout="topleft" search_column="1" left="0" follows="left|top|right" right="-1" name="role_list" - top_pad="2" - width="310"> + top_pad="2"> <scroll_list.columns label="Role" name="name" @@ -232,16 +221,11 @@ including the Everyone and Owner Roles. </panel> <panel border="false" - height="303" label="ABILITIES" - layout="topleft" - left="0" - right="-1" help_topic="roles_actions_tab" name="actions_sub_tab" class="panel_group_actions_subtab" - tool_tip="You can view an Ability's Description and which Roles and Members can execute the Ability." - width="310"> + tool_tip="You can view an Ability's Description and which Roles and Members can execute the Ability."> <panel.string name="help_text"> Abilities allow Members in Roles to do specific @@ -280,8 +264,7 @@ things in this group. There's a broad variety of Abilities. name="action_list" search_column="2" tool_tip="Select an Ability to view more details" - top_pad="5" - width="300"> + top_pad="5"> <scroll_list.columns label="" name="icon" @@ -297,16 +280,11 @@ things in this group. There's a broad variety of Abilities. </panel> <panel border="false" - height="303" label="BANNED RESIDENTS" - layout="topleft" - left="0" - right="-1" help_topic="roles_banlist_tab" name="banlist_sub_tab" class="panel_group_banlist_subtab" - tool_tip="View the banned residents from this group." - width="310"> + tool_tip="View the banned residents from this group."> <panel.string name="help_text"> Any resident on the ban list will be unable to join the group. @@ -318,7 +296,7 @@ things in this group. There's a broad variety of Abilities. <name_list column_padding="0" draw_heading="true" - height="400" + height="714" follows="left|top|right" layout="topleft" left="0" @@ -384,7 +362,6 @@ things in this group. There's a broad variety of Abilities. follows="top|left|right" left="0" right="-1" - width="313" mouse_opaque="false" name="members_footer" top="325" @@ -464,7 +441,6 @@ things in this group. There's a broad variety of Abilities. follows="top|left|right" left="0" right="-1" - width="313" mouse_opaque="false" name="members_header" top_pad="3" @@ -496,11 +472,10 @@ things in this group. There's a broad variety of Abilities. follows="top|left|right" left="0" right="-1" - width="313" mouse_opaque="false" name="roles_footer" top_delta="0" - top="209" + top="215" visible="false"> <text type="string" @@ -522,8 +497,7 @@ things in this group. There's a broad variety of Abilities. right="-1" max_length_bytes="20" name="role_name" - top_pad="0" - width="300"> + top_pad="0"> </line_editor> <text type="string" @@ -545,8 +519,7 @@ things in this group. There's a broad variety of Abilities. right="-1" max_length_bytes="20" name="role_title" - top_pad="0" - width="300"> + top_pad="0"> </line_editor> <text type="string" @@ -569,7 +542,6 @@ things in this group. There's a broad variety of Abilities. height="35" name="role_description" top_pad="0" - width="300" word_wrap="true"> </text_editor> <text @@ -592,8 +564,7 @@ things in this group. There's a broad variety of Abilities. follows="left|top|right" right="-1" name="role_assigned_members" - top_pad="0" - width="300" /> + top_pad="0" /> <check_box height="15" label="Reveal members" @@ -625,8 +596,7 @@ things in this group. There's a broad variety of Abilities. name="role_allowed_actions" search_column="2" tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0" - width="300"> + top_pad="0"> <scroll_list.columns label="" name="icon" @@ -648,7 +618,6 @@ things in this group. There's a broad variety of Abilities. follows="top|left|right" left="0" right="-1" - width="313" mouse_opaque="false" name="roles_header" top_pad="3" @@ -673,14 +642,13 @@ things in this group. There's a broad variety of Abilities. </text_editor> </panel> <panel - height="424" + height="513" background_visible="false" bg_alpha_color="FloaterUnfocusBorderColor" layout="topleft" follows="top|left|right" left="0" right="-1" - width="313" mouse_opaque="false" name="actions_footer" top_delta="0" @@ -716,14 +684,13 @@ things in this group. There's a broad variety of Abilities. Roles with this ability </text> <scroll_list - height="172" + height="216" layout="topleft" follows="left|top|right" left="5" right="-1" name="action_roles" - top_pad="0" - width="300" /> + top_pad="0" /> <text type="string" height="16" @@ -736,13 +703,12 @@ things in this group. There's a broad variety of Abilities. Members with this ability </text> <name_list - height="122" + height="167" follows="left|top|right" layout="topleft" left="5" right="-1" name="action_members" - top_pad="0" - width="300" /> + top_pad="0" /> </panel> </panel> -- cgit v1.2.3 From 60947eebafe7c7ef707e7e1d05d2179e17404104 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Mon, 23 Sep 2024 11:59:10 +0300 Subject: #2626 fix for incoming IM calls not being rejected when DND mode is active --- indra/newview/llimview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 06cf9919b6..1402cc8c37 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3551,6 +3551,7 @@ void LLIMMgr::inviteToSession( && voice_invite && "VoiceInviteQuestionDefault" == question_type) { LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; + payload["voice_channel_info"] = voice_channel_info; LLIncomingCallDialog::processCallResponse(1, payload); return; } @@ -3599,6 +3600,7 @@ void LLIMMgr::inviteToSession( send_do_not_disturb_message(gMessageSystem, caller_id, session_id); } // silently decline the call + payload["voice_channel_info"] = voice_channel_info; LLIncomingCallDialog::processCallResponse(1, payload); return; } -- cgit v1.2.3 From 8efba1db81fc1294114cea70de0df53f4d4ab9a4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Mon, 23 Sep 2024 10:23:37 -0400 Subject: Use Lua command-line args to make frame_profile_quit.lua generic. Now the location to which to teleport and the camera focus point can both be specified by the caller, in this case the frame_profile bash script. --- indra/newview/scripts/lua/frame_profile_quit.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/scripts/lua/frame_profile_quit.lua b/indra/newview/scripts/lua/frame_profile_quit.lua index e3177a3f67..ad136c86d2 100644 --- a/indra/newview/scripts/lua/frame_profile_quit.lua +++ b/indra/newview/scripts/lua/frame_profile_quit.lua @@ -1,5 +1,11 @@ -- Trigger Develop -> Render Tests -> Frame Profile and quit +assert(arg.n == 3, 'Usage: frame_profile_quit.lua x y z (for camera focus)') +-- Try coercing string arguments to numbers, using Lua's implicit conversion. +-- If the args passed as x, y, z won't convert nicely to numbers, better find +-- out now. +focus = {arg[1]+0, arg[2]+0, arg[3]+0} + LLAgent = require 'LLAgent' logout = require 'logout' startup = require 'startup' @@ -8,11 +14,14 @@ UI = require 'UI' startup.wait('STATE_STARTED') --- Assume we logged into http://maps.secondlife.com/secondlife/Bug%20Island/220/224/27 --- (see frame_profile bash script) +-- Figure out where we are +camera = LLAgent.getRegionPosition() +-- assume z is the agent's feet, add 2 meters +camera[2] += 2 + Timer(10, 'wait') -LLAgent.setCamera{camera_pos={220, 224, 26}, camera_locked=true, - focus_pos ={228, 232, 26}, focus_locked=true} +LLAgent.setCamera{camera_pos=camera, camera_locked=true, + focus_pos=focus, focus_locked=true} Timer(1, 'wait') -- This freezes the viewer for perceptible realtime UI.popup:tip('starting Render Tests -> Frame Profile') -- cgit v1.2.3 From 0f4b1b8523add2ffffecbbf9d01d35a9db32106b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 23 Sep 2024 16:26:27 +0300 Subject: viewer#2631 Couple small tweaks --- indra/newview/llhudnametag.cpp | 14 ++++++++------ indra/newview/llhudrender.cpp | 1 + indra/newview/llviewerdisplay.cpp | 3 ++- indra/newview/llviewerwindow.cpp | 12 +++++++----- 4 files changed, 18 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 19ae35813c..66130a2744 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -275,7 +275,8 @@ void LLHUDNameTag::renderText() LLVector3 x_pixel_vec; LLVector3 y_pixel_vec; - LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); + LLViewerCamera* camera = LLViewerCamera::getInstance(); + camera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); LLVector3 width_vec = mWidth * x_pixel_vec; LLVector3 height_vec = mHeight * y_pixel_vec; @@ -283,7 +284,7 @@ void LLHUDNameTag::renderText() mRadius = (width_vec + height_vec).magVec() * 0.5f; LLCoordGL screen_pos; - LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, false); + camera->projectPosAgentToScreen(mPositionAgent, screen_pos, false); LLVector2 screen_offset = updateScreenPos(mPositionOffset); @@ -310,7 +311,7 @@ void LLHUDNameTag::renderText() const S32 label_height = ll_round((mFontp->getLineHeight() * (F32)mLabelSegments.size() + (VERTICAL_PADDING / 3.f))); label_top_rect.mBottom = label_top_rect.mTop - label_height; LLColor4 label_top_color = text_color; - label_top_color.mV[VALPHA] = gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor; + label_top_color.mV[VALPHA] = bubble_opacity() * alpha_factor; mRoundedRectTopImgp->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); } @@ -645,12 +646,13 @@ LLVector2 LLHUDNameTag::updateScreenPos(LLVector2 &offset) LLVector2 screen_pos_vec; LLVector3 x_pixel_vec; LLVector3 y_pixel_vec; - LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); + LLViewerCamera* camera = LLViewerCamera::getInstance(); + camera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec); - if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, false) && mVisibleOffScreen) + if (!camera->projectPosAgentToScreen(world_pos, screen_pos, false) && mVisibleOffScreen) { // bubble off-screen, so find a spot for it along screen edge - LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos); + camera->projectPosAgentToScreenEdge(world_pos, screen_pos); } screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY); diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp index 4180e49e94..aa440c6cf5 100644 --- a/indra/newview/llhudrender.cpp +++ b/indra/newview/llhudrender.cpp @@ -63,6 +63,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, const LLColor4& color, const bool orthographic) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLViewerCamera* camera = LLViewerCamera::getInstance(); // Do cheap plane culling LLVector3 dir_vec = pos_agent - camera->getOrigin(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index f722d0bd1d..6278832765 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1625,7 +1625,8 @@ void render_ui_3d() gGL.color4f(1, 1, 1, 1); // Coordinate axes - if (gSavedSettings.getBOOL("ShowAxes")) + LLCachedControl<bool> show_axes(gSavedSettings, "ShowAxes"); + if (show_axes()) { draw_axes(); } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index acb2c85ef8..3bc76bbb67 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3776,19 +3776,21 @@ void LLViewerWindow::updateUI() void LLViewerWindow::updateLayout() { - LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); + LLToolMgr* tool_mgr = LLToolMgr::getInstance(); + LLTool* tool = tool_mgr->getCurrentTool(); + LLCachedControl<bool> freeze_time(gSavedSettings, "FreezeTime"); if (gFloaterTools != NULL && tool != NULL && tool != gToolNull && tool != LLToolCompInspect::getInstance() && tool != LLToolDragAndDrop::getInstance() - && !gSavedSettings.getBOOL("FreezeTime")) + && !freeze_time()) { // Suppress the toolbox view if our source tool was the pie tool, // and we've overridden to something else. bool suppress_toolbox = - (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) && - (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()); + (tool_mgr->getBaseTool() == LLToolPie::getInstance()) && + (tool_mgr->getCurrentTool() != LLToolPie::getInstance()); LLMouseHandler *captor = gFocusMgr.getMouseCapture(); // With the null, inspect, or drag and drop tool, don't muck @@ -3798,7 +3800,7 @@ void LLViewerWindow::updateLayout() || (tool != LLToolPie::getInstance() // not default tool && tool != LLToolCompGun::getInstance() // not coming out of mouselook && !suppress_toolbox // not override in third person - && LLToolMgr::getInstance()->getCurrentToolset()->isShowFloaterTools() + && tool_mgr->getCurrentToolset()->isShowFloaterTools() && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging { // Force floater tools to be visible (unless minimized) -- cgit v1.2.3 From 9a95e69bfc8a75b72d2e13d2d091297230d101ba Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Mon, 23 Sep 2024 23:03:30 +0200 Subject: Restore WebRTC shutdown fix (#2658) --- indra/newview/llvoicewebrtc.cpp | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 32803c6117..7161f5af5e 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2769,17 +2769,6 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { mRetryWaitPeriod = 0; mRetryWaitSecs = (F32)((F32)rand() / (F32)RAND_MAX) + 0.5f; - LLUUID agentRegionID; - if (isSpatial() && gAgent.getRegion()) - { - - bool primary = (mRegionID == gAgent.getRegion()->getRegionID()); - if (primary != mPrimary) - { - mPrimary = primary; - sendJoin(); - } - } // we'll stay here as long as the session remains up. if (mShutDown) -- cgit v1.2.3 From 3090e018eac74d87c01c672b602cbcf63ccf450a Mon Sep 17 00:00:00 2001 From: Cosmic Linden <cosmic@lindenlab.com> Date: Mon, 23 Sep 2024 15:55:05 -0700 Subject: secondlife/viewer#2638: Remove pointless assert and cast --- indra/newview/llviewerobject.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 86440fca48..bc6a343e89 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5097,8 +5097,7 @@ void LLViewerObject::updateTEMaterialTextures(U8 te) LLUUID mat_id = getRenderMaterialID(te); if (mat == nullptr && mat_id.notNull()) { - mat = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mat_id); - llassert(mat == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(gGLTFMaterialList.getMaterial(mat_id)) != nullptr); + mat = gGLTFMaterialList.getMaterial(mat_id); if (mat->isFetching()) { // material is not loaded yet, rebuild draw info when the object finishes loading mat->onMaterialComplete([id=getID()] -- cgit v1.2.3 From 3b6bdee4b834f92b04ada30668d538002fdc698b Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Tue, 24 Sep 2024 01:52:55 +0200 Subject: Performance improvements and cleanup in llviewerdisplay.cpp --- indra/newview/llviewerdisplay.cpp | 66 +++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 6278832765..cd35de12c6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -100,13 +100,13 @@ extern LLPointer<LLViewerTexture> gStartTexture; extern bool gShiftFrame; -LLPointer<LLViewerTexture> gDisconnectedImagep = NULL; +LLPointer<LLViewerTexture> gDisconnectedImagep = nullptr; // used to toggle renderer back on after teleport bool gTeleportDisplay = false; LLFrameTimer gTeleportDisplayTimer; LLFrameTimer gTeleportArrivalTimer; -const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain +constexpr F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain bool gForceRenderLandFence = false; bool gDisplaySwapBuffers = false; @@ -120,9 +120,9 @@ bool gSnapshotNoPost = false; bool gShaderProfileFrame = false; // This is how long the sim will try to teleport you before giving up. -const F32 TELEPORT_EXPIRY = 15.0f; +constexpr F32 TELEPORT_EXPIRY = 15.0f; // Additional time (in seconds) to wait per attachment -const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f; +constexpr F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f; U32 gRecentFrameCount = 0; // number of 'recent' frames LLFrameTimer gRecentFPSTime; @@ -130,8 +130,6 @@ LLFrameTimer gRecentMemoryTime; LLFrameTimer gAssetStorageLogTime; // Rendering stuff -void pre_show_depth_buffer(); -void post_show_depth_buffer(); void render_ui(F32 zoom_factor = 1.f, int subfield = 0); void swap(); void render_hud_attachments(); @@ -212,7 +210,8 @@ void display_update_camera() F32 final_far = gAgentCamera.mDrawDistance; if (gCubeSnapshot) { - final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance"); + static LLCachedControl<F32> reflection_probe_draw_distance(gSavedSettings, "RenderReflectionProbeDrawDistance", 64.f); + final_far = reflection_probe_draw_distance(); } else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) @@ -233,7 +232,7 @@ void display_update_camera() void display_stats() { LL_PROFILE_ZONE_SCOPED; - const F32 FPS_LOG_FREQUENCY = 10.f; + constexpr F32 FPS_LOG_FREQUENCY = 10.f; if (gRecentFPSTime.getElapsedTimeF32() >= FPS_LOG_FREQUENCY) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS"); @@ -242,7 +241,7 @@ void display_stats() gRecentFrameCount = 0; gRecentFPSTime.reset(); } - F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); + static LLCachedControl<F32> mem_log_freq(gSavedSettings, "MemoryLogFrequency", 600.f); if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory"); @@ -252,7 +251,7 @@ void display_stats() LLMemory::logMemoryInfo(true) ; gRecentMemoryTime.reset(); } - const F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f; + constexpr F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f; if (gAssetStorageLogTime.getElapsedTimeF32() >= ASSET_STORAGE_LOG_FREQUENCY) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage"); @@ -539,8 +538,10 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) LLImageGL::updateStats(gFrameTimeSeconds); - LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode"); - LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode")); + static LLCachedControl<S32> avatar_name_tag_mode(gSavedSettings, "AvatarNameTagMode", 1); + static LLCachedControl<bool> name_tag_show_group_titles(gSavedSettings, "NameTagShowGroupTitles", true); + LLVOAvatar::sRenderName = avatar_name_tag_mode; + LLVOAvatar::sRenderGroupTitles = name_tag_show_group_titles && avatar_name_tag_mode > 0; gPipeline.mBackfaceCull = true; gFrameCount++; @@ -763,7 +764,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) } gGL.setColorMask(true, true); - glClearColor(0,0,0,0); + glClearColor(0.f, 0.f, 0.f, 0.f); LLGLState::checkStates(); @@ -933,7 +934,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) gPipeline.mRT->deferredScreen.bindTarget(); if (gUseWireframe) { - F32 g = 0.5f; + constexpr F32 g = 0.5f; glClearColor(g, g, g, 1.f); } else @@ -947,8 +948,8 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) gPipeline.mRT->screen.bindTarget(); if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) { - const LLColor4 &col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor(); - glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); + const LLColor4& col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor(); + glClearColor(col.mV[VRED], col.mV[VGREEN], col.mV[VBLUE], 0.f); } gPipeline.mRT->screen.clear(); } @@ -963,11 +964,12 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5") LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - if (gSavedSettings.getBOOL("RenderDepthPrePass")) + static LLCachedControl<bool> render_depth_pre_pass(gSavedSettings, "RenderDepthPrePass", false); + if (render_depth_pre_pass) { gGL.setColorMask(false, false); - static const U32 types[] = { + constexpr U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY @@ -1181,7 +1183,7 @@ void display_cube_face() gGL.setColorMask(true, true); - glClearColor(0, 0, 0, 0); + glClearColor(0.f, 0.f, 0.f, 0.f); gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); glClear(GL_DEPTH_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT); @@ -1217,7 +1219,7 @@ void display_cube_face() } else { - glClearColor(1, 0, 1, 1); + glClearColor(1.f, 0.f, 1.f, 1.f); } gPipeline.mRT->deferredScreen.clear(); @@ -1258,11 +1260,12 @@ void render_hud_attachments() { LLPipeline::sRenderingHUDs = true; LLCamera hud_cam = *LLViewerCamera::getInstance(); - hud_cam.setOrigin(-1.f,0,0); - hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); + hud_cam.setOrigin(-1.f, 0.f, 0.f); + hud_cam.setAxes(LLVector3(1.f, 0.f, 0.f), LLVector3(0.f, 1.f, 0.f), LLVector3(0.f, 0.f, 1.f)); LLViewerCamera::updateFrustumPlanes(hud_cam, true); - bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles"); + static LLCachedControl<bool> render_hud_particles(gSavedSettings, "RenderHUDParticles", false); + bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && render_hud_particles; //only render hud objects gPipeline.pushRenderTypeMask(); @@ -1622,10 +1625,10 @@ void render_ui_3d() stop_glerror(); gUIProgram.bind(); - gGL.color4f(1, 1, 1, 1); + gGL.color4f(1.f, 1.f, 1.f, 1.f); // Coordinate axes - LLCachedControl<bool> show_axes(gSavedSettings, "ShowAxes"); + static LLCachedControl<bool> show_axes(gSavedSettings, "ShowAxes"); if (show_axes()) { draw_axes(); @@ -1686,7 +1689,7 @@ void render_ui_2d() gGL.pushMatrix(); S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2); S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2); - gGL.scalef(LLUI::getScaleFactor().mV[0], LLUI::getScaleFactor().mV[1], 1.f); + gGL.scalef(LLUI::getScaleFactor().mV[VX], LLUI::getScaleFactor().mV[VY], 1.f); gGL.translatef((F32)half_width, (F32)half_height, 0.f); F32 zoom = gAgentCamera.mHUDCurZoom; gGL.scalef(zoom,zoom,1.f); @@ -1708,7 +1711,7 @@ void render_ui_2d() gPipeline.mUIScreen.bindTarget(); gGL.setColorMask(true, true); { - static const S32 pad = 8; + constexpr S32 pad = 8; LLView::sDirtyRect.mLeft -= pad; LLView::sDirtyRect.mRight += pad; @@ -1761,8 +1764,6 @@ void render_ui_2d() gViewerWindow->draw(); } - - // reset current origin for font rendering, in case of tiling render LLFontGL::sCurOrigin.set(0, 0); } @@ -1771,7 +1772,7 @@ void render_disconnected_background() { gUIProgram.bind(); - gGL.color4f(1,1,1,1); + gGL.color4f(1.f, 1.f, 1.f, 1.f); if (!gDisconnectedImagep && gDisconnected) { LL_INFOS() << "Loading last bitmap..." << LL_ENDL; @@ -1811,7 +1812,7 @@ void render_disconnected_background() raw->expandToPowerOfTwo(); - gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false ); + gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false); gStartTexture = gDisconnectedImagep; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } @@ -1846,6 +1847,5 @@ void render_disconnected_background() void display_cleanup() { - gDisconnectedImagep = NULL; + gDisconnectedImagep = nullptr; } - -- cgit v1.2.3 From 776fae7dd7a6b5c1d0a2536248e767fdf4a565d4 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Tue, 24 Sep 2024 02:59:48 +0200 Subject: Reduce memory allocations pinging the mainloop timeout --- indra/newview/llappviewer.cpp | 24 ++++++++++++------------ indra/newview/llappviewer.h | 6 +++--- indra/newview/llwatchdog.cpp | 34 +++++++++++++++++----------------- indra/newview/llwatchdog.h | 12 ++++++------ 4 files changed, 38 insertions(+), 38 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ffd333dd33..68cb64f492 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5549,9 +5549,9 @@ void LLAppViewer::forceErrorThreadCrash() thread->start(); } -void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) +void LLAppViewer::initMainloopTimeout(std::string_view state, F32 secs) { - if(!mMainloopTimeout) + if (!mMainloopTimeout) { mMainloopTimeout = new LLWatchdogTimeout(); resumeMainloopTimeout(state, secs); @@ -5560,20 +5560,20 @@ void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) void LLAppViewer::destroyMainloopTimeout() { - if(mMainloopTimeout) + if (mMainloopTimeout) { delete mMainloopTimeout; - mMainloopTimeout = NULL; + mMainloopTimeout = nullptr; } } -void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) +void LLAppViewer::resumeMainloopTimeout(std::string_view state, F32 secs) { - if(mMainloopTimeout) + if (mMainloopTimeout) { - if(secs < 0.0f) + if (secs < 0.0f) { - static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60.f); secs = mainloop_timeout; } @@ -5584,19 +5584,19 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) void LLAppViewer::pauseMainloopTimeout() { - if(mMainloopTimeout) + if (mMainloopTimeout) { mMainloopTimeout->stop(); } } -void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) +void LLAppViewer::pingMainloopTimeout(std::string_view state, F32 secs) { LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - if(mMainloopTimeout) + if (mMainloopTimeout) { - if(secs < 0.0f) + if (secs < 0.0f) { static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); secs = mainloop_timeout; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 4ce4259ed8..6e02869fba 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -183,11 +183,11 @@ public: // For thread debugging. // llstartup needs to control init. // llworld, send_agent_pause() also controls pause/resume. - void initMainloopTimeout(const std::string& state, F32 secs = -1.0f); + void initMainloopTimeout(std::string_view state, F32 secs = -1.0f); void destroyMainloopTimeout(); void pauseMainloopTimeout(); - void resumeMainloopTimeout(const std::string& state = "", F32 secs = -1.0f); - void pingMainloopTimeout(const std::string& state, F32 secs = -1.0f); + void resumeMainloopTimeout(std::string_view state = "", F32 secs = -1.0f); + void pingMainloopTimeout(std::string_view state, F32 secs = -1.0f); // Handle the 'login completed' event. // *NOTE:Mani Fix this for login abstraction!! diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 0a1d346266..bf171fe954 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -29,7 +29,7 @@ #include "llwatchdog.h" #include "llthread.h" -const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000; +constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U; // This class runs the watchdog timing thread. class LLWatchdogTimerThread : public LLThread @@ -51,7 +51,7 @@ public: mSleepMsecs = 1; } - /* virtual */ void run() + void run() override { while(!mStopping) { @@ -83,7 +83,7 @@ void LLWatchdogEntry::start() void LLWatchdogEntry::stop() { // this can happen very late in the shutdown sequence - if (! LLWatchdog::wasDeleted()) + if (!LLWatchdog::wasDeleted()) { LLWatchdog::getInstance()->remove(this); } @@ -117,7 +117,7 @@ void LLWatchdogTimeout::setTimeout(F32 d) mTimeout = d; } -void LLWatchdogTimeout::start(const std::string& state) +void LLWatchdogTimeout::start(std::string_view state) { if (mTimeout == 0) { @@ -139,9 +139,9 @@ void LLWatchdogTimeout::stop() mTimer.stop(); } -void LLWatchdogTimeout::ping(const std::string& state) +void LLWatchdogTimeout::ping(std::string_view state) { - if(!state.empty()) + if (!state.empty()) { mPingState = state; } @@ -151,7 +151,7 @@ void LLWatchdogTimeout::ping(const std::string& state) // LLWatchdog LLWatchdog::LLWatchdog() :mSuspectsAccessMutex() - ,mTimer(NULL) + ,mTimer(nullptr) ,mLastClockCount(0) { } @@ -176,7 +176,7 @@ void LLWatchdog::remove(LLWatchdogEntry* e) void LLWatchdog::init() { - if(!mSuspectsAccessMutex && !mTimer) + if (!mSuspectsAccessMutex && !mTimer) { mSuspectsAccessMutex = new LLMutex(); mTimer = new LLWatchdogTimerThread(); @@ -191,17 +191,17 @@ void LLWatchdog::init() void LLWatchdog::cleanup() { - if(mTimer) + if (mTimer) { mTimer->stop(); delete mTimer; - mTimer = NULL; + mTimer = nullptr; } - if(mSuspectsAccessMutex) + if (mSuspectsAccessMutex) { delete mSuspectsAccessMutex; - mSuspectsAccessMutex = NULL; + mSuspectsAccessMutex = nullptr; } mLastClockCount = 0; @@ -214,12 +214,12 @@ void LLWatchdog::run() // Check the time since the last call to run... // If the time elapsed is two times greater than the regualr sleep time // reset the active timeouts. - const U32 TIME_ELAPSED_MULTIPLIER = 2; + constexpr U32 TIME_ELAPSED_MULTIPLIER = 2; U64 current_time = LLTimer::getTotalTime(); U64 current_run_delta = current_time - mLastClockCount; mLastClockCount = current_time; - if(current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER)) + if (current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER)) { LL_INFOS() << "Watchdog thread delayed: resetting entries." << LL_ENDL; for (const auto& suspect : mSuspects) @@ -233,7 +233,7 @@ void LLWatchdog::run() std::find_if(mSuspects.begin(), mSuspects.end(), [](const LLWatchdogEntry* suspect){ return ! suspect->isAlive(); }); - if(result != mSuspects.end()) + if (result != mSuspects.end()) { // error!!! if(mTimer) @@ -251,7 +251,7 @@ void LLWatchdog::run() void LLWatchdog::lockThread() { - if(mSuspectsAccessMutex != NULL) + if (mSuspectsAccessMutex) { mSuspectsAccessMutex->lock(); } @@ -259,7 +259,7 @@ void LLWatchdog::lockThread() void LLWatchdog::unlockThread() { - if(mSuspectsAccessMutex != NULL) + if (mSuspectsAccessMutex) { mSuspectsAccessMutex->unlock(); } diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h index fe8932e298..1931c582b0 100644 --- a/indra/newview/llwatchdog.h +++ b/indra/newview/llwatchdog.h @@ -56,14 +56,14 @@ public: LLWatchdogTimeout(); virtual ~LLWatchdogTimeout(); - /* virtual */ bool isAlive() const; - /* virtual */ void reset(); - /* virtual */ void start() { start(""); } - /* virtual */ void stop(); + bool isAlive() const override; + void reset() override; + void start() override { start(""); } + void stop() override; - void start(const std::string& state); + void start(std::string_view state); void setTimeout(F32 d); - void ping(const std::string& state); + void ping(std::string_view state); const std::string& getState() {return mPingState; } private: -- cgit v1.2.3 From 86d2fb93b73d2689104c564ec859be7f83416691 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Mon, 23 Sep 2024 23:49:06 +0200 Subject: #2559 No mouseover if a link is embedded with an emoji --- indra/newview/llexpandabletextbox.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 5c46eb9d80..093f978e74 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -42,17 +42,18 @@ public: mEditor(editor), mStyle(style), mExpanderLabel(utf8str_to_wstring(more_text)) - {} + { + } /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const { - LLStyleSP sp(cloneStyle(target, mStyle)); + LLStyleSP sp((&target == &mEditor) ? mStyle : mStyle->clone()); LLExpanderSegment* copy = new LLExpanderSegment(sp, mStart, mEnd, LLStringUtil::null, target); copy->mExpanderLabel = mExpanderLabel; return copy; } - /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { // more label always spans width of text box if (num_chars == 0) @@ -67,11 +68,13 @@ public: } return true; } - /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const + + /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return start_offset; } - /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const + + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const { // require full line to ourselves if (line_offset == 0) @@ -85,7 +88,8 @@ public: return 0; } } - /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) + + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { F32 right_x; mStyle->getFont()->render(mExpanderLabel, start, @@ -99,6 +103,7 @@ public: mEditor.getUseEllipses(), mEditor.getUseColor()); return right_x; } + /*virtual*/ bool canEdit() const { return false; } // eat handleMouseDown event so we get the mouseup event /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) { return true; } @@ -108,6 +113,7 @@ public: LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); return true; } + private: LLTextBase& mEditor; LLStyleSP mStyle; -- cgit v1.2.3 From c7c5abad7ef878ef94333efbc9de43f0326a29ec Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Tue, 24 Sep 2024 21:35:46 +0200 Subject: Add Lua scripts to viewer source tree --- indra/newview/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 03c80a596c..04ce88f0c6 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1626,6 +1626,13 @@ set_source_files_properties(${viewer_SHADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_SHADER_FILES}) +# Add lua script sources +file(GLOB_RECURSE viewer_LUA_SCRIPT_FILES LIST_DIRECTORIES FALSE + ${CMAKE_CURRENT_SOURCE_DIR}/scripts/lua/*.lua) +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/lua PREFIX "LUA Scripts" FILES ${viewer_LUA_SCRIPT_FILES}) +set_source_files_properties(${viewer_LUA_SCRIPT_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) +list(APPEND viewer_SOURCE_FILES ${viewer_LUA_SCRIPT_FILES}) set(viewer_APPSETTINGS_FILES app_settings/anim.ini -- cgit v1.2.3 From c7b001265dee1ba94f7fcb8f563253d94d549e86 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Wed, 25 Sep 2024 00:03:28 +0200 Subject: #2674 Optimize LLWorld::renderPropertyLines() - use simplified lines --- indra/newview/llviewerparceloverlay.cpp | 174 +++++++++++++++++--------------- indra/newview/llviewerparceloverlay.h | 2 +- 2 files changed, 94 insertions(+), 82 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 2e9b5de72b..f1a8d83aef 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -62,9 +62,9 @@ LLUIColor LLViewerParcelOverlay::sForSaleColor; LLUIColor LLViewerParcelOverlay::sAuctionColor; LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters) -: mRegion( region ), - mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ), - mDirty( false ), +: mRegion(region), + mParcelGridsPerEdge(S32(region_width_meters / PARCEL_GRID_STEP_METERS)), + mDirty(false), mTimeSinceLastUpdate(), mOverlayTextureIdx(-1) { @@ -431,7 +431,6 @@ void LLViewerParcelOverlay::updateOverlayTexture() } } - void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay) { // Unpack the message data into the ownership array @@ -467,9 +466,9 @@ void LLViewerParcelOverlay::updatePropertyLines() { for (S32 col = 0; col < GRIDS_PER_EDGE; col++) { - U8 overlay = mOwnership[row*GRIDS_PER_EDGE+col]; + U8 overlay = mOwnership[row * GRIDS_PER_EDGE + col]; S32 colorIndex = overlay & PARCEL_COLOR_MASK; - switch(colorIndex) + switch (colorIndex) { case PARCEL_SELF: case PARCEL_GROUP: @@ -483,11 +482,11 @@ void LLViewerParcelOverlay::updatePropertyLines() const LLColor4U& color = colors[colorIndex]; - F32 left = col*GRID_STEP; - F32 right = left+GRID_STEP; + F32 left = col * GRID_STEP; + F32 right = left + GRID_STEP; - F32 bottom = row*GRID_STEP; - F32 top = bottom+GRID_STEP; + F32 bottom = row * GRID_STEP; + F32 top = bottom + GRID_STEP; // West edge if (overlay & PARCEL_WEST_LINE) @@ -528,99 +527,107 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 Edge& edge = mEdges.back(); edge.color = color; + // Detailized rendering vertices: + // A B C D E F G + // *-*------*--------*--------*------*-* : 'outside' vertices are placed right on the border + // *------*--------*--------*------* : 'inside' vertices are shifted on LINE_WIDTH inside + + // Simplified rendering vertices: + // A G + // *-----------------------------------* + // *-----------------------------------* + F32 outside_x = start_x; F32 outside_y = start_y; - F32 outside_z = 0.f; - F32 inside_x = start_x + tick_dx; - F32 inside_y = start_y + tick_dy; - F32 inside_z = 0.f; + F32 outside_z = land.resolveHeightRegion(outside_x, outside_y); + F32 inside_x = start_x + tick_dx; + F32 inside_y = start_y + tick_dy; + F32 inside_z = land.resolveHeightRegion(inside_x, inside_y); - auto split = [&](const LLVector3& start, F32 x, F32 y, F32 z, F32 part) + auto move = [&](F32 distance) + { + outside_x += dx * distance; + outside_y += dy * distance; + outside_z = land.resolveHeightRegion(outside_x, outside_y); + inside_x += dx * distance; + inside_y += dy * distance; + inside_z = land.resolveHeightRegion(inside_x, inside_y); + }; + + auto split = [&](U32 lod, const LLVector3& start, F32 x, F32 y, F32 z, F32 part) { F32 new_x = start.mV[0] + (x - start.mV[0]) * part; F32 new_y = start.mV[1] + (y - start.mV[1]) * part; F32 new_z = start.mV[2] + (z - start.mV[2]) * part; - edge.vertices.emplace_back(new_x, new_y, new_z); + edge.vertices[lod].emplace_back(new_x, new_y, new_z); }; - auto checkForSplit = [&]() + auto checkForSplit = [&](U32 lod) { - const LLVector3& last_outside = edge.vertices.back(); + const std::vector<LLVector3>& vertices = edge.vertices[lod]; + const LLVector3& last_outside = vertices.back(); F32 z0 = last_outside.mV[2]; F32 z1 = outside_z; if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z)) return; F32 part = (water_z - z0) / (z1 - z0); - const LLVector3& last_inside = edge.vertices[edge.vertices.size() - 2]; - split(last_inside, inside_x, inside_y, inside_z, part); - split(last_outside, outside_x, outside_y, outside_z, part); + const LLVector3& last_inside = vertices[vertices.size() - 2]; + split(lod, last_inside, inside_x, inside_y, inside_z, part); + split(lod, last_outside, outside_x, outside_y, outside_z, part); }; - // First part, only one vertex - outside_z = land.resolveHeightRegion( outside_x, outside_y ); - - edge.vertices.emplace_back(outside_x, outside_y, outside_z); - - inside_x += dx * LINE_WIDTH; - inside_y += dy * LINE_WIDTH; - - outside_x += dx * LINE_WIDTH; - outside_y += dy * LINE_WIDTH; - - // Then the "actual edge" - inside_z = land.resolveHeightRegion( inside_x, inside_y ); - outside_z = land.resolveHeightRegion( outside_x, outside_y ); + auto pushTwoVertices = [&](U32 lod) + { + if (fabs(inside_z - outside_z) < LINE_WIDTH / 5) + { + edge.vertices[lod].emplace_back(inside_x, inside_y, inside_z); + } + else + { + // Make the line thinner if heights differ too much + LLVector3 out(outside_x, outside_y, outside_z); + LLVector3 in(inside_x, inside_y, inside_z); + LLVector3 dist(in - out); + F32 coef = dist.length() / LINE_WIDTH; + LLVector3 new_in(out + dist / coef); + edge.vertices[lod].push_back(new_in); + } + edge.vertices[lod].emplace_back(outside_x, outside_y, outside_z); + }; - edge.vertices.emplace_back(inside_x, inside_y, inside_z); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); + // Point A simplified (first two vertices) + pushTwoVertices(1); - inside_x += dx * (dx - LINE_WIDTH); - inside_y += dy * (dy - LINE_WIDTH); + // Point A detailized (only one vertex) + edge.vertices[0].emplace_back(outside_x, outside_y, outside_z); - outside_x += dx * (dx - LINE_WIDTH); - outside_y += dy * (dy - LINE_WIDTH); + // Point B (two vertices) + move(LINE_WIDTH); + pushTwoVertices(0); - // Middle part, full width - const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS ); - for (S32 i = 1; i < GRID_STEP; i++) + // Points C, D, E + F32 distance = 1.f - LINE_WIDTH; + const U32 GRID_STEP = (U32)PARCEL_GRID_STEP_METERS; + for (U32 i = 1; i < GRID_STEP; ++i) { - inside_z = land.resolveHeightRegion( inside_x, inside_y ); - outside_z = land.resolveHeightRegion( outside_x, outside_y ); - - checkForSplit(); - - edge.vertices.emplace_back(inside_x, inside_y, inside_z); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); - - inside_x += dx; - inside_y += dy; - - outside_x += dx; - outside_y += dy; + move(distance); + checkForSplit(0); + pushTwoVertices(0); + distance = 1.f; } - // Extra buffer for edge - inside_x -= dx * LINE_WIDTH; - inside_y -= dy * LINE_WIDTH; + // Point F (two vertices) + move(1.f - LINE_WIDTH); + checkForSplit(0); + pushTwoVertices(0); - outside_x -= dx * LINE_WIDTH; - outside_y -= dy * LINE_WIDTH; + // Point G simplified (last two vertices) + move(LINE_WIDTH); + checkForSplit(1); + pushTwoVertices(1); - inside_z = land.resolveHeightRegion( inside_x, inside_y ); - outside_z = land.resolveHeightRegion( outside_x, outside_y ); - - checkForSplit(); - - edge.vertices.emplace_back(inside_x, inside_y, inside_z); - edge.vertices.emplace_back(outside_x, outside_y, outside_z); - - outside_x += dx * LINE_WIDTH; - outside_y += dy * LINE_WIDTH; - - // Last edge is not drawn to the edge - outside_z = land.resolveHeightRegion( outside_x, outside_y ); - - edge.vertices.emplace_back(outside_x, outside_y, outside_z); + // Point G detailized (only one vertex) + edge.vertices[0].emplace_back(outside_x, outside_y, outside_z); } void LLViewerParcelOverlay::setDirty() @@ -710,12 +717,15 @@ void LLViewerParcelOverlay::renderPropertyLines() bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build"); const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; + const F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25; for (const Edge& edge : mEdges) { - LLVector3 center = edge.vertices[edge.vertices.size() >> 1]; + const std::vector<LLVector3>& vertices0 = edge.vertices[0]; + LLVector3 center = (vertices0.front() + vertices0.back()) / 2; + F32 dist_squared = dist_vec_squared(center, camera_region); - if (dist_vec_squared2D(center, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED) + if (dist_squared > PROPERTY_LINE_CLIP_DIST_SQUARED) { continue; } @@ -729,11 +739,13 @@ void LLViewerParcelOverlay::renderPropertyLines() continue; } + U32 lod = dist_squared < PROPERTY_LINE_LOD0_DIST_SQUARED ? 0 : 1; + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.color4ubv(edge.color.mV); - for (const LLVector3& vertex : edge.vertices) + for (const LLVector3& vertex : edge.vertices[lod]) { if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z) { @@ -759,7 +771,7 @@ void LLViewerParcelOverlay::renderPropertyLines() color.mV[3] /= 4; gGL.color4ubv(color.mV); - for (const LLVector3& vertex : edge.vertices) + for (const LLVector3& vertex : edge.vertices[lod]) { gGL.vertex3fv(vertex.mV); } diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 03ae464cb8..875b32e79a 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -119,7 +119,7 @@ private: struct Edge { - std::vector<LLVector3> vertices; + std::vector<LLVector3> vertices[2]; // 0 - detailized, 1 - simplified LLColor4U color; }; -- cgit v1.2.3 From 9e5d0f3cb6ced5601e41cce15c79719e0fa3b571 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Wed, 25 Sep 2024 18:58:03 +0300 Subject: #2650 Add UI controls for debug settings: RenderTonemapMix RenderTonemapType --- .../en/floater_preferences_graphics_advanced.xml | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 2fa965b6e4..73ea0f548e 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -943,6 +943,57 @@ width="260"> </slider> <!-- End of Sharpening Settings--> + <!-- Tone Mapping Settings --> + <text + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + left="420" + name="TonemapTypeText" + text_readonly_color="LabelDisabledColor" + top_delta="25" + width="128"> + Tone Mapper: + </text> + <combo_box + control_name="RenderTonemapType" + height="18" + layout="topleft" + left_delta="130" + top_delta="0" + name="TonemapType" + width="150"> + <combo_box.item + label="Khronos Neutral" + name="0" + value="0"/> + <combo_box.item + label="ACES" + name="1" + value="1"/> + </combo_box> + <slider + control_name="RenderTonemapMix" + decimal_digits="1" + follows="left|top" + height="16" + increment="0.1" + initial_value="1" + label="Tone Mapping Mix:" + tool_tip="Mix between linear and tone mapped colors" + label_width="145" + layout="topleft" + left="420" + min_val="0.0" + max_val="1.0" + name="TonemapMix" + show_text="true" + top_delta="22" + width="260"> + </slider> + <!-- End of Tone Mapping Settings--> <!-- End of Advanced Settings block --> <view_border bevel_style="in" -- cgit v1.2.3 From b48c1b530f6c0f3c33f7546a8f24d66007905b16 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller <Ansariel@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:08:58 +0200 Subject: More improvements and cleanup of LLViewerParcelOverlay (#2678) --- indra/newview/llagentcamera.cpp | 10 ----- indra/newview/llviewerparceloverlay.cpp | 78 ++++++++++++++++----------------- indra/newview/llviewerparceloverlay.h | 13 +++--- 3 files changed, 44 insertions(+), 57 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 81e79a2ed9..d4767e18af 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1988,16 +1988,6 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(bool *hit_limit) isConstrained = true; } } - -// JC - Could constrain camera based on parcel stuff here. -// LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(camera_position_global); -// -// if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global))) -// { -// camera_position_global = last_position_global; -// -// isConstrained = true; -// } } // Don't let camera go underground diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index f1a8d83aef..2077cbdd08 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -33,6 +33,7 @@ #include "llfloaterreg.h" #include "llgl.h" #include "llrender.h" +#include "lluicolor.h" #include "v4color.h" #include "v2math.h" @@ -50,8 +51,8 @@ #include "pipeline.h" -static const U8 OVERLAY_IMG_COMPONENTS = 4; -static const F32 LINE_WIDTH = 0.0625f; +static constexpr U8 OVERLAY_IMG_COMPONENTS = 4; +static constexpr F32 LINE_WIDTH = 0.0625f; bool LLViewerParcelOverlay::sColorSetInitialized = false; LLUIColor LLViewerParcelOverlay::sAvailColor; @@ -91,7 +92,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_ // Initialize the GL texture with empty data. // // Create the base texture. - U8 *raw = mImageRaw->getData(); + U8* raw = mImageRaw->getData(); const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge * OVERLAY_IMG_COMPONENTS; for (S32 i = 0; i < COUNT; i++) { @@ -158,10 +159,10 @@ bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) co LLVector3 min = boxes[i].getMinAgent(); LLVector3 max = boxes[i].getMaxAgent(); - S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); for (S32 row = top; row <= bottom; row++) { @@ -186,10 +187,10 @@ bool LLViewerParcelOverlay::encroachesOnUnowned(const std::vector<LLBBox>& boxes LLVector3 min = boxes[i].getMinAgent(); LLVector3 max = boxes[i].getMaxAgent(); - S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); for (S32 row = top; row <= bottom; row++) { @@ -223,10 +224,10 @@ bool LLViewerParcelOverlay::encroachesOnNearbyParcel(const std::vector<LLBBox>& return true; } - S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); + S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f)); const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge; @@ -348,11 +349,11 @@ void LLViewerParcelOverlay::updateOverlayTexture() const LLColor4U auction = sAuctionColor.get(); // Create the base texture. - U8 *raw = mImageRaw->getData(); + U8* raw = mImageRaw->getData(); const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge; S32 max = mOverlayTextureIdx + mParcelGridsPerEdge; if (max > COUNT) max = COUNT; - S32 pixel_index = mOverlayTextureIdx*OVERLAY_IMG_COMPONENTS; + S32 pixel_index = mOverlayTextureIdx * OVERLAY_IMG_COMPONENTS; S32 i; for (i = mOverlayTextureIdx; i < max; i++) { @@ -361,7 +362,7 @@ void LLViewerParcelOverlay::updateOverlayTexture() U8 r,g,b,a; // Color stored in low three bits - switch( ownership & 0x7 ) + switch (ownership & 0x7) { case PARCEL_PUBLIC: r = avail.mV[VRED]; @@ -407,10 +408,10 @@ void LLViewerParcelOverlay::updateOverlayTexture() break; } - raw[pixel_index + 0] = (U8)r; - raw[pixel_index + 1] = (U8)g; - raw[pixel_index + 2] = (U8)b; - raw[pixel_index + 3] = (U8)a; + raw[pixel_index + VRED] = (U8)r; + raw[pixel_index + VGREEN] = (U8)g; + raw[pixel_index + VBLUE] = (U8)b; + raw[pixel_index + VALPHA] = (U8)a; pixel_index += OVERLAY_IMG_COMPONENTS; } @@ -431,10 +432,10 @@ void LLViewerParcelOverlay::updateOverlayTexture() } } -void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay) +void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8* packed_overlay) { // Unpack the message data into the ownership array - S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge; + S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge; S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS; memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size); /*Flawfinder: ignore*/ @@ -459,7 +460,7 @@ void LLViewerParcelOverlay::updatePropertyLines() mEdges.clear(); - const F32 GRID_STEP = PARCEL_GRID_STEP_METERS; + constexpr F32 GRID_STEP = PARCEL_GRID_STEP_METERS; const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge; for (S32 row = 0; row < GRIDS_PER_EDGE; row++) @@ -556,9 +557,9 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 auto split = [&](U32 lod, const LLVector3& start, F32 x, F32 y, F32 z, F32 part) { - F32 new_x = start.mV[0] + (x - start.mV[0]) * part; - F32 new_y = start.mV[1] + (y - start.mV[1]) * part; - F32 new_z = start.mV[2] + (z - start.mV[2]) * part; + F32 new_x = start.mV[VX] + (x - start.mV[VX]) * part; + F32 new_y = start.mV[VY] + (y - start.mV[VY]) * part; + F32 new_z = start.mV[VZ] + (z - start.mV[VZ]) * part; edge.vertices[lod].emplace_back(new_x, new_y, new_z); }; @@ -566,7 +567,7 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 { const std::vector<LLVector3>& vertices = edge.vertices[lod]; const LLVector3& last_outside = vertices.back(); - F32 z0 = last_outside.mV[2]; + F32 z0 = last_outside.mV[VZ]; F32 z1 = outside_z; if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z)) return; @@ -589,8 +590,7 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 LLVector3 in(inside_x, inside_y, inside_z); LLVector3 dist(in - out); F32 coef = dist.length() / LINE_WIDTH; - LLVector3 new_in(out + dist / coef); - edge.vertices[lod].push_back(new_in); + edge.vertices[lod].emplace_back(out + dist / coef); } edge.vertices[lod].emplace_back(outside_x, outside_y, outside_z); }; @@ -607,7 +607,7 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 // Points C, D, E F32 distance = 1.f - LINE_WIDTH; - const U32 GRID_STEP = (U32)PARCEL_GRID_STEP_METERS; + constexpr U32 GRID_STEP = (U32)PARCEL_GRID_STEP_METERS; for (U32 i = 1; i < GRID_STEP; ++i) { move(distance); @@ -716,8 +716,8 @@ void LLViewerParcelOverlay::renderPropertyLines() bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build"); - const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; - const F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25; + constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; + constexpr F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25.f; for (const Edge& edge : mEdges) { @@ -754,7 +754,7 @@ void LLViewerParcelOverlay::renderPropertyLines() else { LLVector3 visible = vertex; - visible.mV[2] = water_z; + visible.mV[VZ] = water_z; gGL.vertex3fv(visible.mV); } } @@ -768,7 +768,7 @@ void LLViewerParcelOverlay::renderPropertyLines() gGL.begin(LLRender::TRIANGLE_STRIP); LLColor4U color = edge.color; - color.mV[3] /= 4; + color.mV[VALPHA] /= 4; gGL.color4ubv(color.mV); for (const LLVector3& vertex : edge.vertices[lod]) @@ -802,7 +802,7 @@ void grid_2d_part_lines(const F32 left, const F32 top, const F32 right, const F3 gGL.end(); } -void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color) +void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color) { static LLCachedControl<bool> show(gSavedSettings, "MiniMapShowPropertyLines"); @@ -813,8 +813,8 @@ void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_me LLVector3 origin_agent = mRegion->getOriginAgent(); LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent(); - F32 region_left = rel_region_pos.mV[0] * scale_pixels_per_meter; - F32 region_bottom = rel_region_pos.mV[1] * scale_pixels_per_meter; + F32 region_left = rel_region_pos.mV[VX] * scale_pixels_per_meter; + F32 region_bottom = rel_region_pos.mV[VY] * scale_pixels_per_meter; F32 map_parcel_width = PARCEL_GRID_STEP_METERS * scale_pixels_per_meter; const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge; diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 875b32e79a..68900d16a6 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -34,12 +34,11 @@ #include "llframetimer.h" #include "lluuid.h" #include "llviewertexture.h" -#include "llgl.h" -#include "lluicolor.h" class LLViewerRegion; class LLVector3; class LLColor4U; +class LLUIColor; class LLVector2; class LLViewerParcelOverlay : public LLGLUpdate @@ -65,19 +64,18 @@ public: bool isSoundLocal(const LLVector3& pos) const; - bool isBuildCameraAllowed(const LLVector3& pos) const; F32 getOwnedRatio() const; // Returns the number of vertices drawn void renderPropertyLines(); void renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color); - U8 ownership( const LLVector3& pos) const; - U8 parcelLineFlags( const LLVector3& pos) const; + U8 ownership(const LLVector3& pos) const; + U8 parcelLineFlags(const LLVector3& pos) const; U8 parcelLineFlags(S32 row, S32 col) const; // MANIPULATE - void uncompressLandOverlay(S32 chunk, U8 *compressed_overlay); + void uncompressLandOverlay(S32 chunk, U8* compressed_overlay); // Indicate property lines and overlay texture need to be rebuilt. void setDirty(); @@ -88,8 +86,7 @@ public: private: // This is in parcel rows and columns, not grid rows and columns // Stored in bottom three bits. - U8 ownership(S32 row, S32 col) const - { return parcelFlags(row, col, (U8)0x7); } + U8 ownership(S32 row, S32 col) const { return parcelFlags(row, col, (U8)0x7); } U8 parcelFlags(S32 row, S32 col, U8 flags) const; -- cgit v1.2.3 From 5a445b41c37c498210794fdf90620f7661e93462 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Wed, 25 Sep 2024 22:14:39 +0200 Subject: Remove orphaned LLPanelOutfitSnapshotInventory --- indra/newview/llpanelsnapshotinventory.cpp | 106 ++++------------------------- indra/newview/llpanelsnapshotlocal.cpp | 20 +++--- indra/newview/llpanelsnapshotoptions.cpp | 4 +- indra/newview/llpanelsnapshotpostcard.cpp | 20 +++--- indra/newview/llpanelsnapshotprofile.cpp | 18 ++--- 5 files changed, 45 insertions(+), 123 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp index 5a7dd92b98..79c48e2663 100644 --- a/indra/newview/llpanelsnapshotinventory.cpp +++ b/indra/newview/llpanelsnapshotinventory.cpp @@ -42,77 +42,33 @@ /** * The panel provides UI for saving snapshot as an inventory texture. */ -class LLPanelSnapshotInventoryBase - : public LLPanelSnapshot -{ - LOG_CLASS(LLPanelSnapshotInventoryBase); - -public: - LLPanelSnapshotInventoryBase(); - - /*virtual*/ bool postBuild(); -protected: - void onSend(); - /*virtual*/ LLSnapshotModel::ESnapshotType getSnapshotType(); -}; - class LLPanelSnapshotInventory - : public LLPanelSnapshotInventoryBase + : public LLPanelSnapshot { LOG_CLASS(LLPanelSnapshotInventory); public: LLPanelSnapshotInventory(); - /*virtual*/ bool postBuild(); - /*virtual*/ void onOpen(const LLSD& key); + bool postBuild() override; + void onOpen(const LLSD& key) override; void onResolutionCommit(LLUICtrl* ctrl); private: - /*virtual*/ std::string getWidthSpinnerName() const { return "inventory_snapshot_width"; } - /*virtual*/ std::string getHeightSpinnerName() const { return "inventory_snapshot_height"; } - /*virtual*/ std::string getAspectRatioCBName() const { return "inventory_keep_aspect_check"; } - /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; } - /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; } - /*virtual*/ void updateControls(const LLSD& info); - -}; - -class LLPanelOutfitSnapshotInventory - : public LLPanelSnapshotInventoryBase -{ - LOG_CLASS(LLPanelOutfitSnapshotInventory); + std::string getWidthSpinnerName() const override { return "inventory_snapshot_width"; } + std::string getHeightSpinnerName() const override { return "inventory_snapshot_height"; } + std::string getAspectRatioCBName() const override { return "inventory_keep_aspect_check"; } + std::string getImageSizeComboName() const override { return "texture_size_combo"; } + std::string getImageSizePanelName() const override { return LLStringUtil::null; } + LLSnapshotModel::ESnapshotType getSnapshotType() override; + void updateControls(const LLSD& info) override; -public: - LLPanelOutfitSnapshotInventory(); - /*virtual*/ bool postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - -private: - /*virtual*/ std::string getWidthSpinnerName() const { return ""; } - /*virtual*/ std::string getHeightSpinnerName() const { return ""; } - /*virtual*/ std::string getAspectRatioCBName() const { return ""; } - /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; } - /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; } - /*virtual*/ void updateControls(const LLSD& info); - - /*virtual*/ void cancel(); + void onSend(); }; static LLPanelInjector<LLPanelSnapshotInventory> panel_class1("llpanelsnapshotinventory"); -static LLPanelInjector<LLPanelOutfitSnapshotInventory> panel_class2("llpaneloutfitsnapshotinventory"); - -LLPanelSnapshotInventoryBase::LLPanelSnapshotInventoryBase() -{ -} - -bool LLPanelSnapshotInventoryBase::postBuild() -{ - return LLPanelSnapshot::postBuild(); -} - -LLSnapshotModel::ESnapshotType LLPanelSnapshotInventoryBase::getSnapshotType() +LLSnapshotModel::ESnapshotType LLPanelSnapshotInventory::getSnapshotType() { return LLSnapshotModel::SNAPSHOT_TEXTURE; } @@ -130,7 +86,7 @@ bool LLPanelSnapshotInventory::postBuild() getChild<LLSpinCtrl>(getHeightSpinnerName())->setAllowEdit(false); getChild<LLUICtrl>(getImageSizeComboName())->setCommitCallback(boost::bind(&LLPanelSnapshotInventory::onResolutionCommit, this, _1)); - return LLPanelSnapshotInventoryBase::postBuild(); + return LLPanelSnapshot::postBuild(); } // virtual @@ -153,7 +109,7 @@ void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl) getChild<LLSpinCtrl>(getHeightSpinnerName())->setVisible(!current_window_selected); } -void LLPanelSnapshotInventoryBase::onSend() +void LLPanelSnapshotInventory::onSend() { S32 w = 0; S32 h = 0; @@ -187,37 +143,3 @@ void LLPanelSnapshotInventoryBase::onSend() } } } - -LLPanelOutfitSnapshotInventory::LLPanelOutfitSnapshotInventory() -{ - mCommitCallbackRegistrar.add("Inventory.SaveOutfitPhoto", { boost::bind(&LLPanelOutfitSnapshotInventory::onSend, this), cb_info::UNTRUSTED_BLOCK }); - mCommitCallbackRegistrar.add("Inventory.SaveOutfitCancel", { boost::bind(&LLPanelOutfitSnapshotInventory::cancel, this), cb_info::UNTRUSTED_BLOCK }); -} - -// virtual -bool LLPanelOutfitSnapshotInventory::postBuild() -{ - return LLPanelSnapshotInventoryBase::postBuild(); -} - -// virtual -void LLPanelOutfitSnapshotInventory::onOpen(const LLSD& key) -{ - getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost())); - LLPanelSnapshot::onOpen(key); -} - -// virtual -void LLPanelOutfitSnapshotInventory::updateControls(const LLSD& info) -{ - const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true; - getChild<LLUICtrl>("save_btn")->setEnabled(have_snapshot); -} - -void LLPanelOutfitSnapshotInventory::cancel() -{ - if (mSnapshotFloater) - { - mSnapshotFloater->closeFloater(); - } -} diff --git a/indra/newview/llpanelsnapshotlocal.cpp b/indra/newview/llpanelsnapshotlocal.cpp index aea002bb91..d1807ca3f8 100644 --- a/indra/newview/llpanelsnapshotlocal.cpp +++ b/indra/newview/llpanelsnapshotlocal.cpp @@ -47,18 +47,18 @@ class LLPanelSnapshotLocal public: LLPanelSnapshotLocal(); - /*virtual*/ bool postBuild(); - /*virtual*/ void onOpen(const LLSD& key); + bool postBuild() override; + void onOpen(const LLSD& key) override; private: - /*virtual*/ std::string getWidthSpinnerName() const { return "local_snapshot_width"; } - /*virtual*/ std::string getHeightSpinnerName() const { return "local_snapshot_height"; } - /*virtual*/ std::string getAspectRatioCBName() const { return "local_keep_aspect_check"; } - /*virtual*/ std::string getImageSizeComboName() const { return "local_size_combo"; } - /*virtual*/ std::string getImageSizePanelName() const { return "local_image_size_lp"; } - /*virtual*/ LLSnapshotModel::ESnapshotFormat getImageFormat() const; - /*virtual*/ LLSnapshotModel::ESnapshotType getSnapshotType(); - /*virtual*/ void updateControls(const LLSD& info); + std::string getWidthSpinnerName() const override { return "local_snapshot_width"; } + std::string getHeightSpinnerName() const override { return "local_snapshot_height"; } + std::string getAspectRatioCBName() const override { return "local_keep_aspect_check"; } + std::string getImageSizeComboName() const override { return "local_size_combo"; } + std::string getImageSizePanelName() const override { return "local_image_size_lp"; } + LLSnapshotModel::ESnapshotFormat getImageFormat() const override; + LLSnapshotModel::ESnapshotType getSnapshotType() override; + void updateControls(const LLSD& info) override; S32 mLocalFormat; diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp index 51fad92720..0d9f778a65 100644 --- a/indra/newview/llpanelsnapshotoptions.cpp +++ b/indra/newview/llpanelsnapshotoptions.cpp @@ -47,8 +47,8 @@ class LLPanelSnapshotOptions public: LLPanelSnapshotOptions(); ~LLPanelSnapshotOptions(); - /*virtual*/ bool postBuild(); - /*virtual*/ void onOpen(const LLSD& key); + bool postBuild() override; + void onOpen(const LLSD& key) override; private: void updateUploadCost(); diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index ac6d954091..3a17a1d58c 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -56,18 +56,18 @@ class LLPanelSnapshotPostcard public: LLPanelSnapshotPostcard(); - /*virtual*/ bool postBuild(); - /*virtual*/ void onOpen(const LLSD& key); + bool postBuild() override; + void onOpen(const LLSD& key) override; private: - /*virtual*/ std::string getWidthSpinnerName() const { return "postcard_snapshot_width"; } - /*virtual*/ std::string getHeightSpinnerName() const { return "postcard_snapshot_height"; } - /*virtual*/ std::string getAspectRatioCBName() const { return "postcard_keep_aspect_check"; } - /*virtual*/ std::string getImageSizeComboName() const { return "postcard_size_combo"; } - /*virtual*/ std::string getImageSizePanelName() const { return "postcard_image_size_lp"; } - /*virtual*/ LLSnapshotModel::ESnapshotFormat getImageFormat() const { return LLSnapshotModel::SNAPSHOT_FORMAT_JPEG; } - /*virtual*/ LLSnapshotModel::ESnapshotType getSnapshotType(); - /*virtual*/ void updateControls(const LLSD& info); + std::string getWidthSpinnerName() const override { return "postcard_snapshot_width"; } + std::string getHeightSpinnerName() const override { return "postcard_snapshot_height"; } + std::string getAspectRatioCBName() const override { return "postcard_keep_aspect_check"; } + std::string getImageSizeComboName() const override { return "postcard_size_combo"; } + std::string getImageSizePanelName() const override { return "postcard_image_size_lp"; } + LLSnapshotModel::ESnapshotFormat getImageFormat() const override { return LLSnapshotModel::SNAPSHOT_FORMAT_JPEG; } + LLSnapshotModel::ESnapshotType getSnapshotType() override; + void updateControls(const LLSD& info) override; bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response); static void sendPostcardFinished(LLSD result); diff --git a/indra/newview/llpanelsnapshotprofile.cpp b/indra/newview/llpanelsnapshotprofile.cpp index 35318461e8..960b507099 100644 --- a/indra/newview/llpanelsnapshotprofile.cpp +++ b/indra/newview/llpanelsnapshotprofile.cpp @@ -49,17 +49,17 @@ class LLPanelSnapshotProfile public: LLPanelSnapshotProfile(); - /*virtual*/ bool postBuild(); - /*virtual*/ void onOpen(const LLSD& key); + bool postBuild() override; + void onOpen(const LLSD& key) override; private: - /*virtual*/ std::string getWidthSpinnerName() const { return "profile_snapshot_width"; } - /*virtual*/ std::string getHeightSpinnerName() const { return "profile_snapshot_height"; } - /*virtual*/ std::string getAspectRatioCBName() const { return "profile_keep_aspect_check"; } - /*virtual*/ std::string getImageSizeComboName() const { return "profile_size_combo"; } - /*virtual*/ std::string getImageSizePanelName() const { return "profile_image_size_lp"; } - /*virtual*/ LLSnapshotModel::ESnapshotFormat getImageFormat() const { return LLSnapshotModel::SNAPSHOT_FORMAT_PNG; } - /*virtual*/ void updateControls(const LLSD& info); + std::string getWidthSpinnerName() const override { return "profile_snapshot_width"; } + std::string getHeightSpinnerName() const override { return "profile_snapshot_height"; } + std::string getAspectRatioCBName() const override { return "profile_keep_aspect_check"; } + std::string getImageSizeComboName() const override { return "profile_size_combo"; } + std::string getImageSizePanelName() const override { return "profile_image_size_lp"; } + LLSnapshotModel::ESnapshotFormat getImageFormat() const override { return LLSnapshotModel::SNAPSHOT_FORMAT_PNG; } + void updateControls(const LLSD& info) override; void onSend(); }; -- cgit v1.2.3 From ce7d6c789004befdbd26ac9d9f03f1610a9cf7fd Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Wed, 25 Sep 2024 23:05:44 +0200 Subject: Fix upload cost calculation for snapshots to inventory based on encoded image size and display upload cost to user --- indra/newview/llpanelsnapshotinventory.cpp | 42 +++++++++++++++------- .../default/xui/de/panel_snapshot_inventory.xml | 2 +- .../default/xui/en/panel_snapshot_inventory.xml | 4 ++- .../default/xui/es/panel_snapshot_inventory.xml | 2 +- .../default/xui/fr/panel_snapshot_inventory.xml | 2 +- .../default/xui/it/panel_snapshot_inventory.xml | 2 +- .../default/xui/ja/panel_snapshot_inventory.xml | 2 +- .../default/xui/pt/panel_snapshot_inventory.xml | 2 +- .../default/xui/ru/panel_snapshot_inventory.xml | 2 +- .../default/xui/tr/panel_snapshot_inventory.xml | 2 +- .../default/xui/zh/panel_snapshot_inventory.xml | 2 +- 11 files changed, 41 insertions(+), 23 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp index 79c48e2663..dda14c1e32 100644 --- a/indra/newview/llpanelsnapshotinventory.cpp +++ b/indra/newview/llpanelsnapshotinventory.cpp @@ -64,6 +64,8 @@ private: void updateControls(const LLSD& info) override; void onSend(); + void updateUploadCost(); + S32 calculateUploadCost(); }; static LLPanelInjector<LLPanelSnapshotInventory> panel_class1("llpanelsnapshotinventory"); @@ -92,6 +94,8 @@ bool LLPanelSnapshotInventory::postBuild() // virtual void LLPanelSnapshotInventory::onOpen(const LLSD& key) { + updateUploadCost(); + LLPanelSnapshot::onOpen(key); } @@ -100,6 +104,8 @@ void LLPanelSnapshotInventory::updateControls(const LLSD& info) { const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true; getChild<LLUICtrl>("save_btn")->setEnabled(have_snapshot); + + updateUploadCost(); } void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl) @@ -111,19 +117,7 @@ void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl) void LLPanelSnapshotInventory::onSend() { - S32 w = 0; - S32 h = 0; - - if( mSnapshotFloater ) - { - LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView(); - if( preview ) - { - preview->getSize(w, h); - } - } - - S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(w, h); + S32 expected_upload_cost = calculateUploadCost(); if (can_afford_transaction(expected_upload_cost)) { if (mSnapshotFloater) @@ -143,3 +137,25 @@ void LLPanelSnapshotInventory::onSend() } } } + +void LLPanelSnapshotInventory::updateUploadCost() +{ + getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", calculateUploadCost())); +} + +S32 LLPanelSnapshotInventory::calculateUploadCost() +{ + S32 w = 0; + S32 h = 0; + + if (mSnapshotFloater) + { + if (LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView()) + { + w = preview->getEncodedImageWidth(); + h = preview->getEncodedImageHeight(); + } + } + + return LLAgentBenefitsMgr::current().getTextureUploadCost(w, h); +} diff --git a/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml index 602424821f..09447cbbaf 100644 --- a/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ <combo_box.item label="Klein (128x128)" name="Small(128x128)"/> <combo_box.item label="Mittel (256x256)" name="Medium(256x256)"/> <combo_box.item label="Groß (512x512)" name="Large(512x512)"/> - <combo_box.item label="Aktuelles Fenster (512x512)" name="CurrentWindow"/> + <combo_box.item label="Aktuelles Fenster" name="CurrentWindow"/> <combo_box.item label="Benutzerdefiniert" name="Custom"/> </combo_box> <spinner label="Breite x Höhe" name="inventory_snapshot_width"/> diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml index f8040b9a65..0cac1b410f 100644 --- a/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml @@ -60,7 +60,7 @@ name="Large(512x512)" value="[i512,i512]" /> <combo_box.item - label="Current Window(512x512)" + label="Current Window" name="CurrentWindow" value="[i0,i0]" /> <combo_box.item @@ -119,6 +119,8 @@ type="string" word_wrap="true"> To save your image as a texture select one of the square formats. + +Upload cost: L$[UPLOAD_COST] </text> <button follows="right|bottom" diff --git a/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml index b5cf57ade7..c9eea9a58e 100644 --- a/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ Guardar una imagen en el inventario cuesta [UPLOAD_COST] L$. Para guardar una imagen como una textura, selecciona uno de los formatos cuadrados. </text> <combo_box label="Resolución" name="texture_size_combo"> - <combo_box.item label="Ventana actual (512 × 512)" name="CurrentWindow"/> + <combo_box.item label="Ventana actual" name="CurrentWindow"/> <combo_box.item label="Pequeña (128x128)" name="Small(128x128)"/> <combo_box.item label="Mediana (256x256)" name="Medium(256x256)"/> <combo_box.item label="Grande (512x512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml index 3cf64583d2..a560ff8d5e 100644 --- a/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ L'enregistrement d'une image dans l'inventaire coûte [UPLOAD_COST] L$. Pour enregistrer votre image sous forme de texture, sélectionnez un format carré. </text> <combo_box label="Résolution" name="texture_size_combo"> - <combo_box.item label="Fenêtre actuelle (512x512)" name="CurrentWindow"/> + <combo_box.item label="Fenêtre actuelle" name="CurrentWindow"/> <combo_box.item label="Petite (128 x 128)" name="Small(128x128)"/> <combo_box.item label="Moyenne (256 x 256)" name="Medium(256x256)"/> <combo_box.item label="Grande (512 x 512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml index 75b5d64660..21b65e8e69 100644 --- a/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ Salvare un'immagine nell'inventario costa L$[UPLOAD_COST]. Per salvare l'immagine come texture, selezionare uno dei formati quadrati. </text> <combo_box label="Risoluzione" name="texture_size_combo"> - <combo_box.item label="Finestra corrente (512x512)" name="CurrentWindow"/> + <combo_box.item label="Finestra corrente" name="CurrentWindow"/> <combo_box.item label="Piccola (128x128)" name="Small(128x128)"/> <combo_box.item label="Media (256x256)" name="Medium(256x256)"/> <combo_box.item label="Grande (512x512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml index c55c11e928..30542378cc 100644 --- a/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml @@ -6,7 +6,7 @@ </text> <view_border name="hr"/> <combo_box label="解像度" name="texture_size_combo"> - <combo_box.item label="現在のウィンドウ (512✕512)" name="CurrentWindow"/> + <combo_box.item label="現在のウィンドウ" name="CurrentWindow"/> <combo_box.item label="小(128✕128)" name="Small(128x128)"/> <combo_box.item label="中(256✕256)" name="Medium(256x256)"/> <combo_box.item label="大(512✕512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml index f3357026d5..28a5142baa 100644 --- a/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ Salvar uma imagem em seu inventário custa L$[UPLOAD_COST]. Para salvar sua imagem como uma textura, selecione um dos formatos quadrados. </text> <combo_box label="Resolução" name="texture_size_combo"> - <combo_box.item label="Janela ativa (512x512)" name="CurrentWindow"/> + <combo_box.item label="Janela ativa" name="CurrentWindow"/> <combo_box.item label="Pequeno (128x128)" name="Small(128x128)"/> <combo_box.item label="Médio (256x256)" name="Medium(256x256)"/> <combo_box.item label="Grande (512x512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml index f07e12e0ed..adc612dfd8 100644 --- a/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ Сохранение изображения в инвентаре стоит L$[UPLOAD_COST]. Чтобы сохранить его как текстуру, выберите один из квадратных форматов. </text> <combo_box label="Размер" name="texture_size_combo"> - <combo_box.item label="Текущее окно (512x512)" name="CurrentWindow"/> + <combo_box.item label="Текущее окно" name="CurrentWindow"/> <combo_box.item label="Маленький (128x128)" name="Small(128x128)"/> <combo_box.item label="Средний (256x256)" name="Medium(256x256)"/> <combo_box.item label="Большой (512x512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml index be5940c4b9..160cba8700 100644 --- a/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ Bir görüntüyü envanterinize kaydetmenin maliyeti L$[UPLOAD_COST] olur. Görüntünüzü bir doku olarak kaydetmek için kare formatlardan birini seçin. </text> <combo_box label="Çözünürlük" name="texture_size_combo"> - <combo_box.item label="Mevcut Pencere(512x512)" name="CurrentWindow"/> + <combo_box.item label="Mevcut Pencere" name="CurrentWindow"/> <combo_box.item label="Küçük (128x128)" name="Small(128x128)"/> <combo_box.item label="Orta (256x256)" name="Medium(256x256)"/> <combo_box.item label="Büyük (512x512)" name="Large(512x512)"/> diff --git a/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml index 094bf019b4..9c45c54a5e 100644 --- a/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml @@ -7,7 +7,7 @@ 將圖像儲存到收納區的費用為 L$[UPLOAD_COST]。 若要將圖像存為材質,請選擇一個正方格式。 </text> <combo_box label="解析度" name="texture_size_combo"> - <combo_box.item label="目前視窗(512x512)" name="CurrentWindow"/> + <combo_box.item label="目前視窗" name="CurrentWindow"/> <combo_box.item label="小(128x128)" name="Small(128x128)"/> <combo_box.item label="中(256x256)" name="Medium(256x256)"/> <combo_box.item label="大(512x512)" name="Large(512x512)"/> -- cgit v1.2.3 From 18bdbaa957674fea4653221f2226df7694c315a8 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Wed, 25 Sep 2024 23:12:27 +0200 Subject: Remove incorrectly calculated upload fee from snapshot options button based on previously selected snapshot type and not necessarily snapshot to inventory --- indra/newview/llpanelsnapshotoptions.cpp | 35 ---------------------- .../default/xui/de/panel_snapshot_options.xml | 2 +- .../default/xui/en/panel_snapshot_options.xml | 2 +- .../default/xui/es/panel_snapshot_options.xml | 2 +- .../default/xui/fr/panel_snapshot_options.xml | 2 +- .../default/xui/it/panel_snapshot_options.xml | 2 +- .../default/xui/ja/panel_snapshot_options.xml | 2 +- .../default/xui/pl/panel_snapshot_options.xml | 2 +- .../default/xui/pt/panel_snapshot_options.xml | 2 +- .../default/xui/ru/panel_snapshot_options.xml | 2 +- .../default/xui/tr/panel_snapshot_options.xml | 2 +- .../default/xui/zh/panel_snapshot_options.xml | 2 +- 12 files changed, 11 insertions(+), 46 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp index 0d9f778a65..eadf8df188 100644 --- a/indra/newview/llpanelsnapshotoptions.cpp +++ b/indra/newview/llpanelsnapshotoptions.cpp @@ -30,12 +30,8 @@ #include "llsidetraypanelcontainer.h" #include "llfloatersnapshot.h" // FIXME: create a snapshot model -#include "llsnapshotlivepreview.h" #include "llfloaterreg.h" -#include "llagentbenefits.h" - - /** * Provides several ways to save a snapshot. */ @@ -46,12 +42,9 @@ class LLPanelSnapshotOptions public: LLPanelSnapshotOptions(); - ~LLPanelSnapshotOptions(); bool postBuild() override; - void onOpen(const LLSD& key) override; private: - void updateUploadCost(); void openPanel(const std::string& panel_name); void onSaveToProfile(); void onSaveToEmail(); @@ -71,10 +64,6 @@ LLPanelSnapshotOptions::LLPanelSnapshotOptions() mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", { boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this) }); } -LLPanelSnapshotOptions::~LLPanelSnapshotOptions() -{ -} - // virtual bool LLPanelSnapshotOptions::postBuild() { @@ -82,30 +71,6 @@ bool LLPanelSnapshotOptions::postBuild() return LLPanel::postBuild(); } -// virtual -void LLPanelSnapshotOptions::onOpen(const LLSD& key) -{ - updateUploadCost(); -} - -void LLPanelSnapshotOptions::updateUploadCost() -{ - S32 w = 0; - S32 h = 0; - - if( mSnapshotFloater ) - { - LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView(); - if( preview ) - { - preview->getSize(w, h); - } - } - - S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(w, h); - getChild<LLUICtrl>("save_to_inventory_btn")->setLabelArg("[AMOUNT]", llformat("%d", upload_cost)); -} - void LLPanelSnapshotOptions::openPanel(const std::string& panel_name) { LLSideTrayPanelContainer* parent = dynamic_cast<LLSideTrayPanelContainer*>(getParent()); diff --git a/indra/newview/skins/default/xui/de/panel_snapshot_options.xml b/indra/newview/skins/default/xui/de/panel_snapshot_options.xml index dab20d63eb..2a51f10894 100644 --- a/indra/newview/skins/default/xui/de/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/de/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Auf Datenträger speichern" name="save_to_computer_btn"/> - <button label="In Inventar speichern ([AMOUNT] L$)" name="save_to_inventory_btn"/> + <button label="In Inventar speichern" name="save_to_inventory_btn"/> <button label="Im Profil-Feed teilen" name="save_to_profile_btn"/> <button label="Auf Facebook teilen" name="send_to_facebook_btn"/> <button label="Auf Twitter teilen" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml index 3a7731d235..2fb02af61c 100644 --- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml @@ -31,7 +31,7 @@ image_overlay_alignment="left" image_top_pad="-1" imgoverlay_label_space="10" - label="Save to Inventory (L$[AMOUNT])" + label="Save to Inventory" layout="topleft" left_delta="0" name="save_to_inventory_btn" diff --git a/indra/newview/skins/default/xui/es/panel_snapshot_options.xml b/indra/newview/skins/default/xui/es/panel_snapshot_options.xml index 4eb9ecf28f..f3119c739e 100644 --- a/indra/newview/skins/default/xui/es/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/es/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Guardar en disco" name="save_to_computer_btn"/> - <button label="Guardar en inventario (L$[AMOUNT])" name="save_to_inventory_btn"/> + <button label="Guardar en inventario" name="save_to_inventory_btn"/> <button label="Compartir en los comentarios de Mi perfil" name="save_to_profile_btn"/> <button label="Compartir en Facebook" name="send_to_facebook_btn"/> <button label="Compartir en Twitter" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml b/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml index bdedb9162f..52fa318f8e 100644 --- a/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Enreg. sur le disque" name="save_to_computer_btn"/> - <button label="Enreg. dans l'inventaire ([AMOUNT] L$)" name="save_to_inventory_btn"/> + <button label="Enreg. dans l'inventaire" name="save_to_inventory_btn"/> <button label="Partager sur le flux de profil" name="save_to_profile_btn"/> <button label="Partager sur Facebook" name="send_to_facebook_btn"/> <button label="Partager sur Twitter" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/it/panel_snapshot_options.xml b/indra/newview/skins/default/xui/it/panel_snapshot_options.xml index 50fb3d39fa..7fce171326 100644 --- a/indra/newview/skins/default/xui/it/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/it/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Salva sul disco" name="save_to_computer_btn"/> - <button label="Salva nell'inventario (L$[AMOUNT])" name="save_to_inventory_btn"/> + <button label="Salva nell'inventario" name="save_to_inventory_btn"/> <button label="Condividi sul feed del profilo" name="save_to_profile_btn"/> <button label="Condividi su Facebook" name="send_to_facebook_btn"/> <button label="Condividi su Twitter" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml index 7a1aa280ec..a979e31c9a 100644 --- a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="ディスクに保存" name="save_to_computer_btn"/> - <button label="インベントリに保存(L$ [AMOUNT])" name="save_to_inventory_btn"/> + <button label="インベントリに保存" name="save_to_inventory_btn"/> <button label="プロフィールフィードで共有する" name="save_to_profile_btn"/> <button label="メールで送信" name="save_to_email_btn"/> <text name="fee_hint_lbl"> diff --git a/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml b/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml index 016b9ca197..04c01940e1 100644 --- a/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel name="panel_snapshot_options"> <button label="Zapisz na dysku twardym" name="save_to_computer_btn" /> - <button label="Zapisz do Szafy ([AMOUNT]L$)" name="save_to_inventory_btn" /> + <button label="Zapisz do Szafy" name="save_to_inventory_btn" /> <button label="Wyślij na mój Kanał" name="save_to_profile_btn" /> <button label="Załaduj na Facebook" name="send_to_facebook_btn" /> <button label="Załaduj na Twitter" name="send_to_twitter_btn" /> diff --git a/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml b/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml index 067e5dbd76..f71bc7cd12 100644 --- a/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Salvar no disco" name="save_to_computer_btn"/> - <button label="Salvar em inventário (L$[AMOUNT])" name="save_to_inventory_btn"/> + <button label="Salvar em inventário" name="save_to_inventory_btn"/> <button label="Compartilhar no feed do perfil" name="save_to_profile_btn"/> <button label="Compartilhar no Facebook" name="send_to_facebook_btn"/> <button label="Compartilhar no Twitter" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml b/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml index 7ba03ee0c9..f7fda0b1dc 100644 --- a/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Сохранить на диске" name="save_to_computer_btn"/> - <button label="Сохранить в инвентаре (L$[AMOUNT])" name="save_to_inventory_btn"/> + <button label="Сохранить в инвентаре" name="save_to_inventory_btn"/> <button label="Поделиться в профиле" name="save_to_profile_btn"/> <button label="Поделиться в Facebook" name="send_to_facebook_btn"/> <button label="Поделиться в Twitter" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml b/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml index 1b48bbeec2..a028710b98 100644 --- a/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="Diske Kaydet" name="save_to_computer_btn"/> - <button label="Envantere Kaydet (L$[AMOUNT])" name="save_to_inventory_btn"/> + <button label="Envantere Kaydet" name="save_to_inventory_btn"/> <button label="Profil Akışında Paylaş" name="save_to_profile_btn"/> <button label="Facebook'ta Paylaş" name="send_to_facebook_btn"/> <button label="Twitter'da Paylaş" name="send_to_twitter_btn"/> diff --git a/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml b/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml index d7c65bb25e..d9536882ac 100644 --- a/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml +++ b/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_snapshot_options"> <button label="儲存到硬碟" name="save_to_computer_btn"/> - <button label="儲存到收納區(L$[AMOUNT])" name="save_to_inventory_btn"/> + <button label="儲存到收納區" name="save_to_inventory_btn"/> <button label="分享至檔案訊息發佈" name="save_to_profile_btn"/> <button label="分享到臉書" name="send_to_facebook_btn"/> <button label="分享到推特" name="send_to_twitter_btn"/> -- cgit v1.2.3 From 31e8a2565aa05bba7be7fd70b7516ca3a6df6082 Mon Sep 17 00:00:00 2001 From: Ansariel <ansariel.hiller@phoenixviewer.com> Date: Thu, 26 Sep 2024 01:34:59 +0200 Subject: Force snapshot update when opening a snapshot panel and the resolution is "Current Window" to determine correct image size and upload cost --- indra/newview/llpanelsnapshot.cpp | 12 ++++++++++++ .../skins/default/xui/ja/panel_snapshot_inventory.xml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanelsnapshot.cpp b/indra/newview/llpanelsnapshot.cpp index 32c9f6f402..56c0294dbe 100644 --- a/indra/newview/llpanelsnapshot.cpp +++ b/indra/newview/llpanelsnapshot.cpp @@ -37,6 +37,7 @@ // newview #include "llsidetraypanelcontainer.h" +#include "llsnapshotlivepreview.h" #include "llviewercontrol.h" // gSavedSettings #include "llagentbenefits.h" @@ -99,6 +100,17 @@ void LLPanelSnapshot::onOpen(const LLSD& key) { getParentByType<LLFloater>()->notify(LLSD().with("image-format-change", true)); } + + // If resolution is set to "Current Window", force a snapshot update + // each time a snapshot panel is opened to determine the correct + // image size (and upload fee) depending on the snapshot type. + if (mSnapshotFloater && getChild<LLUICtrl>(getImageSizeComboName())->getValue().asString() == "[i0,i0]") + { + if (LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView()) + { + preview->mForceUpdateSnapshot = true; + } + } } LLSnapshotModel::ESnapshotFormat LLPanelSnapshot::getImageFormat() const diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml index 30542378cc..04ecba4264 100644 --- a/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml +++ b/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml @@ -16,7 +16,7 @@ <spinner label="" name="inventory_snapshot_height"/> <check_box label="縦横比の固定" name="inventory_keep_aspect_check"/> <text name="hint_lbl"> - 画像をテクスチャとして保存する場合は、いずれかの正方形を選択してください。 + 画像をインベントリに保存するには L$[UPLOAD_COST] の費用がかかります。画像をテクスチャとして保存するには平方形式の 1 つを選択してください。 </text> <button label="キャンセル" name="cancel_btn"/> <button label="保存" name="save_btn"/> -- cgit v1.2.3 From 9bf8fb38b3348da47caa26ac89072590ddec1d99 Mon Sep 17 00:00:00 2001 From: Rider Linden <rider@lindenlab.com> Date: Wed, 25 Sep 2024 18:03:57 -0700 Subject: Issue #2687: Honor flag sent by server indicating server side autopilot is engaged. When flag is set allow sever to update local avatar rotation. --- indra/newview/llviewerobject.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 41b2c4b44b..6456c98093 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2325,6 +2325,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Set the rotation of the object followed by adjusting for the accumulated angular velocity (llSetTargetOmega) setRotation(new_rot * mAngularVelocityRot); + if ((mFlags & FLAGS_SERVER_AUTOPILOT) && asAvatar() && asAvatar()->isSelf()) + { + gAgent.resetAxes(); + gAgent.rotate(new_rot); + gAgentCamera.resetView(); + } setChanged(ROTATED | SILHOUETTE); } -- cgit v1.2.3 From b6cbad1cf6c6ae6293825da776ce2191175d4632 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 16 Sep 2024 20:29:53 +0300 Subject: Lua api for autopilot functions --- indra/newview/llagentlistener.cpp | 56 ++++++++++++++++++--------- indra/newview/scripts/lua/require/LLAgent.lua | 49 +++++++++++++++++++++++ 2 files changed, 86 insertions(+), 19 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index d9002bf073..120e52402d 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -87,14 +87,15 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("startAutoPilot", "Start the autopilot system using the following parameters:\n" "[\"target_global\"]: array of target global {x, y, z} position\n" - "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n" + "[\"stop_distance\"]: target maximum distance from target [default: autopilot guess]\n" "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n" "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]" "[\"allow_flying\"]: allow flying during autopilot [default: True]", //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n" //"[\"callback_data\"]: data to send back during a callback [default: none]", - &LLAgentListener::startAutoPilot); + &LLAgentListener::startAutoPilot, + llsd::map("target_global", LLSD())); add("getAutoPilot", "Send information about current state of the autopilot system to [\"reply\"]:\n" "[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n" @@ -107,13 +108,14 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"rotation_threshold\"]: target maximum angle from target facing rotation\n" "[\"behavior_name\"]: name of the autopilot behavior", &LLAgentListener::getAutoPilot, - LLSDMap("reply", LLSD())); + llsd::map("reply", LLSD())); add("startFollowPilot", "[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n" "[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n" "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" - "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]", - &LLAgentListener::startFollowPilot); + "[\"stop_distance\"]: target maximum distance from target [default: autopilot guess]", + &LLAgentListener::startFollowPilot, + llsd::map("reply", LLSD())); add("setAutoPilotTarget", "Update target for currently running autopilot:\n" "[\"target_global\"]: array of target global {x, y, z} position", @@ -205,7 +207,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const //mAgent.getAvatarObject()->sitOnObject(); // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand() // *TODO - find a permanent place to share this code properly. - + Response response(LLSD(), event_data); LLViewerObject *object = NULL; if (event_data.has("obj_uuid")) { @@ -216,6 +218,12 @@ void LLAgentListener::requestSit(LLSD const & event_data) const LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); object = findObjectClosestTo(target_position); } + else + { + //just sit on the ground + mAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + return; + } if (object && object->getPCode() == LL_PCODE_VOLUME) { @@ -231,8 +239,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const } else { - LL_WARNS() << "LLAgent requestSit could not find the sit target: " - << event_data << LL_ENDL; + response.error("requestSit could not find the sit target"); } } @@ -354,11 +361,10 @@ void LLAgentListener::getPosition(const LLSD& event_data) const void LLAgentListener::startAutoPilot(LLSD const & event_data) { - LLQuaternion target_rotation_value; LLQuaternion* target_rotation = NULL; if (event_data.has("target_rotation")) { - target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); + LLQuaternion target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); target_rotation = &target_rotation_value; } // *TODO: Use callback_pump and callback_data @@ -381,11 +387,17 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) stop_distance = (F32)event_data["stop_distance"].asReal(); } + std::string behavior_name = LLCoros::getName(); + if (event_data.has("behavior_name")) + { + behavior_name = event_data["behavior_name"].asString(); + } + // Clear follow target, this is doing a path mFollowTarget.setNull(); mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]), - event_data["behavior_name"], + behavior_name, target_rotation, NULL, NULL, stop_distance, @@ -395,7 +407,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) void LLAgentListener::getAutoPilot(const LLSD& event_data) const { - LLSD reply = LLSD::emptyMap(); + Response reply(LLSD(), event_data); LLSD::Boolean enabled = mAgent.getAutoPilot(); reply["enabled"] = enabled; @@ -424,12 +436,11 @@ void LLAgentListener::getAutoPilot(const LLSD& event_data) const reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold(); reply["behavior_name"] = mAgent.getAutoPilotBehaviorName(); reply["fly"] = (LLSD::Boolean) mAgent.getFlying(); - - sendReply(reply, event_data); } void LLAgentListener::startFollowPilot(LLSD const & event_data) { + Response response(LLSD(), event_data); LLUUID target_id; bool allow_flying = true; @@ -463,6 +474,10 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data) } } } + else + { + return response.error("'leader_id' or 'avatar_name' should be specified"); + } F32 stop_distance = 0.f; if (event_data.has("stop_distance")) @@ -470,13 +485,16 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data) stop_distance = (F32)event_data["stop_distance"].asReal(); } - if (target_id.notNull()) + if (!gObjectList.findObject(target_id)) { - mAgent.setFlying(allow_flying); - mFollowTarget = target_id; // Save follow target so we can report distance later - - mAgent.startFollowPilot(target_id, allow_flying, stop_distance); + std::string target_info = event_data.has("leader_id") ? event_data["target_id"] : event_data["avatar_name"]; + return response.error(stringize("Target ", std::quoted(target_info), " was not found")); } + + mAgent.setFlying(allow_flying); + mFollowTarget = target_id; // Save follow target so we can report distance later + + mAgent.startFollowPilot(target_id, allow_flying, stop_distance); } void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 5cee998fcd..7b12493acc 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -80,4 +80,53 @@ function LLAgent.teleport(...) return leap.request('LLTeleportHandler', args).message end +function LLAgent.requestSit(...) + local args = mapargs('obj_uuid,position', ...) + args.op = 'requestSit' + return leap.request('LLAgent', args) +end + +function LLAgent.requestStand() + leap.send('LLAgent', {op = 'requestStand'}) +end + +-- Start the autopilot to move to "target_global" location using specified parameters +-- LLAgent.startAutoPilot{ target_global array of target global {x, y, z} position +-- [, allow_flying] allow flying during autopilot [default: true] +-- [, stop_distance] target maximum distance from target [default: autopilot guess] +-- [, behavior_name] name of the autopilot behavior [default: (script name)] +-- [, target_rotation] array of [x, y, z, w] quaternion values [default: no target] +-- [, rotation_threshold] target maximum angle from target facing rotation [default: 0.03 radians] +function LLAgent.startAutoPilot(...) + local args = mapargs('target_global,allow_flying,stop_distance,behavior_name,target_rotation,rotation_threshold', ...) + args.op = 'startAutoPilot' + leap.send('LLAgent', args) +end + +-- Update target location for currently running autopilot +function LLAgent.setAutoPilotTarget(target_global) + leap.send('LLAgent', {op = 'setAutoPilotTarget', target_global=target_global}) +end + +-- Start the autopilot to move to the specified target location +-- either "leader_id" (uuid of target) or "avatar_name" (avatar full name) should be specified +-- "allow_flying" [default: true], "stop_distance" [default: autopilot guess] +function LLAgent.startFollowPilot(...) + local args = mapargs('leader_id,avatar_name,allow_flying,stop_distance', ...) + args.op = 'startFollowPilot' + return leap.request('LLAgent', args) +end + +-- Stop the autopilot system: "user_cancel" indicates whether or not to act as though user canceled autopilot [default: false] +function LLAgent.stopAutoPilot(...) + local args = mapargs('user_cancel', ...) + args.op = 'stopAutoPilot' + leap.send('LLAgent', args) +end + +-- Get information about current state of the autopilot +function LLAgent.getAutoPilot() + return leap.request('LLAgent', {op = 'getAutoPilot'}) +end + return LLAgent -- cgit v1.2.3 From ed7603bfe63ce5e8c1ff1101270e0406de01dc92 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 17 Sep 2024 12:37:17 +0300 Subject: Use event pump to get autopilot status, when it's terminated; add demo script --- indra/newview/llagentlistener.cpp | 29 ++++++++----- indra/newview/llagentlistener.h | 2 +- indra/newview/scripts/lua/require/LLAgent.lua | 13 +++++- indra/newview/scripts/lua/require/LLChat.lua | 1 + .../newview/scripts/lua/require/LLChatListener.lua | 48 --------------------- indra/newview/scripts/lua/require/LLListener.lua | 50 ++++++++++++++++++++++ indra/newview/scripts/lua/test_LLChatListener.lua | 6 +-- indra/newview/scripts/lua/test_autopilot.lua | 22 ++++++++++ 8 files changed, 108 insertions(+), 63 deletions(-) delete mode 100644 indra/newview/scripts/lua/require/LLChatListener.lua create mode 100644 indra/newview/scripts/lua/require/LLListener.lua create mode 100644 indra/newview/scripts/lua/test_autopilot.lua (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 120e52402d..10f56c4eb3 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -90,10 +90,9 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"stop_distance\"]: target maximum distance from target [default: autopilot guess]\n" "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n" "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" - "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]" - "[\"allow_flying\"]: allow flying during autopilot [default: True]", - //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n" - //"[\"callback_data\"]: data to send back during a callback [default: none]", + "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]\n" + "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" + "event with [\"success\"] flag is sent to 'LLAutopilot' event pump, when auto pilot is terminated", &LLAgentListener::startAutoPilot, llsd::map("target_global", LLSD())); add("getAutoPilot", @@ -216,7 +215,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const else if (event_data.has("position")) { LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); - object = findObjectClosestTo(target_position); + object = findObjectClosestTo(target_position, true); } else { @@ -249,7 +248,7 @@ void LLAgentListener::requestStand(LLSD const & event_data) const } -LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const +LLViewerObject * LLAgentListener::findObjectClosestTo(const LLVector3 & position, bool sit_target) const { LLViewerObject *object = NULL; @@ -260,8 +259,13 @@ LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & positio while (cur_index < num_objects) { LLViewerObject * cur_object = gObjectList.getObject(cur_index++); - if (cur_object) - { // Calculate distance from the target position + if (cur_object && !cur_object->isAttachment()) + { + if(sit_target && (cur_object->getPCode() != LL_PCODE_VOLUME)) + { + continue; + } + // Calculate distance from the target position LLVector3 target_diff = cur_object->getPositionRegion() - position; F32 distance_to_target = target_diff.length(); if (distance_to_target < min_distance) @@ -367,7 +371,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) LLQuaternion target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); target_rotation = &target_rotation_value; } - // *TODO: Use callback_pump and callback_data + F32 rotation_threshold = 0.03f; if (event_data.has("rotation_threshold")) { @@ -396,10 +400,15 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) // Clear follow target, this is doing a path mFollowTarget.setNull(); + auto finish_cb = [](bool success, void*) + { + LLEventPumps::instance().obtain("LLAutopilot").post(llsd::map("success", success)); + }; + mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]), behavior_name, target_rotation, - NULL, NULL, + finish_cb, NULL, stop_distance, rotation_threshold, allow_flying); diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 2765bb5b66..05724ff443 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -67,7 +67,7 @@ private: void stopAnimation(LLSD const &event_data); void getAnimationInfo(LLSD const &event_data); - LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; + LLViewerObject * findObjectClosestTo( const LLVector3 & position, bool sit_target = false ) const; private: LLAgent & mAgent; diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua index 7b12493acc..4a1132fe7e 100644 --- a/indra/newview/scripts/lua/require/LLAgent.lua +++ b/indra/newview/scripts/lua/require/LLAgent.lua @@ -80,6 +80,11 @@ function LLAgent.teleport(...) return leap.request('LLTeleportHandler', args).message end +-- Call with no arguments to sit on the ground. +-- Otherwise specify "obj_uuid" to sit on, +-- or region "position" {x, y, z} where to find closest object to sit on. +-- For example: LLAgent.requestSit{position=LLAgent.getRegionPosition()} +-- Your avatar should be close enough to the object you want to sit on function LLAgent.requestSit(...) local args = mapargs('obj_uuid,position', ...) args.op = 'requestSit' @@ -90,6 +95,11 @@ function LLAgent.requestStand() leap.send('LLAgent', {op = 'requestStand'}) end +-- *************************************************************************** +-- Autopilot +-- *************************************************************************** +LLAgent.autoPilotPump = "LLAutopilot" + -- Start the autopilot to move to "target_global" location using specified parameters -- LLAgent.startAutoPilot{ target_global array of target global {x, y, z} position -- [, allow_flying] allow flying during autopilot [default: true] @@ -97,6 +107,7 @@ end -- [, behavior_name] name of the autopilot behavior [default: (script name)] -- [, target_rotation] array of [x, y, z, w] quaternion values [default: no target] -- [, rotation_threshold] target maximum angle from target facing rotation [default: 0.03 radians] +-- an event with "success" flag is sent to "LLAutopilot" event pump, when auto pilot is terminated function LLAgent.startAutoPilot(...) local args = mapargs('target_global,allow_flying,stop_distance,behavior_name,target_rotation,rotation_threshold', ...) args.op = 'startAutoPilot' @@ -109,7 +120,7 @@ function LLAgent.setAutoPilotTarget(target_global) end -- Start the autopilot to move to the specified target location --- either "leader_id" (uuid of target) or "avatar_name" (avatar full name) should be specified +-- either "leader_id" (uuid of target) or "avatar_name" (avatar full name: use just first name for 'Resident') should be specified -- "allow_flying" [default: true], "stop_distance" [default: autopilot guess] function LLAgent.startFollowPilot(...) local args = mapargs('leader_id,avatar_name,allow_flying,stop_distance', ...) diff --git a/indra/newview/scripts/lua/require/LLChat.lua b/indra/newview/scripts/lua/require/LLChat.lua index bc0fc86d22..3ac3bab746 100644 --- a/indra/newview/scripts/lua/require/LLChat.lua +++ b/indra/newview/scripts/lua/require/LLChat.lua @@ -5,6 +5,7 @@ local LLChat = {} -- *************************************************************************** -- Nearby chat -- *************************************************************************** +LLChat.nearbyChatPump = "LLNearbyChat" -- 0 is public nearby channel, other channels are used to communicate with LSL scripts function LLChat.sendNearby(msg, channel) diff --git a/indra/newview/scripts/lua/require/LLChatListener.lua b/indra/newview/scripts/lua/require/LLChatListener.lua deleted file mode 100644 index 82b28966ce..0000000000 --- a/indra/newview/scripts/lua/require/LLChatListener.lua +++ /dev/null @@ -1,48 +0,0 @@ -local fiber = require 'fiber' -local inspect = require 'inspect' -local leap = require 'leap' -local util = require 'util' - -local LLChatListener = {} -local waitfor = {} -local listener_name = {} - -function LLChatListener:new() - local obj = setmetatable({}, self) - self.__index = self - obj.name = 'Chat_listener' - - return obj -end - -util.classctor(LLChatListener) - -function LLChatListener:handleMessages(event_data) - print(inspect(event_data)) - return true -end - -function LLChatListener:start() - waitfor = leap.WaitFor(-1, self.name) - function waitfor:filter(pump, data) - if pump == "LLNearbyChat" then - return data - end - end - - fiber.launch(self.name, function() - event = waitfor:wait() - while event and self:handleMessages(event) do - event = waitfor:wait() - end - end) - - listener_name = leap.request(leap.cmdpump(), {op='listen', source='LLNearbyChat', listener="ChatListener", tweak=true}).listener -end - -function LLChatListener:stop() - leap.send(leap.cmdpump(), {op='stoplistening', source='LLNearbyChat', listener=listener_name}) - waitfor:close() -end - -return LLChatListener diff --git a/indra/newview/scripts/lua/require/LLListener.lua b/indra/newview/scripts/lua/require/LLListener.lua new file mode 100644 index 0000000000..e3bfb6b358 --- /dev/null +++ b/indra/newview/scripts/lua/require/LLListener.lua @@ -0,0 +1,50 @@ +local fiber = require 'fiber' +local inspect = require 'inspect' +local leap = require 'leap' +local util = require 'util' + +local LLListener = {} +local waitfor = {} +local listener_name = {} +local pump = {} + +function LLListener:new() + local obj = setmetatable({}, self) + self.__index = self + obj.name = 'Listener' + + return obj +end + +util.classctor(LLListener) + +function LLListener:handleMessages(event_data) + print(inspect(event_data)) + return true +end + +function LLListener:start(pump_name) + pump = pump_name + waitfor = leap.WaitFor(-1, self.name) + function waitfor:filter(pump_, data) + if pump == pump_ then + return data + end + end + + fiber.launch(self.name, function() + event = waitfor:wait() + while event and self:handleMessages(event) do + event = waitfor:wait() + end + end) + + listener_name = leap.request(leap.cmdpump(), {op='listen', source=pump, listener="LLListener", tweak=true}).listener +end + +function LLListener:stop() + leap.send(leap.cmdpump(), {op='stoplistening', source=pump, listener=listener_name}) + waitfor:close() +end + +return LLListener diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua index 4a4d40bee5..1df2880f3d 100644 --- a/indra/newview/scripts/lua/test_LLChatListener.lua +++ b/indra/newview/scripts/lua/test_LLChatListener.lua @@ -1,4 +1,4 @@ -local LLChatListener = require 'LLChatListener' +local LLListener = require 'LLListener' local LLChat = require 'LLChat' local UI = require 'UI' @@ -22,7 +22,7 @@ function openOrEcho(message) end end -local listener = LLChatListener() +local listener = LLListener() function listener:handleMessages(event_data) if string.find(event_data.message, '[LUA]') then @@ -36,4 +36,4 @@ function listener:handleMessages(event_data) return true end -listener:start() +listener:start(LLChat.nearbyChatPump) diff --git a/indra/newview/scripts/lua/test_autopilot.lua b/indra/newview/scripts/lua/test_autopilot.lua new file mode 100644 index 0000000000..0560477d38 --- /dev/null +++ b/indra/newview/scripts/lua/test_autopilot.lua @@ -0,0 +1,22 @@ +local LLAgent = require 'LLAgent' +local LLListener = require 'LLListener' + +local pos = LLAgent.getGlobalPosition() +pos[1]+=10 -- delta x +pos[2]+=5 -- delta y +LLAgent.requestStand() +LLAgent.startAutoPilot{target_global=pos,allow_flying=false,stop_distance=1} + +local listener = LLListener() + +function listener:handleMessages(event_data) + if event_data.success then + print('Destination is reached') + LLAgent.requestSit() + else + print('Failed to reach destination') + end + return false +end + +listener:start(LLAgent.autoPilotPump) -- cgit v1.2.3 From 80066449b9cbee018dd1c874c02579b1cbd3d348 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 26 Sep 2024 17:20:47 +0300 Subject: update LLListener and related scripts --- indra/newview/llagentlistener.cpp | 8 ++++---- indra/newview/scripts/lua/require/LLListener.lua | 18 +++++++++--------- indra/newview/scripts/lua/test_LLChatListener.lua | 4 ++-- indra/newview/scripts/lua/test_autopilot.lua | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 10f56c4eb3..14e443ec4e 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -87,7 +87,7 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("startAutoPilot", "Start the autopilot system using the following parameters:\n" "[\"target_global\"]: array of target global {x, y, z} position\n" - "[\"stop_distance\"]: target maximum distance from target [default: autopilot guess]\n" + "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]\n" "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n" "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]\n" @@ -100,7 +100,7 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n" "[\"target_global\"]: array of target global {x, y, z} position\n" "[\"leader_id\"]: uuid of target autopilot is following\n" - "[\"stop_distance\"]: target maximum distance from target\n" + "[\"stop_distance\"]: maximum stop distance from target\n" "[\"target_distance\"]: last known distance from target\n" "[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n" "[\"target_facing\"]: array of {x, y} target direction to face\n" @@ -112,7 +112,7 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n" "[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n" "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" - "[\"stop_distance\"]: target maximum distance from target [default: autopilot guess]", + "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]", &LLAgentListener::startFollowPilot, llsd::map("reply", LLSD())); add("setAutoPilotTarget", @@ -496,7 +496,7 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data) if (!gObjectList.findObject(target_id)) { - std::string target_info = event_data.has("leader_id") ? event_data["target_id"] : event_data["avatar_name"]; + std::string target_info = event_data.has("leader_id") ? event_data["leader_id"] : event_data["avatar_name"]; return response.error(stringize("Target ", std::quoted(target_info), " was not found")); } diff --git a/indra/newview/scripts/lua/require/LLListener.lua b/indra/newview/scripts/lua/require/LLListener.lua index e3bfb6b358..b05f966097 100644 --- a/indra/newview/scripts/lua/require/LLListener.lua +++ b/indra/newview/scripts/lua/require/LLListener.lua @@ -6,12 +6,12 @@ local util = require 'util' local LLListener = {} local waitfor = {} local listener_name = {} -local pump = {} -function LLListener:new() +function LLListener:new(pump_name) local obj = setmetatable({}, self) self.__index = self - obj.name = 'Listener' + obj.name = 'Listener:' .. pump_name + obj._pump = pump_name return obj end @@ -23,11 +23,11 @@ function LLListener:handleMessages(event_data) return true end -function LLListener:start(pump_name) - pump = pump_name +function LLListener:start() + _pump = self._pump waitfor = leap.WaitFor(-1, self.name) - function waitfor:filter(pump_, data) - if pump == pump_ then + function waitfor:filter(pump, data) + if _pump == pump then return data end end @@ -39,11 +39,11 @@ function LLListener:start(pump_name) end end) - listener_name = leap.request(leap.cmdpump(), {op='listen', source=pump, listener="LLListener", tweak=true}).listener + listener_name = leap.request(leap.cmdpump(), {op='listen', source=_pump, listener="LLListener", tweak=true}).listener end function LLListener:stop() - leap.send(leap.cmdpump(), {op='stoplistening', source=pump, listener=listener_name}) + leap.send(leap.cmdpump(), {op='stoplistening', source=self._pump, listener=listener_name}) waitfor:close() end diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua index 1df2880f3d..0f269b54e6 100644 --- a/indra/newview/scripts/lua/test_LLChatListener.lua +++ b/indra/newview/scripts/lua/test_LLChatListener.lua @@ -22,7 +22,7 @@ function openOrEcho(message) end end -local listener = LLListener() +local listener = LLListener(LLChat.nearbyChatPump) function listener:handleMessages(event_data) if string.find(event_data.message, '[LUA]') then @@ -36,4 +36,4 @@ function listener:handleMessages(event_data) return true end -listener:start(LLChat.nearbyChatPump) +listener:start() diff --git a/indra/newview/scripts/lua/test_autopilot.lua b/indra/newview/scripts/lua/test_autopilot.lua index 0560477d38..09c85c140a 100644 --- a/indra/newview/scripts/lua/test_autopilot.lua +++ b/indra/newview/scripts/lua/test_autopilot.lua @@ -7,7 +7,7 @@ pos[2]+=5 -- delta y LLAgent.requestStand() LLAgent.startAutoPilot{target_global=pos,allow_flying=false,stop_distance=1} -local listener = LLListener() +local listener = LLListener(LLAgent.autoPilotPump) function listener:handleMessages(event_data) if event_data.success then @@ -19,4 +19,4 @@ function listener:handleMessages(event_data) return false end -listener:start(LLAgent.autoPilotPump) +listener:start() -- cgit v1.2.3 From 42d52b33b4188a06d921231cd2942761c573fad6 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Thu, 26 Sep 2024 21:26:59 +0300 Subject: #2519 Move "MediaSoundsEarLocation" and "VoiceEarLocation" toggles to the Communicate menu (#2707) --- indra/newview/skins/default/xui/en/menu_viewer.xml | 37 +++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 43cdf30ba0..a0d3a5e960 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -465,24 +465,6 @@ <menu_item_check.on_click function="World.AlwaysRun" /> </menu_item_check> - <menu_item_check - label="Hear Media and Sound from Avatar" - name="Hear Media and Sound from Avatar"> - <menu_item_check.on_check - control="MediaSoundsEarLocation" /> - <menu_item_check.on_click - function="Agent.ToggleHearMediaSoundFromAvatar" /> - </menu_item_check> - <menu_item_check - label="Hear Voice from Avatar" - name="Hear Voice from Avatar"> - <menu_item_check.on_check - control="VoiceEarLocation" /> - <menu_item_check.on_click - function="Agent.ToggleHearVoiceFromAvatar" /> - <menu_item_call.on_enable - control="EnableVoiceChat" /> - </menu_item_check> <menu_item_separator/> <menu_item_check label="Gestures..." @@ -579,6 +561,25 @@ parameter="conversation" /> </menu_item_check> <menu_item_separator/> + <menu_item_check + label="Hear Media and Sound from Avatar" + name="Hear Media and Sound from Avatar"> + <menu_item_check.on_check + control="MediaSoundsEarLocation" /> + <menu_item_check.on_click + function="Agent.ToggleHearMediaSoundFromAvatar" /> + </menu_item_check> + <menu_item_check + label="Hear Voice from Avatar" + name="Hear Voice from Avatar"> + <menu_item_check.on_check + control="VoiceEarLocation" /> + <menu_item_check.on_click + function="Agent.ToggleHearVoiceFromAvatar" /> + <menu_item_call.on_enable + control="EnableVoiceChat" /> + </menu_item_check> + <menu_item_separator/> <menu_item_check label="Gestures..." name="Gestures" -- cgit v1.2.3 From 6ebd6494a75d9b3d34e45655d79d0027fbba3898 Mon Sep 17 00:00:00 2001 From: Cosmic Linden <cosmic@lindenlab.com> Date: Thu, 26 Sep 2024 17:23:06 -0700 Subject: secondlife/viewer#2638: Don't clear big render target if all pixels will be replaced --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/pipeline.cpp | 25 ++++++++++--------------- 2 files changed, 21 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 82eb98b06b..2cbb493b91 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7330,6 +7330,17 @@ <key>Value</key> <integer>-1</integer> </map> + <key>RenderBufferClearOnInvalidate</key> + <map> + <key>Comment</key> + <string>Whether to call glClear on render buffers that will be fully overwritten with new contents</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>RenderCompressTextures</key> <map> <key>Comment</key> diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index fe02742aac..19868d2eef 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -576,6 +576,7 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionAdaptiveStepMultiplier"); connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionGlossySamples"); connectRefreshCachedSettingsSafe("RenderBufferVisualization"); + connectRefreshCachedSettingsSafe("RenderBufferClearOnInvalidate"); connectRefreshCachedSettingsSafe("RenderMirrors"); connectRefreshCachedSettingsSafe("RenderHeroProbeUpdateRate"); connectRefreshCachedSettingsSafe("RenderHeroProbeConservativeUpdateMultiplier"); @@ -1084,6 +1085,7 @@ void LLPipeline::refreshCachedSettings() RenderScreenSpaceReflectionAdaptiveStepMultiplier = gSavedSettings.getF32("RenderScreenSpaceReflectionAdaptiveStepMultiplier"); RenderScreenSpaceReflectionGlossySamples = gSavedSettings.getS32("RenderScreenSpaceReflectionGlossySamples"); RenderBufferVisualization = gSavedSettings.getS32("RenderBufferVisualization"); + LLRenderTarget::sClearOnInvalidate = gSavedSettings.getBOOL("RenderBufferClearOnInvalidate"); RenderMirrors = gSavedSettings.getBOOL("RenderMirrors"); RenderHeroProbeUpdateRate = gSavedSettings.getS32("RenderHeroProbeUpdateRate"); RenderHeroProbeConservativeUpdateMultiplier = gSavedSettings.getS32("RenderHeroProbeConservativeUpdateMultiplier"); @@ -7147,7 +7149,7 @@ void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* LLRenderTarget& depth_src = mRT->deferredScreen; dst->bindTarget(); - dst->clear(); + dst->invalidate(); gCopyDepthProgram.bind(); S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP); @@ -7334,7 +7336,7 @@ void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) // bake out texture2D with RGBL for FXAA shader mFXAAMap.bindTarget(); - mFXAAMap.clear(GL_COLOR_BUFFER_BIT); + mFXAAMap.invalidate(GL_COLOR_BUFFER_BIT); shader = &gGlowCombineFXAAProgram; shader->bind(); @@ -7433,7 +7435,7 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src) LLGLSLShader& edge_shader = gSMAAEdgeDetectProgram[fsaa_quality]; dest.bindTarget(); - dest.clear(GL_COLOR_BUFFER_BIT); + dest.invalidate(GL_COLOR_BUFFER_BIT); edge_shader.bind(); edge_shader.uniform4fv(sSmaaRTMetrics, 1, rt_metrics); @@ -7476,7 +7478,7 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src) LLGLSLShader& blend_weights_shader = gSMAABlendWeightsProgram[fsaa_quality]; dest.bindTarget(); - dest.clear(GL_COLOR_BUFFER_BIT); + dest.invalidate(GL_COLOR_BUFFER_BIT); blend_weights_shader.bind(); blend_weights_shader.uniform4fv(sSmaaRTMetrics, 1, rt_metrics); @@ -7552,7 +7554,7 @@ void LLPipeline::applySMAA(LLRenderTarget* src, LLRenderTarget* dst) LLGLSLShader& blend_shader = gSMAANeighborhoodBlendProgram[fsaa_quality]; bound_target->bindTarget(); - bound_target->clear(GL_COLOR_BUFFER_BIT); + bound_target->invalidate(GL_COLOR_BUFFER_BIT); blend_shader.bind(); blend_shader.uniform4fv(sSmaaRTMetrics, 1, rt_metrics); @@ -8330,9 +8332,7 @@ void LLPipeline::renderDeferredLighting() LLGLSLShader& sun_shader = gCubeSnapshot ? gDeferredSunProbeProgram : gDeferredSunProgram; bindDeferredShader(sun_shader, deferred_light_target); mScreenTriangleVB->setBuffer(); - glClearColor(1, 1, 1, 1); - deferred_light_target->clear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 0); + deferred_light_target->invalidate(GL_COLOR_BUFFER_BIT); sun_shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, (GLfloat)deferred_light_target->getWidth(), @@ -8356,9 +8356,7 @@ void LLPipeline::renderDeferredLighting() LL_PROFILE_GPU_ZONE("soften shadow"); // blur lightmap screen_target->bindTarget(); - glClearColor(1, 1, 1, 1); - screen_target->clear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 0); + screen_target->invalidate(GL_COLOR_BUFFER_BIT); bindDeferredShader(gDeferredBlurLightProgram); @@ -8410,11 +8408,8 @@ void LLPipeline::renderDeferredLighting() deferred_light_target->flush(); unbindDeferredShader(gDeferredBlurLightProgram); } - screen_target->bindTarget(); - // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky - glClearColor(0, 0, 0, 0); - screen_target->clear(GL_COLOR_BUFFER_BIT); + screen_target->invalidate(GL_COLOR_BUFFER_BIT); if (RenderDeferredAtmospheric) { // apply sunlight contribution -- cgit v1.2.3 From e36452483744b41c4af7f5ac2240083b1cba0738 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Thu, 26 Sep 2024 14:14:27 +0200 Subject: #2674 Optimize LLWorld::renderPropertyLines() - use vertexBatchPreTransformed() --- indra/newview/llviewerparceloverlay.cpp | 102 ++++++++++++++++++-------------- indra/newview/llviewerparceloverlay.h | 5 +- 2 files changed, 61 insertions(+), 46 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 2077cbdd08..019e870829 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -555,51 +555,52 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 inside_z = land.resolveHeightRegion(inside_x, inside_y); }; - auto split = [&](U32 lod, const LLVector3& start, F32 x, F32 y, F32 z, F32 part) + auto split = [&](U32 lod, const LLVector4a& start, F32 x, F32 y, F32 z, F32 part) { - F32 new_x = start.mV[VX] + (x - start.mV[VX]) * part; - F32 new_y = start.mV[VY] + (y - start.mV[VY]) * part; - F32 new_z = start.mV[VZ] + (z - start.mV[VZ]) * part; - edge.vertices[lod].emplace_back(new_x, new_y, new_z); + F32 new_x = start[VX] + (x - start[VX]) * part; + F32 new_y = start[VY] + (y - start[VY]) * part; + F32 new_z = start[VZ] + (z - start[VZ]) * part; + edge.pushVertex(lod, new_x, new_y, new_z, water_z); }; auto checkForSplit = [&](U32 lod) { - const std::vector<LLVector3>& vertices = edge.vertices[lod]; - const LLVector3& last_outside = vertices.back(); - F32 z0 = last_outside.mV[VZ]; + const std::vector<LLVector4a>& vertices = edge.verticesUnderWater[lod]; + const LLVector4a& last_outside = vertices.back(); + F32 z0 = last_outside[VZ]; F32 z1 = outside_z; if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z)) return; F32 part = (water_z - z0) / (z1 - z0); - const LLVector3& last_inside = vertices[vertices.size() - 2]; + const LLVector4a& last_inside = vertices[vertices.size() - 2]; split(lod, last_inside, inside_x, inside_y, inside_z, part); split(lod, last_outside, outside_x, outside_y, outside_z, part); }; auto pushTwoVertices = [&](U32 lod) { + LLVector3 out(outside_x, outside_y, outside_z); + LLVector3 in(inside_x, inside_y, inside_z); if (fabs(inside_z - outside_z) < LINE_WIDTH / 5) { - edge.vertices[lod].emplace_back(inside_x, inside_y, inside_z); + edge.pushVertex(lod, inside_x, inside_y, inside_z, water_z); } else { // Make the line thinner if heights differ too much - LLVector3 out(outside_x, outside_y, outside_z); - LLVector3 in(inside_x, inside_y, inside_z); LLVector3 dist(in - out); F32 coef = dist.length() / LINE_WIDTH; - edge.vertices[lod].emplace_back(out + dist / coef); + LLVector3 new_in(out + dist / coef); + edge.pushVertex(lod, new_in[VX], new_in[VY], new_in[VZ], water_z); } - edge.vertices[lod].emplace_back(outside_x, outside_y, outside_z); + edge.pushVertex(lod, outside_x, outside_y, outside_z, water_z); }; // Point A simplified (first two vertices) pushTwoVertices(1); // Point A detailized (only one vertex) - edge.vertices[0].emplace_back(outside_x, outside_y, outside_z); + edge.pushVertex(0, outside_x, outside_y, outside_z, water_z); // Point B (two vertices) move(LINE_WIDTH); @@ -627,7 +628,23 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 pushTwoVertices(1); // Point G detailized (only one vertex) - edge.vertices[0].emplace_back(outside_x, outside_y, outside_z); + edge.pushVertex(0, outside_x, outside_y, outside_z, water_z); +} + +void LLViewerParcelOverlay::Edge::pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z) +{ + verticesUnderWater[lod].emplace_back(x, y, z); + gGL.transform(verticesUnderWater[lod].back()); + + if (z >= water_z) + { + verticesAboveWater[lod].push_back(verticesUnderWater[lod].back()); + } + else + { + verticesAboveWater[lod].emplace_back(x, y, water_z); + gGL.transform(verticesAboveWater[lod].back()); + } } void LLViewerParcelOverlay::setDirty() @@ -707,6 +724,8 @@ void LLViewerParcelOverlay::renderPropertyLines() // Stomp the camera into two dimensions LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() ); + bool draw_underwater = camera_region.mV[VZ] < water_z || + !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER); // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind // the camera. The cull plane normal is the camera's at axis. @@ -714,17 +733,22 @@ void LLViewerParcelOverlay::renderPropertyLines() cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS; cull_plane_point += camera_region; - bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build"); + bool render_hidden = !draw_underwater && + LLSelectMgr::sRenderHiddenSelections && + LLFloaterReg::instanceVisible("build"); constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; constexpr F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25.f; for (const Edge& edge : mEdges) { - const std::vector<LLVector3>& vertices0 = edge.vertices[0]; - LLVector3 center = (vertices0.front() + vertices0.back()) / 2; - F32 dist_squared = dist_vec_squared(center, camera_region); + const std::vector<LLVector4a>& vertices0 = edge.verticesAboveWater[0]; + const F32* first = vertices0.front().getF32ptr(); + const F32* last = vertices0.back().getF32ptr(); + LLVector3 center((first[VX] + last[VX]) / 2, (first[VY] + last[VY]) / 2, (first[VZ] + last[VZ]) / 2); + gGL.untransform(center); + F32 dist_squared = dist_vec_squared(center, camera_region); if (dist_squared > PROPERTY_LINE_CLIP_DIST_SQUARED) { continue; @@ -745,39 +769,27 @@ void LLViewerParcelOverlay::renderPropertyLines() gGL.color4ubv(edge.color.mV); - for (const LLVector3& vertex : edge.vertices[lod]) + if (draw_underwater) { - if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z) - { - gGL.vertex3fv(vertex.mV); - } - else - { - LLVector3 visible = vertex; - visible.mV[VZ] = water_z; - gGL.vertex3fv(visible.mV); - } + gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]); } - - gGL.end(); - - if (render_hidden) + else { - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); + gGL.vertexBatchPreTransformed(edge.verticesAboveWater[lod]); - gGL.begin(LLRender::TRIANGLE_STRIP); + if (render_hidden) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); - LLColor4U color = edge.color; - color.mV[VALPHA] /= 4; - gGL.color4ubv(color.mV); + LLColor4U color = edge.color; + color.mV[VALPHA] /= 4; + gGL.color4ubv(color.mV); - for (const LLVector3& vertex : edge.vertices[lod]) - { - gGL.vertex3fv(vertex.mV); + gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]); } - - gGL.end(); } + + gGL.end(); } gGL.popMatrix(); diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 68900d16a6..7271c85701 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -116,7 +116,10 @@ private: struct Edge { - std::vector<LLVector3> vertices[2]; // 0 - detailized, 1 - simplified + void pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z); + // LOD: 0 - detailized, 1 - simplified + std::vector<LLVector4a> verticesAboveWater[2]; + std::vector<LLVector4a> verticesUnderWater[2]; LLColor4U color; }; -- cgit v1.2.3 From 294f6a73ea4fa1b1763250b5f74eb19deb7703e4 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko <maximnproductengine@lindenlab.com> Date: Fri, 27 Sep 2024 14:38:46 +0300 Subject: #2711 Remove ALM text from About SL --- indra/newview/skins/default/xui/de/strings.xml | 1 - indra/newview/skins/default/xui/es/strings.xml | 1 - indra/newview/skins/default/xui/fr/strings.xml | 1 - indra/newview/skins/default/xui/it/strings.xml | 1 - indra/newview/skins/default/xui/pl/strings.xml | 1 - indra/newview/skins/default/xui/pt/strings.xml | 1 - indra/newview/skins/default/xui/ru/strings.xml | 1 - indra/newview/skins/default/xui/tr/strings.xml | 1 - 8 files changed, 8 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index a9e7626dc5..486d604e9f 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -31,7 +31,6 @@ Sichtweite: [DRAW_DISTANCE] m Bandbreite: [NET_BANDWITH] kbit/s LOD-Faktor: [LOD_FACTOR] Darstellungsqualität: [RENDER_QUALITY] -Erweitertes Beleuchtungsmodell: [GPU_SHADERS] Texturspeicher: [TEXTURE_MEMORY] MB</string> <string name="AboutOSXHiDPI">HiDPI-Anzeigemodus: [HIDPI]</string> <string name="AboutLibs">J2C-Decoderversion: [J2C_VERSION] diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index cd8e7687ae..9fcfc2daa5 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -29,7 +29,6 @@ Distancia de dibujo: [DRAW_DISTANCE]m Ancho de banda: [NET_BANDWITH]kbit/s Factor LOD: [LOD_FACTOR] Calidad de renderización: [RENDER_QUALITY] -Modelo de iluminación avanzado: [GPU_SHADERS] Memoria de textura: [TEXTURE_MEMORY]MB</string> <string name="AboutOSXHiDPI">Modo de visualización HiDPi: [HIDPI]</string> <string name="AboutLibs">Versión de descodificador J2C: [J2C_VERSION] diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 0a3fbeb603..55f6209fe1 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -32,7 +32,6 @@ Distance de dessin : [DRAW_DISTANCE]m Bande passante : [NET_BANDWITH] kbit/s Facteur LOD (niveau de détail) : [LOD_FACTOR] Qualité de rendu : [RENDER_QUALITY] -Modèle d’éclairage avancé : [GPU_SHADERS] Mémoire textures : [TEXTURE_MEMORY] Mo</string> <string name="AboutOSXHiDPI">Mode d'affichage HiDPI : [HIDPI]</string> <string name="AboutLibs">J2C Decoder Version: [J2C_VERSION] diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 178bb90ca6..f77ab1062a 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -31,7 +31,6 @@ Distanza visualizzazione: [DRAW_DISTANCE]m Larghezza banda: [NET_BANDWITH]kbit/s Fattore livello di dettaglio: [LOD_FACTOR] Qualità di rendering: [RENDER_QUALITY] -Modello illuminazione avanzato: [GPU_SHADERS] Memoria texture: [TEXTURE_MEMORY]MB</string> <string name="AboutOSXHiDPI">Modalità display HiDPI: [HIDPI]</string> <string name="AboutLibs">J2C Versione decoder: [J2C_VERSION] diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index 26ec6cc9dc..8032443020 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -49,7 +49,6 @@ Pole widzenia (Draw Distance): [DRAW_DISTANCE]m Przepustowość (Bandwidth): [NET_BANDWITH]kbit/s Mnożnik poziomu detali (LOD Factor): [LOD_FACTOR] Jakość wyświetlania (Render quality): [RENDER_QUALITY] -Zaawansowane oświetlenie (Advanced Lighting Model): [GPU_SHADERS] Pamięć tekstur (Texture memory): [TEXTURE_MEMORY]MB Pamięć podręczna dysku (Disk cache): [DISK_CACHE_INFO] </string> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 6db5da2e89..4ce1e6d2ec 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -29,7 +29,6 @@ Estabelecer a distância: [DRAW_DISTANCE]m Largura da banda: [NET_BANDWITH]kbit/s LOD fator: [LOD_FACTOR] Qualidade de renderização: [RENDER_QUALITY] -Modelo avançado de luzes: [GPU_SHADERS] Memória de textura: [TEXTURE_MEMORY]MB</string> <string name="AboutOSXHiDPI">HiDPI modo de exibição: [HIDPI]</string> <string name="AboutLibs">Versão do J2C Decoder: [J2C_VERSION] diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 61d836a2d1..0079309ba2 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -69,7 +69,6 @@ SLURL: <nolink>[SLURL]</nolink> Ширина канала: [NET_BANDWITH] кбит/с Коэффициент детализации: [LOD_FACTOR] Качество визуализации: [RENDER_QUALITY] -Расширенная модель освещения: [GPU_SHADERS] Память текстур: [TEXTURE_MEMORY] МБ </string> <string name="AboutOSXHiDPI"> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index e709a4c5d6..fa2fd3a802 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -69,7 +69,6 @@ UI Ölçeklendirme: [UI_SCALE] Bant genişliği: [NET_BANDWITH]kbit/s LOD faktörü: [LOD_FACTOR] İşleme kalitesi: [RENDER_QUALITY] -Gelişmiş Aydınlatma Modeli: [GPU_SHADERS] Doku belleği: [TEXTURE_MEMORY]MB </string> <string name="AboutOSXHiDPI"> -- cgit v1.2.3 From 00331d3dca86fd54e6f31aea3c0f5018672e1bcb Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Fri, 27 Sep 2024 17:33:01 +0300 Subject: Add UI callback to invoke specified script via menu --- indra/newview/llviewermenu.cpp | 21 +++++++++++++++++++++ indra/newview/scripts/lua/test_top_menu.lua | 28 +++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index af719293e6..5a012f3015 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -78,6 +78,7 @@ #include "llfloatertools.h" #include "llfloaterworldmap.h" #include "llfloaterbuildoptions.h" +#include "fsyspath.h" #include "llavataractions.h" #include "lllandmarkactions.h" #include "llgroupmgr.h" @@ -90,6 +91,7 @@ #include "llinventorybridge.h" #include "llinventorydefines.h" #include "llinventoryfunctions.h" +#include "llluamanager.h" #include "llpanellogin.h" #include "llpanelblockedlist.h" #include "llpanelmaininventory.h" @@ -9472,6 +9474,23 @@ void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str) mCostStr = std::to_string(upload_cost); } +void lua_run_script(const LLSD& userdata) +{ + std::string script_path = userdata.asString(); + if (script_path.empty()) + { + LL_WARNS() << "Script name is not specified" << LL_ENDL; + return; + } + fsyspath fs_script_path(script_path); + script_path = fs_script_path.lexically_normal().u8string(); + if (!fs_script_path.is_absolute()) + { + script_path = (fsyspath(gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua")) / script_path).u8string(); + } + LLLUAmanager::runScriptFile(script_path); +} + void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) { static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", @@ -10074,4 +10093,6 @@ void initialize_menus() view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); + + registrar.add("Lua.RunScript", boost::bind(&lua_run_script, _2), cb_info::UNTRUSTED_BLOCK); } diff --git a/indra/newview/scripts/lua/test_top_menu.lua b/indra/newview/scripts/lua/test_top_menu.lua index 780a384c92..f877cda5eb 100644 --- a/indra/newview/scripts/lua/test_top_menu.lua +++ b/indra/newview/scripts/lua/test_top_menu.lua @@ -18,17 +18,35 @@ UI.addMenuItem{name="lua_scripts",label="Scripts", --Add menu separator to the 'LUA Menu' under added menu items UI.addMenuSeparator{parent_menu=MENU_NAME} ---Add two new menu branch 'About...' to the 'LUA Menu' -local BRANCH_NAME = "about_branch" -UI.addMenuBranch{name="about_branch",label="About...",parent_menu=MENU_NAME} +--Add 'Demo scripts...' branch to the 'LUA Menu' +local DEMO_BRANCH = "demo_scripts" +UI.addMenuBranch{name=DEMO_BRANCH,label="Demo scripts...",parent_menu=MENU_NAME} + +--Add menu items to the 'Demo scripts...' branch, which will invoke specified script on click +UI.addMenuItem{name="speedometer",label="Speedometer", + param="test_luafloater_speedometer.lua", + func="Lua.RunScript", + parent_menu=DEMO_BRANCH} + +UI.addMenuItem{name="gesture_list",label="Gesture list", + param="test_luafloater_gesture_list.lua", + func="Lua.RunScript", + parent_menu=DEMO_BRANCH} + +--Add one more menu separator +UI.addMenuSeparator{parent_menu=MENU_NAME} + +--Add 'About...' branch to the 'LUA Menu' +local ABOUT_BRANCH = "about_branch" +UI.addMenuBranch{name=ABOUT_BRANCH,label="About...",parent_menu=MENU_NAME} --Add two new menu items to the 'About...' branch UI.addMenuItem{name="lua_info",label="Lua...", param="https://www.lua.org/about.html", func="Advanced.ShowURL", - parent_menu=BRANCH_NAME} + parent_menu=ABOUT_BRANCH} UI.addMenuItem{name="lua_info",label="Luau...", param="https://luau-lang.org/", func="Advanced.ShowURL", - parent_menu=BRANCH_NAME} + parent_menu=ABOUT_BRANCH} -- cgit v1.2.3 From c47678801b061494a40beb3d14d44071954fc387 Mon Sep 17 00:00:00 2001 From: Rye Cogtail <rye@lindenlab.com> Date: Fri, 27 Sep 2024 13:09:33 -0400 Subject: Remove dead LLPostProcess class and related code --- indra/newview/CMakeLists.txt | 2 - indra/newview/llappviewer.cpp | 3 - indra/newview/llfloaterpostprocess.cpp | 229 ----------- indra/newview/llfloaterpostprocess.h | 72 ---- indra/newview/llstartup.cpp | 5 - indra/newview/llviewerdisplay.cpp | 1 - indra/newview/llviewerdisplay.h | 2 - indra/newview/llviewerfloaterreg.cpp | 2 - indra/newview/llviewermenu.cpp | 12 - indra/newview/llviewerwindow.cpp | 6 - .../skins/default/xui/en/floater_post_process.xml | 426 --------------------- 11 files changed, 760 deletions(-) delete mode 100644 indra/newview/llfloaterpostprocess.cpp delete mode 100644 indra/newview/llfloaterpostprocess.h delete mode 100644 indra/newview/skins/default/xui/en/floater_post_process.xml (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 04ce88f0c6..29dbceedac 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -271,7 +271,6 @@ set(viewer_SOURCE_FILES llfloaterpay.cpp llfloaterperformance.cpp llfloaterperms.cpp - llfloaterpostprocess.cpp llfloaterprofile.cpp llfloaterpreference.cpp llfloaterpreferencesgraphicsadvanced.cpp @@ -946,7 +945,6 @@ set(viewer_HEADER_FILES llfloaterpay.h llfloaterperformance.h llfloaterperms.h - llfloaterpostprocess.h llfloaterprofile.h llfloaterpreference.h llfloaterpreferencesgraphicsadvanced.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 377fb4d486..521e6eee1a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -184,7 +184,6 @@ #include "lltracker.h" #include "llviewerparcelmgr.h" #include "llworldmapview.h" -#include "llpostprocess.h" #include "lldebugview.h" #include "llconsole.h" @@ -1972,8 +1971,6 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLPostProcess); - LLTracker::cleanupInstance(); // *FIX: This is handled in LLAppViewerWin32::cleanup(). diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp deleted file mode 100644 index 616c13cdc7..0000000000 --- a/indra/newview/llfloaterpostprocess.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @file llfloaterpostprocess.cpp - * @brief LLFloaterPostProcess class definition - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterpostprocess.h" - -#include "llsliderctrl.h" -#include "llcheckboxctrl.h" -#include "llnotificationsutil.h" -#include "lluictrlfactory.h" -#include "llviewerdisplay.h" -#include "llpostprocess.h" -#include "llcombobox.h" -#include "lllineeditor.h" -#include "llviewerwindow.h" - - -LLFloaterPostProcess::LLFloaterPostProcess(const LLSD& key) - : LLFloater(key) -{ -} - -LLFloaterPostProcess::~LLFloaterPostProcess() -{ - - -} -bool LLFloaterPostProcess::postBuild() -{ - /// Color Filter Callbacks - childSetCommitCallback("ColorFilterToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_color_filter"); - //childSetCommitCallback("ColorFilterGamma", &LLFloaterPostProcess::onFloatControlMoved, &(gPostProcess->tweaks.gamma())); - childSetCommitCallback("ColorFilterBrightness", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness"); - childSetCommitCallback("ColorFilterSaturation", &LLFloaterPostProcess::onFloatControlMoved, (char*)"saturation"); - childSetCommitCallback("ColorFilterContrast", &LLFloaterPostProcess::onFloatControlMoved, (char*)"contrast"); - - childSetCommitCallback("ColorFilterBaseR", &LLFloaterPostProcess::onColorControlRMoved, (char*)"contrast_base"); - childSetCommitCallback("ColorFilterBaseG", &LLFloaterPostProcess::onColorControlGMoved, (char*)"contrast_base"); - childSetCommitCallback("ColorFilterBaseB", &LLFloaterPostProcess::onColorControlBMoved, (char*)"contrast_base"); - childSetCommitCallback("ColorFilterBaseI", &LLFloaterPostProcess::onColorControlIMoved, (char*)"contrast_base"); - - /// Night Vision Callbacks - childSetCommitCallback("NightVisionToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_night_vision"); - childSetCommitCallback("NightVisionBrightMult", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness_multiplier"); - childSetCommitCallback("NightVisionNoiseSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_size"); - childSetCommitCallback("NightVisionNoiseStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_strength"); - - /// Bloom Callbacks - childSetCommitCallback("BloomToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_bloom"); - childSetCommitCallback("BloomExtract", &LLFloaterPostProcess::onFloatControlMoved, (char*)"extract_low"); - childSetCommitCallback("BloomSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_width"); - childSetCommitCallback("BloomStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_strength"); - - // Effect loading and saving. - LLComboBox* comboBox = getChild<LLComboBox>("PPEffectsCombo"); - getChild<LLComboBox>("PPLoadEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onLoadEffect, this, comboBox)); - comboBox->setCommitCallback(boost::bind(&LLFloaterPostProcess::onChangeEffectName, this, _1)); - - LLLineEditor* editBox = getChild<LLLineEditor>("PPEffectNameEditor"); - getChild<LLComboBox>("PPSaveEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onSaveEffect, this, editBox)); - - syncMenu(); - return true; -} - -// Bool Toggle -void LLFloaterPostProcess::onBoolToggle(LLUICtrl* ctrl, void* userData) -{ - char const * boolVariableName = (char const *)userData; - - // check the bool - LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl); - gPostProcess->tweaks[boolVariableName] = cbCtrl->getValue(); -} - -// Float Moved -void LLFloaterPostProcess::onFloatControlMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); - gPostProcess->tweaks[floatVariableName] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlRMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); - gPostProcess->tweaks[floatVariableName][0] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlGMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); - gPostProcess->tweaks[floatVariableName][1] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlBMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); - gPostProcess->tweaks[floatVariableName][2] = sldrCtrl->getValue(); -} - -// Color Moved -void LLFloaterPostProcess::onColorControlIMoved(LLUICtrl* ctrl, void* userData) -{ - char const * floatVariableName = (char const *)userData; - LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); - gPostProcess->tweaks[floatVariableName][3] = sldrCtrl->getValue(); -} - -void LLFloaterPostProcess::onLoadEffect(LLComboBox* comboBox) -{ - LLSD::String effectName(comboBox->getSelectedValue().asString()); - - gPostProcess->setSelectedEffect(effectName); - - syncMenu(); -} - -void LLFloaterPostProcess::onSaveEffect(LLLineEditor* editBox) -{ - std::string effectName(editBox->getValue().asString()); - - if (gPostProcess->mAllEffects.has(effectName)) - { - LLSD payload; - payload["effect_name"] = effectName; - LLNotificationsUtil::add("PPSaveEffectAlert", LLSD(), payload, boost::bind(&LLFloaterPostProcess::saveAlertCallback, this, _1, _2)); - } - else - { - gPostProcess->saveEffect(effectName); - syncMenu(); - } -} - -void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl) -{ - // get the combo box and name - LLLineEditor* editBox = getChild<LLLineEditor>("PPEffectNameEditor"); - - // set the parameter's new name - editBox->setValue(ctrl->getValue()); -} - -bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - // if they choose save, do it. Otherwise, don't do anything - if (option == 0) - { - gPostProcess->saveEffect(notification["payload"]["effect_name"].asString()); - - syncMenu(); - } - return false; -} - -void LLFloaterPostProcess::syncMenu() -{ - // add the combo boxe contents - LLComboBox* comboBox = getChild<LLComboBox>("PPEffectsCombo"); - - comboBox->removeall(); - - LLSD::map_const_iterator currEffect; - for(currEffect = gPostProcess->mAllEffects.beginMap(); - currEffect != gPostProcess->mAllEffects.endMap(); - ++currEffect) - { - comboBox->add(currEffect->first); - } - - // set the current effect as selected. - comboBox->selectByValue(gPostProcess->getSelectedEffect()); - - /// Sync Color Filter Menu - getChild<LLUICtrl>("ColorFilterToggle")->setValue(gPostProcess->tweaks.useColorFilter()); - //getChild<LLUICtrl>("ColorFilterGamma")->setValue(gPostProcess->tweaks.gamma()); - getChild<LLUICtrl>("ColorFilterBrightness")->setValue(gPostProcess->tweaks.brightness()); - getChild<LLUICtrl>("ColorFilterSaturation")->setValue(gPostProcess->tweaks.saturation()); - getChild<LLUICtrl>("ColorFilterContrast")->setValue(gPostProcess->tweaks.contrast()); - getChild<LLUICtrl>("ColorFilterBaseR")->setValue(gPostProcess->tweaks.contrastBaseR()); - getChild<LLUICtrl>("ColorFilterBaseG")->setValue(gPostProcess->tweaks.contrastBaseG()); - getChild<LLUICtrl>("ColorFilterBaseB")->setValue(gPostProcess->tweaks.contrastBaseB()); - getChild<LLUICtrl>("ColorFilterBaseI")->setValue(gPostProcess->tweaks.contrastBaseIntensity()); - - /// Sync Night Vision Menu - getChild<LLUICtrl>("NightVisionToggle")->setValue(gPostProcess->tweaks.useNightVisionShader()); - getChild<LLUICtrl>("NightVisionBrightMult")->setValue(gPostProcess->tweaks.brightMult()); - getChild<LLUICtrl>("NightVisionNoiseSize")->setValue(gPostProcess->tweaks.noiseSize()); - getChild<LLUICtrl>("NightVisionNoiseStrength")->setValue(gPostProcess->tweaks.noiseStrength()); - - /// Sync Bloom Menu - getChild<LLUICtrl>("BloomToggle")->setValue(LLSD(gPostProcess->tweaks.useBloomShader())); - getChild<LLUICtrl>("BloomExtract")->setValue(gPostProcess->tweaks.extractLow()); - getChild<LLUICtrl>("BloomSize")->setValue(gPostProcess->tweaks.bloomWidth()); - getChild<LLUICtrl>("BloomStrength")->setValue(gPostProcess->tweaks.bloomStrength()); -} diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h deleted file mode 100644 index 50b48d8410..0000000000 --- a/indra/newview/llfloaterpostprocess.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file llfloaterpostprocess.h - * @brief LLFloaterPostProcess class definition - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLFLOATERPOSTPROCESS_H -#define LL_LLFLOATERPOSTPROCESS_H - -#include "llfloater.h" - -class LLButton; -class LLComboBox; -class LLLineEditor; -class LLSliderCtrl; -class LLTabContainer; -class LLPanelPermissions; -class LLPanelObject; -class LLPanelVolume; -class LLPanelContents; -class LLPanelFace; - -/** - * Menu for adjusting the post process settings of the world - */ -class LLFloaterPostProcess : public LLFloater -{ -public: - - LLFloaterPostProcess(const LLSD& key); - virtual ~LLFloaterPostProcess(); - bool postBuild(); - - /// post process callbacks - static void onBoolToggle(LLUICtrl* ctrl, void* userData); - static void onFloatControlMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlRMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlGMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlBMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlIMoved(LLUICtrl* ctrl, void* userData); - void onLoadEffect(LLComboBox* comboBox); - void onSaveEffect(LLLineEditor* editBox); - void onChangeEffectName(LLUICtrl* ctrl); - - /// prompts a user when overwriting an effect - bool saveAlertCallback(const LLSD& notification, const LLSD& response); - - /// sync up sliders - void syncMenu(); -}; - -#endif diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6e4a652989..83d6b57fa4 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -181,7 +181,6 @@ #include "llnamelistctrl.h" #include "llnamebox.h" #include "llnameeditor.h" -#include "llpostprocess.h" #include "llagentlanguage.h" #include "llwearable.h" #include "llinventorybridge.h" @@ -1292,10 +1291,6 @@ bool idle_startup() LLDrawable::initClass(); display_startup(); - // init the shader managers - LLPostProcess::initClass(); - display_startup(); - LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); display_startup(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index cd35de12c6..1f4502323c 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -55,7 +55,6 @@ #include "llmemory.h" #include "llparcel.h" #include "llperfstats.h" -#include "llpostprocess.h" #include "llrender.h" #include "llscenemonitor.h" #include "llsdjson.h" diff --git a/indra/newview/llviewerdisplay.h b/indra/newview/llviewerdisplay.h index 673f51600d..2ec02f09fd 100644 --- a/indra/newview/llviewerdisplay.h +++ b/indra/newview/llviewerdisplay.h @@ -27,8 +27,6 @@ #ifndef LL_LLVIEWERDISPLAY_H #define LL_LLVIEWERDISPLAY_H -class LLPostProcess; - void display_startup(); void display_cleanup(); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 8919e1f375..9d9961d51c 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -118,7 +118,6 @@ #include "llfloaterpay.h" #include "llfloaterperformance.h" #include "llfloaterperms.h" -#include "llfloaterpostprocess.h" #include "llfloaterpreference.h" #include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" @@ -363,7 +362,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>); LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>); - LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index af719293e6..2f5a302b3f 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9354,17 +9354,6 @@ class LLWorldEnableEnvPreset : public view_listener_t } }; - -/// Post-Process callbacks -class LLWorldPostProcess : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_post_process"); - return true; - } -}; - class LLWorldCheckBanLines : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9659,7 +9648,6 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); - view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines"); view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines"); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index bef667e3bb..c747319940 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -195,7 +195,6 @@ #include "llviewerjoystick.h" #include "llviewermenufile.h" // LLFilePickerReplyThread #include "llviewernetwork.h" -#include "llpostprocess.h" #include "llfloaterimnearbychat.h" #include "llagentui.h" #include "llwearablelist.h" @@ -5762,11 +5761,6 @@ void LLViewerWindow::stopGL() gBox.cleanupGL(); - if(gPostProcess) - { - gPostProcess->invalidate(); - } - gTextureList.destroyGL(); stop_glerror(); diff --git a/indra/newview/skins/default/xui/en/floater_post_process.xml b/indra/newview/skins/default/xui/en/floater_post_process.xml deleted file mode 100644 index 37339f79c8..0000000000 --- a/indra/newview/skins/default/xui/en/floater_post_process.xml +++ /dev/null @@ -1,426 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater - legacy_header_height="18" - height="400" - layout="topleft" - name="Post-Process Floater" - help_topic="post_process_floater" - title="POST-PROCESS SETTINGS" - width="400"> - <tab_container - follows="left|top" - height="400" - layout="topleft" - left="0" - name="Post-Process Tabs" - tab_position="top" - top="0" - width="400"> - <panel - border="true" - follows="left|top|right|bottom" - height="400" - label="Color Filter" - layout="topleft" - left="1" - mouse_opaque="false" - help_topic="post_process_color_filter_tab" - name="wmiColorFilterPanel" - top="0" - width="398"> - <check_box - control_name="wmiColorFilterToggle" - height="16" - label="Enable" - layout="topleft" - left="14" - name="wmiColorFilterToggle" - top="4" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiColorFilterBrightnessText" - top_pad="4" - width="355"> - Brightness - </text> - <slider - control_name="wmiColorFilterBrightness" - decimal_digits="2" - follows="left" - height="10" - increment="0.01" - initial_value="1.0" - layout="topleft" - left_delta="4" - max_val="4" - name="wmiColorFilterBrightness" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiColorFilterSaturationText" - top_pad="4" - width="355"> - Saturation - </text> - <slider - control_name="wmiColorFilterSaturation" - decimal_digits="2" - follows="left" - height="10" - increment="0.01" - initial_value="1.0" - layout="topleft" - left_delta="4" - max_val="2" - min_val="-1" - name="wmiColorFilterSaturation" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiColorFilterContrastText" - top_pad="4" - width="355"> - Contrast - </text> - <slider - control_name="wmiColorFilterContrast" - decimal_digits="2" - follows="left" - height="10" - increment="0.01" - initial_value="1.0" - layout="topleft" - left_delta="4" - max_val="4" - name="wmiColorFilterContrast" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiColorFilterBaseText" - top_pad="4" - width="355"> - Contrast Base Color - </text> - <slider - control_name="wmiColorFilterBaseR" - follows="left" - height="10" - increment="0.01" - initial_value="1.0" - label="R" - layout="topleft" - left_delta="4" - name="wmiColorFilterBaseR" - top_pad="20" - width="200" /> - <slider - control_name="wmiColorFilterBaseG" - follows="left" - height="10" - increment="0.01" - initial_value="1.0" - label="G" - layout="topleft" - left_delta="0" - name="wmiColorFilterBaseG" - top_pad="10" - width="200" /> - <slider - control_name="wmiColorFilterBaseB" - follows="left" - height="10" - increment="0.01" - initial_value="1.0" - label="B" - layout="topleft" - left_delta="0" - name="wmiColorFilterBaseB" - top_pad="10" - width="200" /> - <slider - control_name="wmiColorFilterBaseI" - follows="left" - height="10" - increment="0.01" - initial_value="0.5" - label="I" - layout="topleft" - left_delta="0" - name="wmiColorFilterBaseI" - top_pad="10" - width="200" /> - </panel> - <panel - border="true" - follows="left|top|right|bottom" - height="400" - label="Night Vision" - layout="topleft" - left_delta="0" - mouse_opaque="false" - help_topic="post_process_night_vision_tab" - name="wmiNightVisionPanel" - top_delta="-236" - width="398"> - <check_box - control_name="wmiNightVisionToggle" - height="16" - label="Enable" - layout="topleft" - left="14" - name="wmiNightVisionToggle" - top="4" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiNightVisionBrightMultText" - top_pad="5" - width="355"> - Light Amplification Multiple - </text> - <slider - control_name="wmiNightVisionBrightMult" - follows="left" - height="10" - increment="0.01" - initial_value="3.0" - layout="topleft" - left_delta="4" - max_val="10" - min_val="1" - name="wmiNightVisionBrightMult" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiNightVisionNoiseSizeText" - top_pad="4" - width="355"> - Noise Size - </text> - <slider - control_name="wmiNightVisionNoiseSize" - follows="left" - height="10" - initial_value="1" - layout="topleft" - left_delta="4" - max_val="100" - min_val="1" - name="wmiNightVisionNoiseSize" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiNightVisionNoiseStrengthText" - top_pad="4" - width="355"> - Noise Strength - </text> - <slider - control_name="wmiNightVisionNoiseStrength" - follows="left" - height="10" - increment="0.01" - initial_value="0.3" - layout="topleft" - left_delta="4" - name="wmiNightVisionNoiseStrength" - top_pad="20" - width="200" /> - </panel> - <panel - border="true" - follows="left|top|right|bottom" - height="400" - label="Bloom" - layout="topleft" - left_delta="0" - help_topic="post_process_bloom_tab" - name="wmiBloomPanel" - top_delta="-236" - width="398"> - <check_box - control_name="wmiBloomToggle" - height="16" - label="Enable" - layout="topleft" - left="14" - name="wmiBloomToggle" - top="4" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiBloomExtractText" - top_pad="5" - width="355"> - Luminosity Extraction - </text> - <slider - control_name="wmiBloomExtract" - follows="left" - height="10" - increment="0.01" - initial_value="0.9" - layout="topleft" - left_delta="4" - name="wmiBloomExtract" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiBloomSizeText" - top_pad="4" - width="355"> - Bloom Size - </text> - <slider - control_name="wmiBloomSize" - follows="left" - height="10" - increment="0.01" - initial_value="3.0" - layout="topleft" - left_delta="4" - max_val="20" - name="wmiBloomSize" - top_pad="20" - width="200" /> - <text - type="string" - length="1" - follows="left|top|right" - font="SansSerif" - height="16" - layout="topleft" - left_delta="-4" - name="wmiBloomStrengthText" - top_pad="4" - width="355"> - Bloom Strength - </text> - <slider - control_name="wmiBloomStrength" - follows="left" - height="10" - increment="0.01" - initial_value="1.2" - layout="topleft" - left_delta="4" - max_val="10" - name="wmiBloomStrength" - top_pad="20" - width="200" /> - </panel> - <panel - border="true" - follows="left|top|right|bottom" - height="400" - label="Extras" - layout="topleft" - left_delta="0" - mouse_opaque="false" - help_topic="post_process_extras_tab" - name="Extras" - top_delta="-236" - width="398"> - <button - height="20" - label="LoadEffect" - label_selected="LoadEffect" - layout="topleft" - left="15" - name="PPLoadEffect" - top="13" - width="100" /> - <button - height="20" - label="SaveEffect" - label_selected="SaveEffect" - layout="topleft" - left_delta="0" - name="PPSaveEffect" - top_pad="7" - width="100" /> - <combo_box - height="18" - layout="topleft" - left_delta="120" - name="PPEffectsCombo" - top="15" - width="150" /> - <line_editor - border_style="line" - border_thickness="1" - follows="left|right|bottom" - font="SansSerif" - height="20" - label="Effect Name" - layout="topleft" - left_delta="0" - max_length_bytes="40" - name="PPEffectNameEditor" - tab_group="1" - top_pad="22" - width="150" /> - </panel> - </tab_container> -</floater> -- cgit v1.2.3 From f6aca1044e2b8ab6d8bad9552355d92a91ca4991 Mon Sep 17 00:00:00 2001 From: Cosmic Linden <cosmic@lindenlab.com> Date: Fri, 27 Sep 2024 12:20:52 -0700 Subject: secondlife/viewer#2638: Do clear smaa buffer due to discard --- indra/newview/pipeline.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 19868d2eef..207afd7a5c 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7435,7 +7435,8 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src) LLGLSLShader& edge_shader = gSMAAEdgeDetectProgram[fsaa_quality]; dest.bindTarget(); - dest.invalidate(GL_COLOR_BUFFER_BIT); + // SMAA utilizes discard, so the background color matters + dest.clear(GL_COLOR_BUFFER_BIT); edge_shader.bind(); edge_shader.uniform4fv(sSmaaRTMetrics, 1, rt_metrics); -- cgit v1.2.3 From f96afdd7a8d254185bd55cf981247a34b5332c33 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Sun, 29 Sep 2024 18:48:24 +0300 Subject: Clear redundant pathing code --- indra/newview/llviewermenu.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 2138da4c64..2d94b4da9f 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9471,12 +9471,7 @@ void lua_run_script(const LLSD& userdata) LL_WARNS() << "Script name is not specified" << LL_ENDL; return; } - fsyspath fs_script_path(script_path); - script_path = fs_script_path.lexically_normal().u8string(); - if (!fs_script_path.is_absolute()) - { - script_path = (fsyspath(gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua")) / script_path).u8string(); - } + LLLUAmanager::runScriptFile(script_path); } -- cgit v1.2.3 From b15c1949f067c752dfddb5d9cfcb10d2dc290cd2 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> Date: Fri, 13 Sep 2024 17:00:22 +0200 Subject: #2410 Combat 2.0 settings not reflected on heart icon --- indra/newview/skins/default/xui/en/notifications.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 848d9aca7c..6c127ece53 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7556,7 +7556,7 @@ Message from [NAME]: type="notify"> <unique/> This land has damage enabled. -You can be hurt here. If you die, you will be teleported to your home location. +You can be hurt here. If you die, you might be teleported to your home location or to the spawn point. </notification> <notification -- cgit v1.2.3