diff options
124 files changed, 40424 insertions, 33941 deletions
diff --git a/.github/labeler.yaml b/.github/labeler.yaml index d31a361baf..6e03801b65 100644 --- a/.github/labeler.yaml +++ b/.github/labeler.yaml @@ -76,3 +76,6 @@ c/cpp: - '**/*.i' - '**/*.inl' - '**/*.y' + +'team:viewer': + - '*' diff --git a/autobuild.xml b/autobuild.xml index 13c9e7ec35..0a49fa7cda 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1732,6 +1732,66 @@ <key>name</key> <string>llphysicsextensions_tpv</string> </map> + <key>luau</key> + <map> + <key>platforms</key> + <map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>59bf3d96f9df4b6981c406abac5c46ae276f9b15</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-luau/releases/download/v0.609-9567db9/luau-0.609-9567db9-darwin64-9567db9.tar.zst</string> + </map> + <key>name</key> + <string>darwin64</string> + </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>549516ada483ddf276183f66b0a7c3d01e4ef1aa</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-luau/releases/download/v0.609-9567db9/luau-0.609-9567db9-linux64-9567db9.tar.zst</string> + </map> + <key>name</key> + <string>linux64</string> + </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>43e2cc2e6e94299f89655435002864925b640e16</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-luau/releases/download/v0.609-9567db9/luau-0.609-9567db9-windows64-9567db9.tar.zst</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + </map> + <key>license</key> + <string>MIT</string> + <key>license_file</key> + <string>LICENSES/luau.txt</string> + <key>copyright</key> + <string>Copyright (c) 2019-2023 Roblox Corporation, Copyright (c) 1994–2019 Lua.org, PUC-Rio.</string> + <key>version</key> + <string>0.609-9567db9</string> + <key>name</key> + <string>luau</string> + <key>description</key> + <string>Luau is a fast, small, safe, gradually typed embeddable scripting language derived from Lua.</string> + </map> <key>mesa</key> <map> <key>platforms</key> diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 05c51c018d..45c56f2d2c 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -44,6 +44,7 @@ set(cmake_SOURCE_FILES LLTestCommand.cmake LLWindow.cmake Linking.cmake + Lualibs.cmake Meshoptimizer.cmake NDOF.cmake OPENAL.cmake diff --git a/indra/cmake/Lualibs.cmake b/indra/cmake/Lualibs.cmake new file mode 100644 index 0000000000..d66305a8e5 --- /dev/null +++ b/indra/cmake/Lualibs.cmake @@ -0,0 +1,29 @@ +# -*- cmake -*- + +include_guard() + +include(Prebuilt) + +add_library( ll::lualibs INTERFACE IMPORTED ) + +use_system_binary( lualibs ) + +use_prebuilt_binary(luau) + +target_include_directories( ll::lualibs SYSTEM INTERFACE + ${LIBS_PREBUILT_DIR}/include +) + +if (WINDOWS) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/Luau.Ast.lib) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/Luau.CodeGen.lib) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/Luau.Compiler.lib) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/Luau.Config.lib) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/Luau.VM.lib) +else () + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libLuau.CodeGen.a) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libLuau.Compiler.a) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libLuau.Config.a) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libLuau.VM.a) + target_link_libraries(ll::lualibs INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libLuau.Ast.a) +endif () diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake index 634cc15c21..a8c702bfef 100644 --- a/indra/cmake/Prebuilt.cmake +++ b/indra/cmake/Prebuilt.cmake @@ -40,6 +40,7 @@ macro (use_prebuilt_binary _binary) --install-dir=${AUTOBUILD_INSTALL_DIR} ${_binary} ") endif(DEBUG_PREBUILT) + message(STATUS "Installing ${_binary}...") execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" install --install-dir=${AUTOBUILD_INSTALL_DIR} diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py index 940a130a50..ef4d712254 100755 --- a/indra/cmake/run_build_test.py +++ b/indra/cmake/run_build_test.py @@ -122,19 +122,17 @@ def main(command, arguments=[], libpath=[], vars={}): # Make sure we see all relevant output *before* child-process output. sys.stdout.flush() try: - return subprocess.call(command_list) - except OSError as err: + return subprocess.run(command_list).returncode + except FileNotFoundError as err: # If the caller is trying to execute a test program that doesn't # exist, we want to produce a reasonable error message rather than a # traceback. This happens when the build is halted by errors, but # CMake tries to proceed with testing anyway <eyeroll/>. However, do # NOT attempt to handle any error but "doesn't exist." - if err.errno != errno.ENOENT: - raise # In practice, the pathnames into CMake's build tree are so long as to # obscure the name of the test program. Just log its basename. - log.warn("No such program %s; check for preceding build errors" % \ - os.path.basename(command[0])) + log.warning("No such program %s; check for preceding build errors" % + os.path.basename(command[0])) # What rc should we simulate for missing executable? Windows produces # 9009. return 9009 @@ -152,7 +150,7 @@ def translate_rc(rc): """ if rc is None: return "still running" - + if rc >= 0: return "terminated with rc %s" % rc diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index c947184dc8..aa0b66f2f4 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -108,6 +108,8 @@ set(llcommon_SOURCE_FILES lluriparser.cpp lluuid.cpp llworkerthread.cpp + lua_function.cpp + lualistener.cpp hbxxh.cpp u64.cpp threadpool.cpp @@ -125,6 +127,7 @@ set(llcommon_HEADER_FILES commoncontrol.h ctype_workaround.h fix_macros.h + fsyspath.h function_types.h indra_constants.h lazyeventapi.h @@ -250,6 +253,8 @@ set(llcommon_HEADER_FILES llwin32headers.h llwin32headerslean.h llworkerthread.h + lua_function.h + lualistener.h hbxxh.h lockstatic.h stdtypes.h diff --git a/indra/llcommon/fsyspath.h b/indra/llcommon/fsyspath.h new file mode 100644 index 0000000000..aa4e0132bc --- /dev/null +++ b/indra/llcommon/fsyspath.h @@ -0,0 +1,74 @@ +/** + * @file fsyspath.h + * @author Nat Goodspeed + * @date 2024-04-03 + * @brief Adapt our UTF-8 std::strings for std::filesystem::path + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_FSYSPATH_H) +#define LL_FSYSPATH_H + +#include <filesystem> + +// While std::filesystem::path can be directly constructed from std::string on +// both Posix and Windows, that's not what we want on Windows. Per +// https://en.cppreference.com/w/cpp/filesystem/path/path: + +// ... the method of conversion to the native character set depends on the +// character type used by source. +// +// * If the source character type is char, the encoding of the source is +// assumed to be the native narrow encoding (so no conversion takes place on +// POSIX systems). +// * If the source character type is char8_t, conversion from UTF-8 to native +// filesystem encoding is used. (since C++20) +// * If the source character type is wchar_t, the input is assumed to be the +// native wide encoding (so no conversion takes places on Windows). + +// The trouble is that on Windows, from std::string ("source character type is +// char"), the "native narrow encoding" isn't UTF-8, so file paths containing +// non-ASCII characters get mangled. +// +// Once we're building with C++20, we could pass a UTF-8 std::string through a +// vector<char8_t> to engage std::filesystem::path's own UTF-8 conversion. But +// sigh, as of 2024-04-03 we're not yet there. +// +// Anyway, encapsulating the important UTF-8 conversions in our own subclass +// allows us to migrate forward to C++20 conventions without changing +// referencing code. + +class fsyspath: public std::filesystem::path +{ + using super = std::filesystem::path; + +public: + // default + fsyspath() {} + // construct from UTF-8 encoded std::string + fsyspath(const std::string& path): super(std::filesystem::u8path(path)) {} + // construct from UTF-8 encoded const char* + fsyspath(const char* path): super(std::filesystem::u8path(path)) {} + // construct from existing path + fsyspath(const super& path): super(path) {} + + fsyspath& operator=(const super& p) { super::operator=(p); return *this; } + fsyspath& operator=(const std::string& p) + { + super::operator=(std::filesystem::u8path(p)); + return *this; + } + fsyspath& operator=(const char* p) + { + super::operator=(std::filesystem::u8path(p)); + return *this; + } + + // shadow base-class string() method with UTF-8 aware method + std::string string() const { return super::u8string(); } +}; + +#endif /* ! defined(LL_FSYSPATH_H) */ diff --git a/indra/test/hexdump.h b/indra/llcommon/hexdump.h index 95f1e297c3..234168cd61 100644..100755 --- a/indra/test/hexdump.h +++ b/indra/llcommon/hexdump.h @@ -1,9 +1,9 @@ /** * @file hexdump.h * @author Nat Goodspeed - * @date 2023-09-08 - * @brief Provide hexdump() and hexmix() ostream formatters - * + * @date 2023-10-03 + * @brief iostream manipulators to stream hex, or string with nonprinting chars + * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Copyright (c) 2023, Linden Research, Inc. * $/LicenseInfo$ @@ -17,6 +17,9 @@ #include <iostream> #include <string_view> +namespace LL +{ + // Format a given byte string as 2-digit hex values, no separators // Usage: std::cout << hexdump(somestring) << ... class hexdump @@ -30,6 +33,10 @@ public: hexdump(reinterpret_cast<const unsigned char*>(data), len) {} + hexdump(const std::vector<unsigned char>& data): + hexdump(data.data(), data.size()) + {} + hexdump(const unsigned char* data, size_t len): mData(data, data + len) {} @@ -94,4 +101,6 @@ private: std::string mData; }; +} // namespace LL + #endif /* ! defined(LL_HEXDUMP_H) */ diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 20340397db..1926941d1f 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-03 * @brief Implementation for llcoros. - * + * * $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$ */ @@ -51,18 +51,19 @@ #endif // other Linden headers #include "llapp.h" -#include "lltimer.h" -#include "llevents.h" #include "llerror.h" -#include "stringize.h" +#include "llevents.h" #include "llexception.h" +#include "llsdutil.h" +#include "lltimer.h" +#include "stringize.h" #if LL_WINDOWS #include <excpt.h> #endif // static -LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller) +LLCoros::CoroData& LLCoros::get_CoroData(const std::string&) { CoroData* current{ nullptr }; // be careful about attempted accesses in the final throes of app shutdown @@ -94,7 +95,7 @@ LLCoros::coro::id LLCoros::get_self() //static void LLCoros::set_consuming(bool consuming) { - CoroData& data(get_CoroData("set_consuming()")); + auto& data(get_CoroData("set_consuming()")); // DO NOT call this on the main() coroutine. llassert_always(! data.mName.empty()); data.mConsuming = consuming; @@ -128,6 +129,15 @@ LLCoros::LLCoros(): // points to it. So initialize it with a no-op deleter. mCurrent{ [](CoroData*){} } { + auto& llapp{ LLEventPumps::instance().obtain("LLApp") }; + if (llapp.getListener("LLCoros") == LLBoundListener()) + { + // chain our "LLCoros" pump onto "LLApp" pump: echo events posted to "LLApp" + mConn = llapp.listen( + "LLCoros", + [](const LLSD& event) + { return LLEventPumps::instance().obtain("LLCoros").post(event); }); + } } LLCoros::~LLCoros() @@ -177,26 +187,26 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const // Until we find an unused name, append a numeric suffix for uniqueness. while (CoroData::getInstance(name)) { - name = STRINGIZE(prefix << unique++); + name = stringize(prefix, unique++); } return name; } -/*==========================================================================*| -bool LLCoros::kill(const std::string& name) +bool LLCoros::killreq(const std::string& name) { - CoroMap::iterator found = mCoros.find(name); - if (found == mCoros.end()) + auto found = CoroData::getInstance(name); + if (! found) { return false; } - // Because this is a boost::ptr_map, erasing the map entry also destroys - // the referenced heap object, in this case the boost::coroutine object, - // which will terminate the coroutine. - mCoros.erase(found); + // Next time the subject coroutine calls checkStop(), make it terminate. + found->mKilledBy = getName(); + // But if it's waiting for something, notify anyone in a position to poke + // it. + LLEventPumps::instance().obtain("LLCoros").post( + llsd::map("status", "killreq", "coro", name)); return true; } -|*==========================================================================*/ //static std::string LLCoros::getName() @@ -207,7 +217,7 @@ std::string LLCoros::getName() //static std::string LLCoros::logname() { - LLCoros::CoroData& data(get_CoroData("logname()")); + auto& data(get_CoroData("logname()")); return data.mName.empty()? data.getKey() : data.mName; } @@ -360,7 +370,7 @@ void LLCoros::toplevel(std::string name, callable_t callable) // Any uncaught exception derived from LLContinueError will be caught // here and logged. This coroutine will terminate but the rest of the // viewer will carry on. - LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + LOG_UNHANDLED_EXCEPTION(stringize("coroutine ", name)); } catch (...) { @@ -373,15 +383,24 @@ void LLCoros::toplevel(std::string name, callable_t callable) } //static -void LLCoros::checkStop() +void LLCoros::checkStop(callable_t cleanup) { + // don't replicate this 'if' test throughout the code below + if (! cleanup) + { + cleanup = {[](){}}; // hey, look, I'm coding in Haskell! + } + if (wasDeleted()) { + cleanup(); LLTHROW(Shutdown("LLCoros was deleted")); } - // do this AFTER the check above, because getName() depends on - // get_CoroData(), which depends on the local_ptr in our instance(). - if (getName().empty()) + + // do this AFTER the check above, because get_CoroData() depends on the + // local_ptr in our instance(). + auto& data(get_CoroData("checkStop()")); + if (data.mName.empty()) { // Our Stop exception and its subclasses are intended to stop loitering // coroutines. Don't throw it from the main coroutine. @@ -389,19 +408,80 @@ void LLCoros::checkStop() } if (LLApp::isStopped()) { + cleanup(); LLTHROW(Stopped("viewer is stopped")); } if (! LLApp::isRunning()) { + cleanup(); LLTHROW(Stopping("viewer is stopping")); } + if (! data.mKilledBy.empty()) + { + // Someone wants to kill this coroutine + cleanup(); + LLTHROW(Killed(stringize("coroutine ", data.mName, " killed by ", data.mKilledBy))); + } +} + +LLBoundListener LLCoros::getStopListener(const std::string& caller, LLVoidListener cleanup) +{ + if (! cleanup) + return {}; + + // This overload only responds to viewer shutdown. + return LLEventPumps::instance().obtain("LLCoros") + .listen( + LLEventPump::inventName(caller), + [cleanup](const LLSD& event) + { + auto status{ event["status"].asString() }; + if (status != "running" && status != "killreq") + { + cleanup(event); + } + return false; + }); +} + +LLBoundListener LLCoros::getStopListener(const std::string& caller, + const std::string& cnsmr, + LLVoidListener cleanup) +{ + if (! cleanup) + return {}; + + std::string consumer{cnsmr}; + if (consumer.empty()) + { + consumer = getName(); + } + + // This overload responds to viewer shutdown and to killreq(consumer). + return LLEventPumps::instance().obtain("LLCoros") + .listen( + LLEventPump::inventName(caller), + [consumer, cleanup](const LLSD& event) + { + auto status{ event["status"].asString() }; + if (status == "killreq") + { + if (event["coro"].asString() == consumer) + { + cleanup(event); + } + } + else if (status != "running") + { + cleanup(event); + } + return false; + }); } LLCoros::CoroData::CoroData(const std::string& name): LLInstanceTracker<CoroData, std::string>(name), mName(name), - // don't consume events unless specifically directed - mConsuming(false), mCreationTime(LLTimer::getTotalSeconds()) { } @@ -414,7 +494,6 @@ LLCoros::CoroData::CoroData(int n): // empty string as its visible name because some consumers test for that. LLInstanceTracker<CoroData, std::string>("main" + stringize(n)), mName(), - mConsuming(false), mCreationTime(LLTimer::getTotalSeconds()) { } diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 71c1c1c443..61c0fef1c3 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-02 * @brief Manage running boost::coroutine instances - * + * * $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$ */ @@ -29,17 +29,18 @@ #if ! defined(LL_LLCOROS_H) #define LL_LLCOROS_H +#include "llevents.h" #include "llexception.h" +#include "llinstancetracker.h" +#include "llsingleton.h" +#include "mutex.h" #include <boost/fiber/fss.hpp> #include <boost/fiber/future/promise.hpp> #include <boost/fiber/future/future.hpp> -#include "mutex.h" -#include "llsingleton.h" -#include "llinstancetracker.h" -#include <boost/function.hpp> -#include <string> #include <exception> +#include <functional> #include <queue> +#include <string> // e.g. #include LLCOROS_MUTEX_HEADER #define LLCOROS_MUTEX_HEADER <boost/fiber/mutex.hpp> @@ -101,7 +102,7 @@ public: /// stuck with the term "coroutine." typedef boost::fibers::fiber coro; /// Canonical callable type - typedef boost::function<void()> callable_t; + typedef std::function<void()> callable_t; /** * Create and start running a new coroutine with specified name. The name @@ -143,13 +144,13 @@ public: std::string launch(const std::string& prefix, const callable_t& callable); /** - * Abort a running coroutine by name. Normally, when a coroutine either + * Ask the named coroutine to abort. Normally, when a coroutine either * runs to completion or terminates with an exception, LLCoros quietly * cleans it up. This is for use only when you must explicitly interrupt * one prematurely. Returns @c true if the specified name was found and * still running at the time. */ -// bool kill(const std::string& name); + bool killreq(const std::string& name); /** * From within a coroutine, look up the (tweaked) name string by which @@ -158,7 +159,7 @@ public: * LLCoros::launch()). */ static std::string getName(); - + /** * rethrow() is called by the thread's main fiber to propagate an * exception from any coroutine into the main fiber, where it can engage @@ -251,15 +252,21 @@ public: /// thrown by checkStop() // It may sound ironic that Stop is derived from LLContinueError, but the // point is that LLContinueError is the category of exception that should - // not immediately crash the viewer. Stop and its subclasses are to notify - // coroutines that the viewer intends to shut down. The expected response - // is to terminate the coroutine, rather than abort the viewer. + // not immediately crash the viewer. Stop and its subclasses are to tell + // coroutines to terminate, e.g. because the viewer is shutting down. We + // do not want any such exception to crash the viewer. struct Stop: public LLContinueError { Stop(const std::string& what): LLContinueError(what) {} }; - /// early stages + /// someone wants to kill this specific coroutine + struct Killed: public Stop + { + Killed(const std::string& what): Stop(what) {} + }; + + /// early shutdown stages struct Stopping: public Stop { Stopping(const std::string& what): Stop(what) {} @@ -278,9 +285,31 @@ public: }; /// Call this intermittently if there's a chance your coroutine might - /// continue running into application shutdown. Throws Stop if LLCoros has - /// been cleaned up. - static void checkStop(); + /// still be running at application shutdown. Throws one of the Stop + /// subclasses if the caller needs to terminate. Pass a cleanup function + /// if you need to execute that cleanup before terminating. + /// Of course, if your cleanup function throws, that will be the exception + /// propagated by checkStop(). + static void checkStop(callable_t cleanup={}); + + /// Call getStopListener() at the source end of a queue, promise or other + /// resource on which coroutines will wait, so that shutdown can wake up + /// consuming coroutines. @a caller should distinguish who's calling. The + /// passed @a cleanup function must close the queue, break the promise or + /// otherwise cause waiting consumers to wake up in an abnormal way. It's + /// advisable to store the returned LLBoundListener in an + /// LLTempBoundListener, or otherwise arrange to disconnect it. + static LLBoundListener getStopListener(const std::string& caller, LLVoidListener cleanup); + + /// This getStopListener() overload is like the two-argument one, for use + /// when we know the name of the only coroutine that will wait on the + /// resource in question. Pass @a consumer as the empty string if the + /// consumer coroutine is the same as the calling coroutine. Unlike the + /// two-argument getStopListener(), this one also responds to + /// killreq(target). + static LLBoundListener getStopListener(const std::string& caller, + const std::string& consumer, + LLVoidListener cleanup); /** * Aliases for promise and future. An older underlying future implementation @@ -312,6 +341,8 @@ private: static CoroData& get_CoroData(const std::string& caller); void saveException(const std::string& name, std::exception_ptr exc); + LLTempBoundListener mConn; + struct ExceptionData { ExceptionData(const std::string& nm, std::exception_ptr exc): @@ -335,8 +366,10 @@ private: // tweaked name of the current coroutine const std::string mName; - // set_consuming() state - bool mConsuming; + // set_consuming() state -- don't consume events unless specifically directed + bool mConsuming{ false }; + // killed by which coroutine + std::string mKilledBy; // setStatus() state std::string mStatus; F64 mCreationTime; // since epoch diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index e1fc4764f6..d651aae39c 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-29 * @brief Implementation for lleventcoro. - * + * * $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$ */ @@ -119,7 +119,7 @@ void llcoro::suspendUntilTimeout(float seconds) // We used to call boost::this_fiber::sleep_for(). But some coroutines // (e.g. LLExperienceCache::idleCoro()) sit in a suspendUntilTimeout() // loop, in which case a sleep_for() call risks sleeping through shutdown. - // So instead, listen for "LLApp" state-changing events -- which + // So instead, listen for LLApp state-changing events -- which // fortunately is handled for us by suspendUntilEventOnWithTimeout(). // Wait for an event on a bogus LLEventPump on which nobody ever posts // events. Don't make it static because that would force instantiation of @@ -132,8 +132,8 @@ void llcoro::suspendUntilTimeout(float seconds) // Timeout is the NORMAL case for this call! static LLSD timedout; // Deliver, but ignore, timedout when (as usual) we did not receive any - // "LLApp" event. The point is that suspendUntilEventOnWithTimeout() will - // itself throw Stopping when "LLApp" starts broadcasting shutdown events. + // LLApp event. The point is that suspendUntilEventOnWithTimeout() will + // itself throw Stopping when LLApp starts broadcasting shutdown events. suspendUntilEventOnWithTimeout(bogus, seconds, timedout); } @@ -167,33 +167,26 @@ postAndSuspendSetup(const std::string& callerName, // "LLApp" were an LLEventMailDrop. But if we ever go there, we'd want to // notice the pending LLApp status first. LLBoundListener stopper( - LLEventPumps::instance().obtain("LLApp").listen( + LLCoros::getStopListener( listenerName, + LLCoros::instance().getName(), [&promise, listenerName](const LLSD& status) { - // anything except "running" should wake up the waiting - // coroutine - auto& statsd = status["status"]; - if (statsd.asString() != "running") + LL_DEBUGS("lleventcoro") << listenerName + << " spotted status " << status + << ", throwing Stopping" << LL_ENDL; + try + { + promise.set_exception( + std::make_exception_ptr( + LLCoros::Stopping("status " + stringize(status)))); + } + catch (const boost::fibers::promise_already_satisfied&) { - LL_DEBUGS("lleventcoro") << listenerName - << " spotted status " << statsd - << ", throwing Stopping" << LL_ENDL; - try - { - promise.set_exception( - std::make_exception_ptr( - LLCoros::Stopping("status " + statsd.asString()))); - } - catch (const boost::fibers::promise_already_satisfied&) - { - LL_WARNS("lleventcoro") << listenerName - << " couldn't throw Stopping " - "because promise already set" << LL_ENDL; - } + LL_WARNS("lleventcoro") << listenerName + << " couldn't throw Stopping " + "because promise already set" << LL_ENDL; } - // do not consume -- every listener must see status - return false; })); LLBoundListener connection( replyPump.listen( diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index 4c3c0f3414..35bf9075a0 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -6,25 +6,25 @@ * useful when you have a single LLEventPump listener on which you can * request different operations, vs. instantiating a different * LLEventPump for each such operation. - * + * * $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$ */ @@ -201,7 +201,7 @@ public: template <typename R, class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG)) @@ -213,7 +213,7 @@ public: template <typename R, class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG) const) @@ -226,7 +226,7 @@ public: template <class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG)) @@ -238,7 +238,7 @@ public: template <class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG) const) @@ -247,7 +247,7 @@ public: } // non-const binary (or more) method - template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG0, ARG1, ARGS...)) @@ -256,7 +256,7 @@ public: } // const binary (or more) method - template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG0, ARG1, ARGS...) const) @@ -265,7 +265,7 @@ public: } // non-const binary (or more) method returning void - template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG0, ARG1, ARGS...)) @@ -274,7 +274,7 @@ public: } // const binary (or more) method returning void - template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG0, ARG1, ARGS...) const) @@ -371,7 +371,7 @@ public: const InstanceGetter& getter, const LLSD& params, const LLSD& defaults=LLSD()); - //@} + //@} /// Unregister a callable bool remove(const std::string& name); @@ -851,6 +851,8 @@ public: ARGS&&... args); virtual ~LLDispatchListener() {} + std::string getPumpName() const { return getName(); } + private: bool process(const LLSD& event) const; void call_one(const LLSD& name, const LLSD& event) const; diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 5b4e69659d..d7870763cc 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-12 * @brief Implementation for llevents. - * + * * $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$ */ @@ -43,6 +43,7 @@ #include <typeinfo> #include <cmath> #include <cctype> +#include <iomanip> // std::quoted // external library headers #include <boost/range/iterator_range.hpp> #if LL_WINDOWS @@ -54,10 +55,11 @@ #pragma warning (pop) #endif // other Linden headers -#include "stringize.h" #include "llerror.h" -#include "llsdutil.h" +#include "lleventfilter.h" #include "llexception.h" +#include "llsdutil.h" +#include "stringize.h" #if LL_MSVC #pragma warning (disable : 4702) #endif @@ -71,7 +73,9 @@ LLEventPumps::LLEventPumps(): { "LLEventStream", [](const std::string& name, bool tweak, const std::string& /*type*/) { return new LLEventStream(name, tweak); } }, { "LLEventMailDrop", [](const std::string& name, bool tweak, const std::string& /*type*/) - { return new LLEventMailDrop(name, tweak); } } + { return new LLEventMailDrop(name, tweak); } }, + { "LLEventLogProxy", [](const std::string& name, bool tweak, const std::string& /*type*/) + { return new LLEventLogProxyFor<LLEventStream>(name, tweak); } } }, mTypes { @@ -186,8 +190,13 @@ bool LLEventPumps::post(const std::string&name, const LLSD&message) PumpMap::iterator found = mPumpMap.find(name); if (found == mPumpMap.end()) + { + LL_DEBUGS("LLEventPumps") << "LLEventPump(" << std::quoted(name) << ") not found" + << LL_ENDL; return false; + } +// LL_DEBUGS("LLEventPumps") << "posting to " << name << ": " << message << LL_ENDL; return (*found).second->post(message); } @@ -414,7 +423,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL { if (!mSignal) { - LL_WARNS() << "Can't connect listener" << LL_ENDL; + LL_WARNS("LLEventPump") << "Can't connect listener" << LL_ENDL; // connect will fail, return dummy return LLBoundListener(); } @@ -423,8 +432,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL float nodePosition = 1.0; - // if the supplied name is empty we are not interested in the ordering mechanism - // and can bypass attempting to find the optimal location to insert the new + // if the supplied name is empty we are not interested in the ordering mechanism + // and can bypass attempting to find the optimal location to insert the new // listener. We'll just tack it on to the end. if (!name.empty()) // should be the same as testing against ANONYMOUS { @@ -569,12 +578,12 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // Now that newNode has a value that places it appropriately in mSignal, // connect it. LLBoundListener bound = mSignal->connect(nodePosition, listener); - + if (!name.empty()) { // note that we are not tracking anonymous listeners here either. - // This means that it is the caller's responsibility to either assign - // to a TempBoundListerer (scoped_connection) or manually disconnect - // when done. + // This means that it is the caller's responsibility to either assign + // to a TempBoundListerer (scoped_connection) or manually disconnect + // when done. mConnections[name] = bound; } return bound; @@ -641,9 +650,9 @@ bool LLEventMailDrop::post(const LLSD& event) { // forward the call to our base class bool posted = LLEventStream::post(event); - + if (!posted) - { // if the event was not handled we will save it for later so that it can + { // if the event was not handled we will save it for later so that it can // be posted to any future listeners when they attach. mEventHistory.push_back(event); } @@ -733,7 +742,7 @@ void LLReqID::stamp(LLSD& response) const response["reqid"] = mReqid; } -bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey) +bool sendReply(LLSD reply, const LLSD& request, const std::string& replyKey) { // If the original request has no value for replyKey, it's pointless to // construct or send a reply event: on which LLEventPump should we send @@ -746,13 +755,10 @@ bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyK // Here the request definitely contains replyKey; reasonable to proceed. - // Copy 'reply' to modify it. - LLSD newreply(reply); // Get the ["reqid"] element from request LLReqID reqID(request); - // and copy it to 'newreply'. - reqID.stamp(newreply); - // Send reply on LLEventPump named in request[replyKey]. Don't forget to - // send the modified 'newreply' instead of the original 'reply'. - return LLEventPumps::instance().obtain(request[replyKey]).post(newreply); + // and copy it to 'reply'. + reqID.stamp(reply); + // Send reply on LLEventPump named in request[replyKey]. + return LLEventPumps::instance().obtain(request[replyKey]).post(reply); } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 9a0a6863f0..1fc0f23ecd 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -6,25 +6,25 @@ * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System, * originally introduced in llnotifications.h. It has nothing * whatsoever to do with the older system in llevent.h. - * + * * $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$ */ @@ -39,36 +39,22 @@ #include <deque> #include <functional> #if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) #endif #include <boost/signals2.hpp> #if LL_WINDOWS - #pragma warning (pop) + #pragma warning (pop) #endif -#include <boost/bind.hpp> -#include <boost/utility.hpp> // noncopyable #include <boost/optional/optional.hpp> -#include <boost/visit_each.hpp> -#include <boost/ref.hpp> // reference_wrapper -#include <boost/type_traits/is_pointer.hpp> -#include <boost/static_assert.hpp> #include "llsd.h" #include "llsingleton.h" #include "lldependencies.h" -#include "llstl.h" #include "llexception.h" #include "llhandle.h" -/*==========================================================================*| -// override this to allow binding free functions with more parameters -#ifndef LLEVENTS_LISTENER_ARITY -#define LLEVENTS_LISTENER_ARITY 10 -#endif -|*==========================================================================*/ - // hack for testing #ifndef testable #define testable private @@ -151,6 +137,8 @@ typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LL /// Methods that forward listeners (e.g. constructed with /// <tt>boost::bind()</tt>) should accept (const LLEventListener&) typedef LLStandardSignal::slot_type LLEventListener; +/// Accept a void listener too +typedef std::function<void(const LLSD&)> LLVoidListener; /// Result of registering a listener, supports <tt>connected()</tt>, /// <tt>disconnect()</tt> and <tt>blocked()</tt> typedef boost::signals2::connection LLBoundListener; @@ -310,9 +298,9 @@ public: /** * Find the named LLEventPump instance. If it exists post the message to it. * If the pump does not exist, do nothing. - * + * * returns the result of the LLEventPump::post. If no pump exists returns false. - * + * * This is syntactically similar to LLEventPumps::instance().post(name, message), * however if the pump does not already exist it will not be created. */ @@ -541,10 +529,10 @@ public: * instantiate your listener, then passing the same name on each listen() * call, allows us to optimize away the second and subsequent dependency * sorts. - * - * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire - * dependency and ordering calculation. In this case, it is critical that - * the result be assigned to a LLTempBoundListener or the listener is + * + * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire + * dependency and ordering calculation. In this case, it is critical that + * the result be assigned to a LLTempBoundListener or the listener is * manually disconnected when no longer needed since there will be no * way to later find and disconnect this listener manually. */ @@ -607,7 +595,7 @@ protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, const NameList& after, const NameList& before); - + /// implement the dispatching std::shared_ptr<LLStandardSignal> mSignal; @@ -660,21 +648,21 @@ public: * by all listeners, until some listener consumes it. The caveat is that each * event *must* eventually reach a listener that will consume it, else the * queue will grow to arbitrary length. - * + * * @NOTE: When using an LLEventMailDrop with an LLEventTimeout or * LLEventFilter attaching the filter downstream, using Timeout's constructor will - * cause the MailDrop to discharge any of its stored events. The timeout should - * instead be connected upstream using its listen() method. + * cause the MailDrop to discharge any of its stored events. The timeout should + * instead be connected upstream using its listen() method. */ class LL_COMMON_API LLEventMailDrop : public LLEventStream { public: LLEventMailDrop(const std::string& name, bool tweak = false) : LLEventStream(name, tweak) {} virtual ~LLEventMailDrop() {} - + /// Post an event to all listeners virtual bool post(const LLSD& event) override; - + /// Remove any history stored in the mail drop. void discard(); @@ -689,6 +677,30 @@ private: }; /***************************************************************************** +* LLNamedListener +*****************************************************************************/ +/** + * LLNamedListener bundles a concrete LLEventPump subclass with a specific + * listener function, with an LLTempBoundListener to ensure that it's + * disconnected before destruction. + */ +template <class PUMP=LLEventStream> +class LL_COMMON_API LLNamedListener: PUMP +{ + using pump_t = PUMP; +public: + template <typename LISTENER> + LLNamedListener(const std::string& name, LISTENER&& listener): + pump_t(name, false), // don't tweak the name + mConn(pump_t::listen("func", std::forward<LISTENER>(listener))) + {} + +private: + LLTempBoundListener mConn; +}; +using LLStreamListener = LLNamedListener<>; + +/***************************************************************************** * LLReqID *****************************************************************************/ /** @@ -780,7 +792,7 @@ private: * Before sending the reply event, sendReply() copies the ["reqid"] item from * the request to the reply. */ -LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request, +LL_COMMON_API bool sendReply(LLSD reply, const LLSD& request, const std::string& replyKey="reply"); #endif /* ! defined(LL_LLEVENTS_H) */ diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 68e609444e..9e322db86d 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-06-29 * @brief Types needed for generic exception handling - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -12,6 +12,7 @@ #if ! defined(LL_LLEXCEPTION_H) #define LL_LLEXCEPTION_H +#include "stdtypes.h" #include <stdexcept> #include <boost/exception/exception.hpp> #include <boost/throw_exception.hpp> diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h index 4456a72696..97ea3b7b78 100644 --- a/indra/llcommon/llformat.h +++ b/indra/llcommon/llformat.h @@ -1,4 +1,4 @@ -/** +/** * @file llformat.h * @date January 2007 * @brief string formatting utility @@ -6,21 +6,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$ */ @@ -28,6 +28,8 @@ #ifndef LL_LLFORMAT_H #define LL_LLFORMAT_H +#include "llpreprocessor.h" + // Use as follows: // LL_INFOS() << llformat("Test:%d (%.2f %.2f)", idx, x, y) << LL_ENDL; // diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 3232a0e219..921f743ada 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -1,4 +1,4 @@ -/** +/** * @file llinstancetracker.h * @brief LLInstanceTracker is a mixin class that automatically tracks object * instances with or without an associated key @@ -6,21 +6,21 @@ * $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$ */ @@ -99,11 +99,11 @@ public: return mSelf; } - static size_t instanceCount() - { - return LockStatic()->mMap.size(); + static size_t instanceCount() + { + return LockStatic()->mMap.size(); } - + // snapshot of std::pair<const KEY, std::shared_ptr<SUBCLASS>> pairs, for // some SUBCLASS derived from T template <typename SUBCLASS> @@ -243,7 +243,7 @@ public: } protected: - LLInstanceTracker(const KEY& key) + LLInstanceTracker(const KEY& key) { // We do not intend to manage the lifespan of this object with // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our @@ -275,6 +275,35 @@ protected: public: virtual const KEY& getKey() const { return mInstanceKey; } + /// for use ONLY for an object we're sure resides on the heap! + static bool destruct(const KEY& key) + { + return destruct(getInstance(key)); + } + + /// for use ONLY for an object we're sure resides on the heap! + static bool destruct(const weak_t& ptr) + { + return destruct(ptr.lock()); + } + + /// for use ONLY for an object we're sure resides on the heap! + static bool destruct(const ptr_t& ptr) + { + if (! ptr) + { + return false; + } + + // Because we store and return ptr_t instances with no-op deleters, + // merely resetting the last pointer doesn't destroy the referenced + // object. Don't even bother resetting 'ptr'. Just extract its raw + // pointer and delete that. + auto raw{ ptr.get() }; + delete raw; + return true; + } + private: LLInstanceTracker( const LLInstanceTracker& ) = delete; LLInstanceTracker& operator=( const LLInstanceTracker& ) = delete; @@ -286,9 +315,9 @@ private: static std::string report(const char* key) { return report(std::string(key)); } // caller must instantiate LockStatic - void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) - { - mInstanceKey = key; + void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) + { + mInstanceKey = key; InstanceMap& map = lock->mMap; switch(KEY_COLLISION_BEHAVIOR) { @@ -373,7 +402,7 @@ public: { return mSelf; } - + static size_t instanceCount() { return LockStatic()->mSet.size(); @@ -479,6 +508,29 @@ public: template <typename SUBCLASS> using key_snapshot_of = instance_snapshot_of<SUBCLASS>; + /// for use ONLY for an object we're sure resides on the heap! + static bool destruct(const weak_t& ptr) + { + return destruct(ptr.lock()); + } + + /// for use ONLY for an object we're sure resides on the heap! + static bool destruct(const ptr_t& ptr) + { + if (! ptr) + { + return false; + } + + // Because we store and return ptr_t instances with no-op deleters, + // merely resetting the last pointer doesn't destroy the referenced + // object. Don't even bother resetting 'ptr'. Just extract its raw + // pointer and delete that. + auto raw{ ptr.get() }; + delete raw; + return true; + } + protected: LLInstanceTracker() { diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index d0fb586459..f7f2981638 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-20 * @brief Implementation for llleap. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ @@ -14,13 +14,11 @@ // associated header #include "llleap.h" // STL headers -#include <sstream> #include <algorithm> +#include <memory> +#include <sstream> // std headers // external library headers -#include <boost/bind.hpp> -#include <boost/scoped_ptr.hpp> -#include <boost/tokenizer.hpp> // other Linden headers #include "llerror.h" #include "llstring.h" @@ -53,18 +51,19 @@ public: // We expect multiple LLLeapImpl instances. Definitely tweak // mDonePump's name for uniqueness. mDonePump("LLLeap", true), - // Troubling thought: what if one plugin intentionally messes with - // another plugin? LLEventPump names are in a single global namespace. - // Try to make that more difficult by generating a UUID for the reply- - // pump name -- so it should NOT need tweaking for uniqueness. - mReplyPump(LLUUID::generateNewID().asString()), mExpect(0), // Instantiate a distinct LLLeapListener for this plugin. (Every // plugin will want its own collection of managed listeners, etc.) - // Pass it a callback to our connect() method, so it can send events + // Pass it our wstdin() method as its callback, so it can send events // from a particular LLEventPump to the plugin without having to know // this class or method name. - mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2))) + mListener( + new LLLeapListener( + "LLLeap", + // Serialize any reply event to our child's stdin, suitably + // enriched with the pump name on which it was received. + [this](const std::string& pump, const LLSD& data) + { return wstdin(pump, data); })) { // Rule out unpopulated Params block if (! cparams.executable.isProvided()) @@ -93,7 +92,7 @@ public: } // Listen for child "termination" right away to catch launch errors. - mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1)); + mDonePump.listen("LLLeap", [this](const LLSD& data){ return bad_launch(data); }); // Okay, launch child. // Get a modifiable copy of params block to set files and postend. @@ -113,7 +112,7 @@ public: // Okay, launch apparently worked. Change our mDonePump listener. mDonePump.stopListening("LLLeap"); - mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::done, this, _1)); + mDonePump.listen("LLLeap", [this](const LLSD& data){ return done(data); }); // Child might pump large volumes of data through either stdout or // stderr. Don't bother copying all that data into notification event. @@ -123,17 +122,14 @@ public: childout.setLimit(20); childerr.setLimit(20); - // Serialize any event received on mReplyPump to our child's stdin. - mStdinConnection = connect(mReplyPump, "LLLeap"); - // Listening on stdout is stateful. In general, we're either waiting // for the length prefix or waiting for the specified length of data. // We address that with two different listener methods -- one of which // is blocked at any given time. mStdoutConnection = childout.getPump() - .listen("prefix", boost::bind(&LLLeapImpl::rstdout, this, _1)); + .listen("prefix", [this](const LLSD& data){ return rstdout(data); }); mStdoutDataConnection = childout.getPump() - .listen("data", boost::bind(&LLLeapImpl::rstdoutData, this, _1)); + .listen("data", [this](const LLSD& data){ return rstdoutData(data); }); mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection)); // Log anything sent up through stderr. When a typical program @@ -142,7 +138,7 @@ public: // interpreter behaves that way. More generally, though, a plugin // author can log whatever s/he wants to the viewer log using stderr. mStderrConnection = childerr.getPump() - .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1)); + .listen("LLLeap", [this](const LLSD& data){ return rstderr(data); }); // For our lifespan, intercept any LL_ERRS so we can notify plugin mRecorder = LLError::addGenericRecorder( @@ -151,7 +147,7 @@ public: // Send child a preliminary event reporting our own reply-pump name -- // which would otherwise be pretty tricky to guess! - wstdin(mReplyPump.getName(), + wstdin(mListener->getReplyPump().getName(), LLSDMap ("command", mListener->getName()) // Include LLLeap features -- this may be important for child to @@ -198,7 +194,7 @@ public: return false; } - // Listener for events on mReplyPump: send to child stdin + // Listener for reply events: send to child stdin bool wstdin(const std::string& pump, const LLSD& data) { LLSD packet(LLSDMap("pump", pump)("data", data)); @@ -355,7 +351,7 @@ public: // request, send a reply. We happen to know who originated // this request, and the reply LLEventPump of interest. // Not our problem if the plugin ignores the reply event. - data["reply"] = mReplyPump.getName(); + data["reply"] = mListener->getReplyPump().getName(); sendReply(llsd::map("error", stringize(LLError::Log::classname(err), ": ", err.what())), data); @@ -428,7 +424,7 @@ public: LLSD event; event["type"] = "error"; event["error"] = error; - mReplyPump.post(event); + mListener->getReplyPump().post(event); // All the above really accomplished was to buffer the serialized // event in our WritePipe. Have to pump mainloop a couple times to @@ -445,23 +441,10 @@ public: } private: - /// We always want to listen on mReplyPump with wstdin(); under some - /// circumstances we'll also echo other LLEventPumps to the plugin. - LLBoundListener connect(LLEventPump& pump, const std::string& listener) - { - // Serialize any event received on the specified LLEventPump to our - // child's stdin, suitably enriched with the pump name on which it was - // received. - return pump.listen(listener, - boost::bind(&LLLeapImpl::wstdin, this, pump.getName(), _1)); - } - std::string mDesc; LLEventStream mDonePump; - LLEventStream mReplyPump; LLProcessPtr mChild; - LLTempBoundListener - mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection; + LLTempBoundListener mStdoutConnection, mStdoutDataConnection, mStderrConnection; std::unique_ptr<LLEventPump::Blocker> mBlocker; LLProcess::ReadPipe::size_type mExpect; LLError::RecorderPtr mRecorder; diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp index 050d71c327..9b9b0f5121 100644 --- a/indra/llcommon/llleaplistener.cpp +++ b/indra/llcommon/llleaplistener.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-03-16 * @brief Implementation for llleaplistener. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ @@ -54,53 +54,62 @@ return features; } -LLLeapListener::LLLeapListener(const ConnectFunc& connect): +LLLeapListener::LLLeapListener(const std::string_view& caller, const Callback& callback): // Each LEAP plugin has an instance of this listener. Make the command // pump name difficult for other such plugins to guess. LLEventAPI(LLUUID::generateNewID().asString(), "Operations relating to the LLSD Event API Plugin (LEAP) protocol"), - mConnect(connect) + mCaller(caller), + mCallback(callback), + // Troubling thought: what if one plugin intentionally messes with + // another plugin? LLEventPump names are in a single global namespace. + // Try to make that more difficult by generating a UUID for the reply- + // pump name -- so it should NOT need tweaking for uniqueness. + mReplyPump(LLUUID::generateNewID().asString()), + mReplyConn(connect(mReplyPump, mCaller)) { LLSD need_name(LLSDMap("name", LLSD())); add("newpump", - "Instantiate a new LLEventPump named like [\"name\"] and listen to it.\n" - "[\"type\"] == \"LLEventStream\", \"LLEventMailDrop\" et al.\n" - "Events sent through new LLEventPump will be decorated with [\"pump\"]=name.\n" - "Returns actual name in [\"name\"] (may be different if collision).", +R"-(Instantiate a new LLEventPump named like ["name"] and listen to it. +["type"] == "LLEventStream", "LLEventMailDrop" et al. +Events sent through new LLEventPump will be decorated with ["pump"]=name. +Returns actual name in ["name"] (may be different if collision).)-", &LLLeapListener::newpump, need_name); LLSD need_source_listener(LLSDMap("source", LLSD())("listener", LLSD())); add("listen", - "Listen to an existing LLEventPump named [\"source\"], with listener name\n" - "[\"listener\"].\n" - "By default, send events on [\"source\"] to the plugin, decorated\n" - "with [\"pump\"]=[\"source\"].\n" - "If [\"dest\"] specified, send undecorated events on [\"source\"] to the\n" - "LLEventPump named [\"dest\"].\n" - "Returns [\"status\"] boolean indicating whether the connection was made.", +R"-(Listen to an existing LLEventPump named ["source"], with listener name +["listener"]. +If ["tweak"] is specified as true, tweak listener name for uniqueness. +By default, send events on ["source"] to the plugin, decorated +with ["pump"]=["source"]. +If ["dest"] specified, send undecorated events on ["source"] to the +LLEventPump named ["dest"]. +Returns ["status"] boolean indicating whether the connection was made, +plus ["listener"] reporting (possibly tweaked) listener name.)-", &LLLeapListener::listen, need_source_listener); add("stoplistening", - "Disconnect a connection previously established by \"listen\".\n" - "Pass same [\"source\"] and [\"listener\"] arguments.\n" - "Returns [\"status\"] boolean indicating whether such a listener existed.", +R"-(Disconnect a connection previously established by "listen". +Pass same ["source"] and ["listener"] arguments. +Returns ["status"] boolean indicating whether such a listener existed.)-", &LLLeapListener::stoplistening, need_source_listener); add("ping", - "No arguments, just a round-trip sanity check.", +"No arguments, just a round-trip sanity check.", &LLLeapListener::ping); add("getAPIs", - "Enumerate all LLEventAPI instances by name and description.", +"Enumerate all LLEventAPI instances by name and description.", &LLLeapListener::getAPIs); add("getAPI", - "Get name, description, dispatch key and operations for LLEventAPI [\"api\"].", +R"-(Get name, description, dispatch key and operations for LLEventAPI ["api"].)-", &LLLeapListener::getAPI, LLSD().with("api", LLSD())); add("getFeatures", - "Return an LLSD map of feature strings (deltas from baseline LEAP protocol)", +"Return an LLSD map of feature strings (deltas from baseline LEAP protocol)", static_cast<void (LLLeapListener::*)(const LLSD&) const>(&LLLeapListener::getFeatures)); add("getFeature", - "Return the feature value with key [\"feature\"]", +R"-(Return the feature value with key ["feature"])-", &LLLeapListener::getFeature, LLSD().with("feature", LLSD())); } @@ -112,6 +121,7 @@ LLLeapListener::~LLLeapListener() // value_type, and Bad Things would happen if you copied an // LLTempBoundListener. (Destruction of the original would disconnect the // listener, invalidating every stored connection.) + LL_DEBUGS("LLLeapListener") << "~LLLeapListener(\"" << mCaller << "\")" << LL_ENDL; for (ListenersMap::value_type& pair : mListeners) { pair.second.disconnect(); @@ -133,8 +143,7 @@ void LLLeapListener::newpump(const LLSD& request) reply["name"] = name; // Now listen on this new pump with our plugin listener - std::string myname("llleap"); - saveListener(name, myname, mConnect(new_pump, myname)); + saveListener(name, mCaller, connect(new_pump, mCaller)); } catch (const LLEventPumps::BadType& error) { @@ -149,6 +158,11 @@ void LLLeapListener::listen(const LLSD& request) std::string source_name = request["source"]; std::string dest_name = request["dest"]; std::string listener_name = request["listener"]; + if (request["tweak"].asBoolean()) + { + listener_name = LLEventPump::inventName(listener_name); + } + reply["listener"] = listener_name; LLEventPump & source = LLEventPumps::instance().obtain(source_name); @@ -170,7 +184,7 @@ void LLLeapListener::listen(const LLSD& request) { // "dest" unspecified means to direct events on "source" // to our plugin listener. - saveListener(source_name, listener_name, mConnect(source, listener_name)); + saveListener(source_name, listener_name, connect(source, listener_name)); } reply["status"] = true; } @@ -292,10 +306,27 @@ void LLLeapListener::getFeature(const LLSD& request) const } } +LLBoundListener LLLeapListener::connect(LLEventPump& pump, const std::string& listener) +{ + // Connect to source pump with an adapter that calls our callback with the + // pump name as well as the event data. + return pump.listen( + listener, + [callback=mCallback, pump=pump.getName()] + (const LLSD& data) + { return callback(pump, data); }); +} + void LLLeapListener::saveListener(const std::string& pump_name, const std::string& listener_name, const LLBoundListener& listener) { - mListeners.insert(ListenersMap::value_type(ListenersMap::key_type(pump_name, listener_name), - listener)); + // Don't use insert() or emplace() because, if this (pump_name, + // listener_name) pair is already in mListeners, we *want* to overwrite it. + auto& listener_entry{ mListeners[ListenersMap::key_type(pump_name, listener_name)] }; + // If we already stored a connection for this pump and listener name, + // disconnect it before overwriting it. But if this entry was newly + // created, disconnect() will be a no-op. + listener_entry.disconnect(); + listener_entry = listener; } diff --git a/indra/llcommon/llleaplistener.h b/indra/llcommon/llleaplistener.h index cad4543d02..040fb737b7 100644 --- a/indra/llcommon/llleaplistener.h +++ b/indra/llcommon/llleaplistener.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-03-16 * @brief LLEventAPI supporting LEAP plugins - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ @@ -13,10 +13,9 @@ #define LL_LLLEAPLISTENER_H #include "lleventapi.h" +#include <functional> #include <map> #include <string> -#include <boost/function.hpp> -#include <boost/ptr_container/ptr_map.hpp> /// Listener class implementing LLLeap query/control operations. /// See https://jira.lindenlab.com/jira/browse/DEV-31978. @@ -24,18 +23,16 @@ class LLLeapListener: public LLEventAPI { public: /** - * Decouple LLLeap by dependency injection. Certain LLLeapListener - * operations must be able to cause LLLeap to listen on a specified - * LLEventPump with the LLLeap listener that wraps incoming events in an - * outer (pump=, data=) map and forwards them to the plugin. Very well, - * define the signature for a function that will perform that, and make - * our constructor accept such a function. + * Certain LLLeapListener operations listen on a specified LLEventPump. + * Accept a bool(pump, data) callback from our caller for when any such + * event is received. */ - typedef boost::function<LLBoundListener(LLEventPump&, const std::string& listener)> - ConnectFunc; - LLLeapListener(const ConnectFunc& connect); + using Callback = std::function<bool(const std::string& pump, const LLSD& data)>; + LLLeapListener(const std::string_view& caller, const Callback& callback); ~LLLeapListener(); + LLEventPump& getReplyPump() { return mReplyPump; } + static LLSD getFeatures(); private: @@ -48,10 +45,16 @@ private: void getFeatures(const LLSD&) const; void getFeature(const LLSD&) const; + LLBoundListener connect(LLEventPump& pump, const std::string& listener); void saveListener(const std::string& pump_name, const std::string& listener_name, const LLBoundListener& listener); - ConnectFunc mConnect; + // The relative order of these next declarations is important because the + // constructor will initialize in this order. + std::string mCaller; + Callback mCallback; + LLEventStream mReplyPump; + LLTempBoundListener mReplyConn; // In theory, listen() could simply call the relevant LLEventPump's // listen() method, stoplistening() likewise. Lifespan issues make us diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 33c9e956b1..5789b5de2c 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -1,25 +1,25 @@ -/** +/** * @file llrefcount.h * @brief Base class for reference counted objects for use with LLPointer * * $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,6 +29,7 @@ #include <boost/noncopyable.hpp> #include <boost/intrusive_ptr.hpp> #include "llatomic.h" +#include "llerror.h" class LLMutex; @@ -44,42 +45,42 @@ extern const S32 gMaxRefCount; class LL_COMMON_API LLRefCount { protected: - LLRefCount(const LLRefCount& other); - LLRefCount& operator=(const LLRefCount&); - virtual ~LLRefCount(); // use unref() - + LLRefCount(const LLRefCount& other); + LLRefCount& operator=(const LLRefCount&); + virtual ~LLRefCount(); // use unref() + public: - LLRefCount(); - - inline void ref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - mRef++; - llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak - } - - inline S32 unref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - llassert(mRef > 0); // ref count below 1, likely corrupted - if (0 == --mRef) - { - mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging - delete this; - return 0; - } - return mRef; - } - - //NOTE: when passing around a const LLRefCount object, this can return different results - // at different types, since mRef is mutable - S32 getNumRefs() const - { - return mRef; - } + LLRefCount(); + + inline void ref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + mRef++; + llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak + } + + inline S32 unref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + llassert(mRef > 0); // ref count below 1, likely corrupted + if (0 == --mRef) + { + mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging + delete this; + return 0; + } + return mRef; + } + + //NOTE: when passing around a const LLRefCount object, this can return different results + // at different types, since mRef is mutable + S32 getNumRefs() const + { + return mRef; + } private: - mutable S32 mRef; + mutable S32 mRef; }; @@ -90,50 +91,50 @@ private: class LL_COMMON_API LLThreadSafeRefCount { public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex + static void initThreadSafeRefCount(); // creates sMutex + static void cleanupThreadSafeRefCount(); // destroys sMutex private: - static LLMutex* sMutex; + static LLMutex* sMutex; protected: - virtual ~LLThreadSafeRefCount(); // use unref() + virtual ~LLThreadSafeRefCount(); // use unref() public: - LLThreadSafeRefCount(); - LLThreadSafeRefCount(const LLThreadSafeRefCount&); - LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) - { - mRef = 0; - return *this; - } - - void ref() - { - mRef++; - } - - void unref() - { - llassert(mRef >= 1); - if ((--mRef) == 0) - { - // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. - // It is technically possible for a vanilla pointer to mess this up, or another thread to - // jump in, find this object, create another smart pointer and end up dangling, but if - // the code is that bad and not thread-safe, it's trouble already. - delete this; - } - } - - S32 getNumRefs() const - { - const S32 currentVal = mRef.CurrentValue(); - return currentVal; - } + LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + { + mRef = 0; + return *this; + } + + void ref() + { + mRef++; + } + + void unref() + { + llassert(mRef >= 1); + if ((--mRef) == 0) + { + // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. + // It is technically possible for a vanilla pointer to mess this up, or another thread to + // jump in, find this object, create another smart pointer and end up dangling, but if + // the code is that bad and not thread-safe, it's trouble already. + delete this; + } + } + + S32 getNumRefs() const + { + const S32 currentVal = mRef.CurrentValue(); + return currentVal; + } private: - LLAtomicS32 mRef; + LLAtomicS32 mRef; }; /** @@ -142,12 +143,12 @@ private: */ inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLThreadSafeRefCount* p) { - p->unref(); + p->unref(); } /** @@ -156,12 +157,12 @@ inline void intrusive_ptr_release(LLThreadSafeRefCount* p) */ inline void intrusive_ptr_add_ref(LLRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLRefCount* p) { - p->unref(); + p->unref(); } #endif diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 3829978ddf..9478dff871 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,25 +1,25 @@ -/** +/** * @file llstring.h * @brief String utility functions and std::string class. * * $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,7 +37,9 @@ #include <algorithm> #include <vector> #include <map> +#include <type_traits> #include "llformat.h" +#include "stdtypes.h" #if LL_LINUX #include <wctype.h> @@ -59,85 +61,85 @@ namespace std template<> struct char_traits<U16> { - typedef U16 char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - typedef mbstate_t state_type; - - static void - assign(char_type& __c1, const char_type& __c2) - { __c1 = __c2; } - - static bool - eq(const char_type& __c1, const char_type& __c2) - { return __c1 == __c2; } - - static bool - lt(const char_type& __c1, const char_type& __c2) - { return __c1 < __c2; } - - static int - compare(const char_type* __s1, const char_type* __s2, size_t __n) - { return memcmp(__s1, __s2, __n * sizeof(char_type)); } - - static size_t - length(const char_type* __s) - { - const char_type *cur_char = __s; - while (*cur_char != 0) - { - ++cur_char; - } - return cur_char - __s; - } - - static const char_type* - find(const char_type* __s, size_t __n, const char_type& __a) - { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } - - static char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } - - static char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ - - static char_type* - assign(char_type* __s, size_t __n, char_type __a) - { - // This isn't right. - //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); - - // I don't think there's a standard 'memset' for 16-bit values. - // Do this the old-fashioned way. - - size_t __i; - for(__i = 0; __i < __n; __i++) - { - __s[__i] = __a; - } - return __s; - } - - static char_type - to_char_type(const int_type& __c) - { return static_cast<char_type>(__c); } - - static int_type - to_int_type(const char_type& __c) - { return static_cast<int_type>(__c); } - - static bool - eq_int_type(const int_type& __c1, const int_type& __c2) - { return __c1 == __c2; } - - static int_type - eof() { return static_cast<int_type>(EOF); } - - static int_type - not_eof(const int_type& __c) + typedef U16 char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + typedef mbstate_t state_type; + + static void + assign(char_type& __c1, const char_type& __c2) + { __c1 = __c2; } + + static bool + eq(const char_type& __c1, const char_type& __c2) + { return __c1 == __c2; } + + static bool + lt(const char_type& __c1, const char_type& __c2) + { return __c1 < __c2; } + + static int + compare(const char_type* __s1, const char_type* __s2, size_t __n) + { return memcmp(__s1, __s2, __n * sizeof(char_type)); } + + static size_t + length(const char_type* __s) + { + const char_type *cur_char = __s; + while (*cur_char != 0) + { + ++cur_char; + } + return cur_char - __s; + } + + static const char_type* + find(const char_type* __s, size_t __n, const char_type& __a) + { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } + + static char_type* + move(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } + + static char_type* + copy(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ + + static char_type* + assign(char_type* __s, size_t __n, char_type __a) + { + // This isn't right. + //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); + + // I don't think there's a standard 'memset' for 16-bit values. + // Do this the old-fashioned way. + + size_t __i; + for(__i = 0; __i < __n; __i++) + { + __s[__i] = __a; + } + return __s; + } + + static char_type + to_char_type(const int_type& __c) + { return static_cast<char_type>(__c); } + + static int_type + to_int_type(const char_type& __c) + { return static_cast<int_type>(__c); } + + static bool + eq_int_type(const int_type& __c1, const int_type& __c2) + { return __c1 == __c2; } + + static int_type + eof() { return static_cast<int_type>(EOF); } + + static int_type + not_eof(const int_type& __c) { return (__c == eof()) ? 0 : __c; } }; }; @@ -146,72 +148,72 @@ struct char_traits<U16> class LL_COMMON_API LLStringOps { private: - static long sPacificTimeOffset; - static long sLocalTimeOffset; - static bool sPacificDaylightTime; + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; - static std::map<std::string, std::string> datetimeToCodes; + static std::map<std::string, std::string> datetimeToCodes; public: - static std::vector<std::string> sWeekDayList; - static std::vector<std::string> sWeekDayShortList; - static std::vector<std::string> sMonthList; - static std::vector<std::string> sMonthShortList; - static std::string sDayFormat; - - static std::string sAM; - static std::string sPM; + static std::vector<std::string> sWeekDayList; + static std::vector<std::string> sWeekDayShortList; + static std::vector<std::string> sMonthList; + static std::vector<std::string> sMonthShortList; + static std::string sDayFormat; - static char toUpper(char elem) { return toupper((unsigned char)elem); } - static llwchar toUpper(llwchar elem) { return towupper(elem); } + static std::string sAM; + static std::string sPM; - static char toLower(char elem) { return tolower((unsigned char)elem); } - static llwchar toLower(llwchar elem) { return towlower(elem); } + static char toUpper(char elem) { return toupper((unsigned char)elem); } + static llwchar toUpper(llwchar elem) { return towupper(elem); } + + static char toLower(char elem) { return tolower((unsigned char)elem); } + static llwchar toLower(llwchar elem) { return towlower(elem); } - static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } - static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } - static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } - static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } - static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } - static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } - static bool isDigit(llwchar a) { return iswdigit(a) != 0; } + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(a) != 0; } - static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } - static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } + static bool isPunct(llwchar a) { return iswpunct(a) != 0; } - static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } - static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } - static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } - static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } + static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - static bool isEmoji(llwchar wch); + static bool isEmoji(llwchar wch); - static S32 collate(const char* a, const char* b) { return strcoll(a, b); } - static S32 collate(const llwchar* a, const llwchar* b); + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } + static S32 collate(const llwchar* a, const llwchar* b); - static void setupDatetimeInfo(bool pacific_daylight_time); + static void setupDatetimeInfo(bool pacific_daylight_time); - static void setupWeekDaysNames(const std::string& data); - static void setupWeekDaysShortNames(const std::string& data); - static void setupMonthNames(const std::string& data); - static void setupMonthShortNames(const std::string& data); - static void setupDayFormat(const std::string& data); + static void setupWeekDaysNames(const std::string& data); + static void setupWeekDaysShortNames(const std::string& data); + static void setupMonthNames(const std::string& data); + static void setupMonthShortNames(const std::string& data); + static void setupDayFormat(const std::string& data); - static long getPacificTimeOffset(void) { return sPacificTimeOffset;} - static long getLocalTimeOffset(void) { return sLocalTimeOffset;} - // Is the Pacific time zone (aka server time zone) - // currently in daylight savings time? - static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} + static long getPacificTimeOffset(void) { return sPacificTimeOffset;} + static long getLocalTimeOffset(void) { return sLocalTimeOffset;} + // Is the Pacific time zone (aka server time zone) + // currently in daylight savings time? + static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - static std::string getDatetimeCode (std::string key); + static std::string getDatetimeCode (std::string key); - // Express a value like 1234567 as "1.23M" + // Express a value like 1234567 as "1.23M" static std::string getReadableNumber(F64 num); }; @@ -228,216 +230,216 @@ LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); class LLFormatMapString { public: - LLFormatMapString() {}; - LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; - LLFormatMapString(const std::string& s) : mString(s) {}; - operator std::string() const { return mString; } - bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } - std::size_t length() const { return mString.length(); } - + LLFormatMapString() {}; + LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; + LLFormatMapString(const std::string& s) : mString(s) {}; + operator std::string() const { return mString; } + bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } + std::size_t length() const { return mString.length(); } + private: - std::string mString; + std::string mString; }; template <class T> class LLStringUtilBase { private: - static std::string sLocale; + static std::string sLocale; public: - typedef std::basic_string<T> string_type; - typedef typename string_type::size_type size_type; - + typedef std::basic_string<T> string_type; + typedef typename string_type::size_type size_type; + public: - ///////////////////////////////////////////////////////////////////////////////////////// - // Static Utility functions that operate on std::strings - - static const string_type null; - - typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; - /// considers any sequence of delims as a single field separator - LL_COMMON_API static void getTokens(const string_type& instr, - std::vector<string_type >& tokens, - const string_type& delims); - /// like simple scan overload, but returns scanned vector - static std::vector<string_type> getTokens(const string_type& instr, - const string_type& delims); - /// add support for keep_delims and quotes (either could be empty string) - static void getTokens(const string_type& instr, - std::vector<string_type>& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// like keep_delims-and-quotes overload, but returns scanned vector - static std::vector<string_type> getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// add support for escapes (could be empty string) - static void getTokens(const string_type& instr, - std::vector<string_type>& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - /// like escapes overload, but returns scanned vector - static std::vector<string_type> getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - - LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); - LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); - LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); - LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); - LL_COMMON_API static void setLocale (std::string inLocale); - LL_COMMON_API static std::string getLocale (void); - - static bool isValidIndex(const string_type& string, size_type i) - { - return !string.empty() && (0 <= i) && (i <= string.size()); - } - - static bool contains(const string_type& string, T c, size_type i=0) - { - return string.find(c, i) != string_type::npos; - } - - static void trimHead(string_type& string); - static void trimTail(string_type& string); - static void trim(string_type& string) { trimHead(string); trimTail(string); } - static void truncate(string_type& string, size_type count); - - static void toUpper(string_type& string); - static void toLower(string_type& string); - - // True if this is the head of s. - static BOOL isHead( const string_type& string, const T* s ); - - /** - * @brief Returns true if string starts with substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool startsWith( - const string_type& string, - const string_type& substr); - - /** - * @brief Returns true if string ends in substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool endsWith( - const string_type& string, - const string_type& substr); - - /** - * get environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by return value == dflt - */ - static string_type getenv(const std::string& key, const string_type& dflt=""); - /** - * get optional environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by (! return value) - */ - static boost::optional<string_type> getoptenv(const std::string& key); - - static void addCRLF(string_type& string); - static void removeCRLF(string_type& string); - static void removeWindowsCR(string_type& string); - - static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); - static void replaceNonstandardASCII( string_type& string, T replacement ); - static void replaceChar( string_type& string, T target, T replacement ); - static void replaceString( string_type& string, string_type target, string_type replacement ); - static string_type capitalize(const string_type& str); - static void capitalize(string_type& str); - - static BOOL containsNonprintable(const string_type& string); - static void stripNonprintable(string_type& string); - - /** - * Double-quote an argument string if needed, unless it's already - * double-quoted. Decide whether it's needed based on the presence of any - * character in @a triggers (default space or double-quote). If we quote - * it, escape any embedded double-quote with the @a escape string (default - * backslash). - * - * Passing triggers="" means always quote, unless it's already double-quoted. - */ - static string_type quote(const string_type& str, - const string_type& triggers=" \"", - const string_type& escape="\\"); - - /** - * @brief Unsafe way to make ascii characters. You should probably - * only call this when interacting with the host operating system. - * The 1 byte std::string does not work correctly. - * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII - * should work. - */ - static void _makeASCII(string_type& string); - - // Conversion to other data types - static BOOL convertToBOOL(const string_type& string, BOOL& value); - static BOOL convertToU8(const string_type& string, U8& value); - static BOOL convertToS8(const string_type& string, S8& value); - static BOOL convertToS16(const string_type& string, S16& value); - static BOOL convertToU16(const string_type& string, U16& value); - static BOOL convertToU32(const string_type& string, U32& value); - static BOOL convertToS32(const string_type& string, S32& value); - static BOOL convertToF32(const string_type& string, F32& value); - static BOOL convertToF64(const string_type& string, F64& value); - - ///////////////////////////////////////////////////////////////////////////////////////// - // Utility functions for working with char*'s and strings - - // Like strcmp but also handles empty strings. Uses - // current locale. - static S32 compareStrings(const T* lhs, const T* rhs); - static S32 compareStrings(const string_type& lhs, const string_type& rhs); - - // case insensitive version of above. Uses current locale on - // Win32, and falls back to a non-locale aware comparison on - // Linux. - static S32 compareInsensitive(const T* lhs, const T* rhs); - static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); - - // Case sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDict(const string_type& a, const string_type& b); - - // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDictInsensitive(const string_type& a, const string_type& b); - - // Puts compareDict() in a form appropriate for LL container classes to use for sorting. - static BOOL precedesDict( const string_type& a, const string_type& b ); - - // A replacement for strncpy. - // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds - // up to dst_size-1 characters of src. - static void copy(T* dst, const T* src, size_type dst_size); - - // Copies src into dst at a given offset. - static void copyInto(string_type& dst, const string_type& src, size_type offset); - - static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } - - -#ifdef _DEBUG - LL_COMMON_API static void testHarness(); + ///////////////////////////////////////////////////////////////////////////////////////// + // Static Utility functions that operate on std::strings + + static const string_type null; + + typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; + /// considers any sequence of delims as a single field separator + LL_COMMON_API static void getTokens(const string_type& instr, + std::vector<string_type >& tokens, + const string_type& delims); + /// like simple scan overload, but returns scanned vector + static std::vector<string_type> getTokens(const string_type& instr, + const string_type& delims); + /// add support for keep_delims and quotes (either could be empty string) + static void getTokens(const string_type& instr, + std::vector<string_type>& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// like keep_delims-and-quotes overload, but returns scanned vector + static std::vector<string_type> getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// add support for escapes (could be empty string) + static void getTokens(const string_type& instr, + std::vector<string_type>& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + /// like escapes overload, but returns scanned vector + static std::vector<string_type> getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + + LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); + LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); + LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); + LL_COMMON_API static void setLocale (std::string inLocale); + LL_COMMON_API static std::string getLocale (void); + + static bool isValidIndex(const string_type& string, size_type i) + { + return !string.empty() && (0 <= i) && (i <= string.size()); + } + + static bool contains(const string_type& string, T c, size_type i=0) + { + return string.find(c, i) != string_type::npos; + } + + static void trimHead(string_type& string); + static void trimTail(string_type& string); + static void trim(string_type& string) { trimHead(string); trimTail(string); } + static void truncate(string_type& string, size_type count); + + static void toUpper(string_type& string); + static void toLower(string_type& string); + + // True if this is the head of s. + static BOOL isHead( const string_type& string, const T* s ); + + /** + * @brief Returns true if string starts with substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool startsWith( + const string_type& string, + const string_type& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const string_type& string, + const string_type& substr); + + /** + * get environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by return value == dflt + */ + static string_type getenv(const std::string& key, const string_type& dflt=""); + /** + * get optional environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by (! return value) + */ + static boost::optional<string_type> getoptenv(const std::string& key); + + static void addCRLF(string_type& string); + static void removeCRLF(string_type& string); + static void removeWindowsCR(string_type& string); + + static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); + static void replaceNonstandardASCII( string_type& string, T replacement ); + static void replaceChar( string_type& string, T target, T replacement ); + static void replaceString( string_type& string, string_type target, string_type replacement ); + static string_type capitalize(const string_type& str); + static void capitalize(string_type& str); + + static BOOL containsNonprintable(const string_type& string); + static void stripNonprintable(string_type& string); + + /** + * Double-quote an argument string if needed, unless it's already + * double-quoted. Decide whether it's needed based on the presence of any + * character in @a triggers (default space or double-quote). If we quote + * it, escape any embedded double-quote with the @a escape string (default + * backslash). + * + * Passing triggers="" means always quote, unless it's already double-quoted. + */ + static string_type quote(const string_type& str, + const string_type& triggers=" \"", + const string_type& escape="\\"); + + /** + * @brief Unsafe way to make ascii characters. You should probably + * only call this when interacting with the host operating system. + * The 1 byte std::string does not work correctly. + * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII + * should work. + */ + static void _makeASCII(string_type& string); + + // Conversion to other data types + static BOOL convertToBOOL(const string_type& string, BOOL& value); + static BOOL convertToU8(const string_type& string, U8& value); + static BOOL convertToS8(const string_type& string, S8& value); + static BOOL convertToS16(const string_type& string, S16& value); + static BOOL convertToU16(const string_type& string, U16& value); + static BOOL convertToU32(const string_type& string, U32& value); + static BOOL convertToS32(const string_type& string, S32& value); + static BOOL convertToF32(const string_type& string, F32& value); + static BOOL convertToF64(const string_type& string, F64& value); + + ///////////////////////////////////////////////////////////////////////////////////////// + // Utility functions for working with char*'s and strings + + // Like strcmp but also handles empty strings. Uses + // current locale. + static S32 compareStrings(const T* lhs, const T* rhs); + static S32 compareStrings(const string_type& lhs, const string_type& rhs); + + // case insensitive version of above. Uses current locale on + // Win32, and falls back to a non-locale aware comparison on + // Linux. + static S32 compareInsensitive(const T* lhs, const T* rhs); + static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); + + // Case sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDict(const string_type& a, const string_type& b); + + // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDictInsensitive(const string_type& a, const string_type& b); + + // Puts compareDict() in a form appropriate for LL container classes to use for sorting. + static BOOL precedesDict( const string_type& a, const string_type& b ); + + // A replacement for strncpy. + // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds + // up to dst_size-1 characters of src. + static void copy(T* dst, const T* src, size_type dst_size); + + // Copies src into dst at a given offset. + static void copyInto(string_type& dst, const string_type& src, size_type offset); + + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + +#ifdef _DEBUG + LL_COMMON_API static void testHarness(); #endif private: - LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector<string_type >& tokens); + LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector<string_type >& tokens); }; template<class T> const std::basic_string<T> LLStringUtilBase<T>::null; @@ -453,18 +455,18 @@ typedef std::basic_string<llwchar> LLWString; class LLStringExplicit : public std::string { public: - explicit LLStringExplicit(const char* s) : std::string(s) {} - LLStringExplicit(const std::string& s) : std::string(s) {} - LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} + explicit LLStringExplicit(const char* s) : std::string(s) {} + LLStringExplicit(const std::string& s) : std::string(s) {} + LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} }; struct LLDictionaryLess { public: - bool operator()(const std::string& a, const std::string& b) const - { - return (LLStringUtil::precedesDict(a, b) ? true : false); - } + bool operator()(const std::string& a, const std::string& b) const + { + return (LLStringUtil::precedesDict(a, b) ? true : false); + } }; @@ -481,10 +483,10 @@ public: * @return a copy of in string minus the trailing count bytes. */ inline std::string chop_tail_copy( - const std::string& in, - std::string::size_type count) + const std::string& in, + std::string::size_type count) { - return std::string(in, 0, in.length() - count); + return std::string(in, 0, in.length() - count); } /** @@ -519,11 +521,38 @@ struct ll_convert_impl TO operator()(const FROM& in) const; }; -// Use a function template to get the nice ll_convert<TO>(from_value) API. +/** + * somefunction(ll_convert(data)) + * target = ll_convert(data) + * totype otherfunc(const fromtype& data) + * { + * // ... + * return ll_convert(data); + * } + * all infer both the FROM type and the TO type. + */ +template <typename FROM> +class ll_convert +{ +private: + const FROM& mRef; + +public: + ll_convert(const FROM& ref): mRef(ref) {} + + template <typename TO> + inline operator TO() const + { + return ll_convert_impl<TO, std::decay_t<const FROM>>()(mRef); + } +}; + +// When the TO type must be explicit, use a function template to get +// ll_convert_to<TO>(from_value) API. template<typename TO, typename FROM> -TO ll_convert(const FROM& in) +TO ll_convert_to(const FROM& in) { - return ll_convert_impl<TO, FROM>()(in); + return ll_convert_impl<TO, std::decay_t<const FROM>>()(in); } // degenerate case @@ -577,8 +606,8 @@ inline size_t ll_convert_length<char> (const char* zstr) { return std::strl // and longname(const string&, len) so calls written pre-ll_convert() will // work. Most of these overloads will be unified once we turn on C++17 and can // use std::string_view. -// It also uses aliasmacro to ensure that both ll_convert<OUTSTR>(const char*) -// and ll_convert<OUTSTR>(const string&) will work. +// It also uses aliasmacro to ensure that both ll_convert(const char*) +// and ll_convert(const string&) will work. #define ll_convert_forms(aliasmacro, OUTSTR, INSTR, longname) \ LL_COMMON_API OUTSTR longname(const INSTR::value_type* in, size_t len); \ inline auto longname(const INSTR& in, size_t len) \ @@ -677,10 +706,10 @@ ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_u inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} // Length of this UTF32 string in bytes when transformed to UTF8 -LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); // Length in bytes of this wide char in a UTF8 string -LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); LL_COMMON_API std::string wchar_utf8_preview(const llwchar wc); @@ -697,7 +726,7 @@ LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wst /** * @brief Properly truncate a utf8 string to a maximum byte count. - * + * * The returned string may be less than max_len if the truncation * happens in the middle of a glyph. If max_len is longer than the * string passed in, the return value == utf8str. @@ -710,8 +739,8 @@ LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); LL_COMMON_API S32 utf8str_compare_insensitive( - const std::string& lhs, - const std::string& rhs); + const std::string& lhs, + const std::string& rhs); /** * @brief Properly truncate a utf8 string to a maximum character count. @@ -732,14 +761,14 @@ LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, co * @param replace_char The wchar which is written on replace */ LL_COMMON_API std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char); + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char); LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); // Hack - used for evil notecards. -LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); @@ -815,7 +844,7 @@ LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in template<typename STRING> STRING windows_message(unsigned long error) { - return ll_convert<STRING>(windows_message<std::wstring>(error)); + return ll_convert(windows_message<std::wstring>(error)); } /// There's only one real implementation @@ -845,52 +874,52 @@ LL_COMMON_API boost::optional<std::string> llstring_getoptenv(const std::string */ namespace LLStringFn { - /** - * @brief Replace all non-printable characters with replacement in - * string. - * NOTE - this will zap non-ascii - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_in_ascii( - std::basic_string<char>& string, - char replacement); - - - /** - * @brief Replace all non-printable characters and pipe characters - * with replacement in a string. - * NOTE - this will zap non-ascii - * - * @param [in,out] the string to modify. out value is the string - * with zero non-printable characters and zero pipe characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, - char replacement); - - - /** - * @brief Remove all characters that are not allowed in XML 1.0. - * Returns a copy of the string with those characters removed. - * Works with US ASCII and UTF-8 encoded strings. JC - */ - LL_COMMON_API std::string strip_invalid_xml(const std::string& input); - - - /** - * @brief Replace all control characters (0 <= c < 0x20) with replacement in - * string. This is safe for utf-8 - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_ascii_controlchars( - std::basic_string<char>& string, - char replacement); + /** + * @brief Replace all non-printable characters with replacement in + * string. + * NOTE - this will zap non-ascii + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_in_ascii( + std::basic_string<char>& string, + char replacement); + + + /** + * @brief Replace all non-printable characters and pipe characters + * with replacement in a string. + * NOTE - this will zap non-ascii + * + * @param [in,out] the string to modify. out value is the string + * with zero non-printable characters and zero pipe characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, + char replacement); + + + /** + * @brief Remove all characters that are not allowed in XML 1.0. + * Returns a copy of the string with those characters removed. + * Works with US ASCII and UTF-8 encoded strings. JC + */ + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + + /** + * @brief Replace all control characters (0 <= c < 0x20) with replacement in + * string. This is safe for utf-8 + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_ascii_controlchars( + std::basic_string<char>& string, + char replacement); } //////////////////////////////////////////////////////////// @@ -905,36 +934,36 @@ template <class T> std::vector<typename LLStringUtilBase<T>::string_type> LLStringUtilBase<T>::getTokens(const string_type& instr, const string_type& delims) { - std::vector<string_type> tokens; - getTokens(instr, tokens, delims); - return tokens; + std::vector<string_type> tokens; + getTokens(instr, tokens, delims); + return tokens; } // static template <class T> std::vector<typename LLStringUtilBase<T>::string_type> LLStringUtilBase<T>::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes) { - std::vector<string_type> tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes); - return tokens; + std::vector<string_type> tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes); + return tokens; } // static template <class T> std::vector<typename LLStringUtilBase<T>::string_type> LLStringUtilBase<T>::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes) -{ - std::vector<string_type> tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); - return tokens; + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes) +{ + std::vector<string_type> tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); + return tokens; } namespace LLStringUtilBaseImpl @@ -950,62 +979,62 @@ namespace LLStringUtilBaseImpl template <class T> struct InString { - typedef std::basic_string<T> string_type; - typedef typename string_type::const_iterator const_iterator; - - InString(const_iterator b, const_iterator e): - mIter(b), - mEnd(e) - {} - virtual ~InString() {} - - bool done() const { return mIter == mEnd; } - /// Is the current character (*mIter) escaped? This implementation can - /// answer trivially because it doesn't support escapes. - virtual bool escaped() const { return false; } - /// Obtain the current character and advance @c mIter. - virtual T next() { return *mIter++; } - /// Does the current character match specified character? - virtual bool is(T ch) const { return (! done()) && *mIter == ch; } - /// Is the current character any one of the specified characters? - virtual bool oneof(const string_type& delims) const - { - return (! done()) && LLStringUtilBase<T>::contains(delims, *mIter); - } - - /** - * Scan forward from @from until either @a delim or end. This is primarily - * useful for processing quoted substrings. - * - * If we do see @a delim, append everything from @from until (excluding) - * @a delim to @a into, advance @c mIter to skip @a delim, and return @c - * true. - * - * If we do not see @a delim, do not alter @a into or @c mIter and return - * @c false. Do not pass GO, do not collect $200. - * - * @note The @c false case described above implements normal getTokens() - * treatment of an unmatched open quote: treat the quote character as if - * escaped, that is, simply collect it as part of the current token. Other - * plausible behaviors directly affect the way getTokens() deals with an - * unmatched quote: e.g. throwing an exception to treat it as an error, or - * assuming a close quote beyond end of string (in which case return @c - * true). - */ - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - const_iterator found = std::find(from, mEnd, delim); - // If we didn't find delim, change nothing, just tell caller. - if (found == mEnd) - return false; - // Found delim! Append everything between from and found. - into.append(from, found); - // advance past delim in input - mIter = found + 1; - return true; - } - - const_iterator mIter, mEnd; + typedef std::basic_string<T> string_type; + typedef typename string_type::const_iterator const_iterator; + + InString(const_iterator b, const_iterator e): + mIter(b), + mEnd(e) + {} + virtual ~InString() {} + + bool done() const { return mIter == mEnd; } + /// Is the current character (*mIter) escaped? This implementation can + /// answer trivially because it doesn't support escapes. + virtual bool escaped() const { return false; } + /// Obtain the current character and advance @c mIter. + virtual T next() { return *mIter++; } + /// Does the current character match specified character? + virtual bool is(T ch) const { return (! done()) && *mIter == ch; } + /// Is the current character any one of the specified characters? + virtual bool oneof(const string_type& delims) const + { + return (! done()) && LLStringUtilBase<T>::contains(delims, *mIter); + } + + /** + * Scan forward from @from until either @a delim or end. This is primarily + * useful for processing quoted substrings. + * + * If we do see @a delim, append everything from @from until (excluding) + * @a delim to @a into, advance @c mIter to skip @a delim, and return @c + * true. + * + * If we do not see @a delim, do not alter @a into or @c mIter and return + * @c false. Do not pass GO, do not collect $200. + * + * @note The @c false case described above implements normal getTokens() + * treatment of an unmatched open quote: treat the quote character as if + * escaped, that is, simply collect it as part of the current token. Other + * plausible behaviors directly affect the way getTokens() deals with an + * unmatched quote: e.g. throwing an exception to treat it as an error, or + * assuming a close quote beyond end of string (in which case return @c + * true). + */ + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + const_iterator found = std::find(from, mEnd, delim); + // If we didn't find delim, change nothing, just tell caller. + if (found == mEnd) + return false; + // Found delim! Append everything between from and found. + into.append(from, found); + // advance past delim in input + mIter = found + 1; + return true; + } + + const_iterator mIter, mEnd; }; /// InString subclass that handles escape characters @@ -1013,177 +1042,177 @@ template <class T> class InEscString: public InString<T> { public: - typedef InString<T> super; - typedef typename super::string_type string_type; - typedef typename super::const_iterator const_iterator; - using super::done; - using super::mIter; - using super::mEnd; - - InEscString(const_iterator b, const_iterator e, const string_type& escapes): - super(b, e), - mEscapes(escapes) - { - // Even though we've already initialized 'mIter' via our base-class - // constructor, set it again to check for initial escape char. - setiter(b); - } - - /// This implementation uses the answer cached by setiter(). - virtual bool escaped() const { return mIsEsc; } - virtual T next() - { - // If we're looking at the escape character of an escape sequence, - // skip that character. This is the one time we can modify 'mIter' - // without using setiter: for this one case we DO NOT CARE if the - // escaped character is itself an escape. - if (mIsEsc) - ++mIter; - // If we were looking at an escape character, this is the escaped - // character; otherwise it's just the next character. - T result(*mIter); - // Advance mIter, checking for escape sequence. - setiter(mIter + 1); - return result; - } - - virtual bool is(T ch) const - { - // Like base-class is(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && *mIter == ch; - } - - virtual bool oneof(const string_type& delims) const - { - // Like base-class oneof(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter); - } - - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - // Deal with escapes in the characters we collect; that is, an escaped - // character must become just that character without the preceding - // escape. Collect characters in a separate string rather than - // directly appending to 'into' in case we do not find delim, in which - // case we're supposed to leave 'into' unmodified. - string_type collected; - // For scanning purposes, we're going to work directly with 'mIter'. - // Save its current value in case we fail to see delim. - const_iterator save_iter(mIter); - // Okay, set 'mIter', checking for escape. - setiter(from); - while (! done()) - { - // If we see an unescaped delim, stop and report success. - if ((! mIsEsc) && *mIter == delim) - { - // Append collected chars to 'into'. - into.append(collected); - // Don't forget to advance 'mIter' past delim. - setiter(mIter + 1); - return true; - } - // We're not at end, and either we're not looking at delim or it's - // escaped. Collect this character and keep going. - collected.push_back(next()); - } - // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell - // caller. - setiter(save_iter); - return false; - } + typedef InString<T> super; + typedef typename super::string_type string_type; + typedef typename super::const_iterator const_iterator; + using super::done; + using super::mIter; + using super::mEnd; + + InEscString(const_iterator b, const_iterator e, const string_type& escapes): + super(b, e), + mEscapes(escapes) + { + // Even though we've already initialized 'mIter' via our base-class + // constructor, set it again to check for initial escape char. + setiter(b); + } + + /// This implementation uses the answer cached by setiter(). + virtual bool escaped() const { return mIsEsc; } + virtual T next() + { + // If we're looking at the escape character of an escape sequence, + // skip that character. This is the one time we can modify 'mIter' + // without using setiter: for this one case we DO NOT CARE if the + // escaped character is itself an escape. + if (mIsEsc) + ++mIter; + // If we were looking at an escape character, this is the escaped + // character; otherwise it's just the next character. + T result(*mIter); + // Advance mIter, checking for escape sequence. + setiter(mIter + 1); + return result; + } + + virtual bool is(T ch) const + { + // Like base-class is(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && *mIter == ch; + } + + virtual bool oneof(const string_type& delims) const + { + // Like base-class oneof(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter); + } + + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + // Deal with escapes in the characters we collect; that is, an escaped + // character must become just that character without the preceding + // escape. Collect characters in a separate string rather than + // directly appending to 'into' in case we do not find delim, in which + // case we're supposed to leave 'into' unmodified. + string_type collected; + // For scanning purposes, we're going to work directly with 'mIter'. + // Save its current value in case we fail to see delim. + const_iterator save_iter(mIter); + // Okay, set 'mIter', checking for escape. + setiter(from); + while (! done()) + { + // If we see an unescaped delim, stop and report success. + if ((! mIsEsc) && *mIter == delim) + { + // Append collected chars to 'into'. + into.append(collected); + // Don't forget to advance 'mIter' past delim. + setiter(mIter + 1); + return true; + } + // We're not at end, and either we're not looking at delim or it's + // escaped. Collect this character and keep going. + collected.push_back(next()); + } + // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell + // caller. + setiter(save_iter); + return false; + } private: - void setiter(const_iterator i) - { - mIter = i; - - // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively - // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches - // contains(mEscapes, *mIter). - - // We're looking at an escaped char if we're not already at end (that - // is, *mIter is even meaningful); if *mIter is in fact one of the - // specified escape characters; and if there's one more character - // following it. That is, if an escape character is the very last - // character of the input string, it loses its special meaning. - mIsEsc = (! done()) && - LLStringUtilBase<T>::contains(mEscapes, *mIter) && - (mIter+1) != mEnd; - } - - const string_type mEscapes; - bool mIsEsc; + void setiter(const_iterator i) + { + mIter = i; + + // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively + // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches + // contains(mEscapes, *mIter). + + // We're looking at an escaped char if we're not already at end (that + // is, *mIter is even meaningful); if *mIter is in fact one of the + // specified escape characters; and if there's one more character + // following it. That is, if an escape character is the very last + // character of the input string, it loses its special meaning. + mIsEsc = (! done()) && + LLStringUtilBase<T>::contains(mEscapes, *mIter) && + (mIter+1) != mEnd; + } + + const string_type mEscapes; + bool mIsEsc; }; /// getTokens() implementation based on InString concept template <typename INSTRING, typename string_type> void getTokens(INSTRING& instr, std::vector<string_type>& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) -{ - // There are times when we want to match either drop_delims or - // keep_delims. Concatenate them up front to speed things up. - string_type all_delims(drop_delims + keep_delims); - // no tokens yet - tokens.clear(); - - // try for another token - while (! instr.done()) - { - // scan past any drop_delims - while (instr.oneof(drop_delims)) - { - // skip this drop_delim - instr.next(); - // but if that was the end of the string, done - if (instr.done()) - return; - } - // found the start of another token: make a slot for it - tokens.push_back(string_type()); - if (instr.oneof(keep_delims)) - { - // *iter is a keep_delim, a token of exactly 1 character. Append - // that character to the new token and proceed. - tokens.back().push_back(instr.next()); - continue; - } - // Here we have a non-delimiter token, which might consist of a mix of - // quoted and unquoted parts. Use bash rules for quoting: you can - // embed a quoted substring in the midst of an unquoted token (e.g. - // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together - // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge - // from bash in that bash considers an unmatched quote an error. Our - // param signature doesn't allow for errors, so just pretend it's not - // a quote and embed it. - // At this level, keep scanning until we hit the next delimiter of - // either type (drop_delims or keep_delims). - while (! instr.oneof(all_delims)) - { - // If we're looking at an open quote, search forward for - // a close quote, collecting characters along the way. - if (instr.oneof(quotes) && - instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) - { - // collect_until is cleverly designed to do exactly what we - // need here. No further action needed if it returns true. - } - else - { - // Either *iter isn't a quote, or there's no matching close - // quote: in other words, just an ordinary char. Append it to - // current token. - tokens.back().push_back(instr.next()); - } - // having scanned that segment of this token, if we've reached the - // end of the string, we're done - if (instr.done()) - return; - } - } + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) +{ + // There are times when we want to match either drop_delims or + // keep_delims. Concatenate them up front to speed things up. + string_type all_delims(drop_delims + keep_delims); + // no tokens yet + tokens.clear(); + + // try for another token + while (! instr.done()) + { + // scan past any drop_delims + while (instr.oneof(drop_delims)) + { + // skip this drop_delim + instr.next(); + // but if that was the end of the string, done + if (instr.done()) + return; + } + // found the start of another token: make a slot for it + tokens.push_back(string_type()); + if (instr.oneof(keep_delims)) + { + // *iter is a keep_delim, a token of exactly 1 character. Append + // that character to the new token and proceed. + tokens.back().push_back(instr.next()); + continue; + } + // Here we have a non-delimiter token, which might consist of a mix of + // quoted and unquoted parts. Use bash rules for quoting: you can + // embed a quoted substring in the midst of an unquoted token (e.g. + // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together + // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge + // from bash in that bash considers an unmatched quote an error. Our + // param signature doesn't allow for errors, so just pretend it's not + // a quote and embed it. + // At this level, keep scanning until we hit the next delimiter of + // either type (drop_delims or keep_delims). + while (! instr.oneof(all_delims)) + { + // If we're looking at an open quote, search forward for + // a close quote, collecting characters along the way. + if (instr.oneof(quotes) && + instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) + { + // collect_until is cleverly designed to do exactly what we + // need here. No further action needed if it returns true. + } + else + { + // Either *iter isn't a quote, or there's no matching close + // quote: in other words, just an ordinary char. Append it to + // current token. + tokens.back().push_back(instr.next()); + } + // having scanned that segment of this token, if we've reached the + // end of the string, we're done + if (instr.done()) + return; + } + } } } // namespace LLStringUtilBaseImpl @@ -1191,256 +1220,256 @@ void getTokens(INSTRING& instr, std::vector<string_type>& tokens, // static template <class T> void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) { - // Because this overload doesn't support escapes, use simple InString to - // manage input range. - LLStringUtilBaseImpl::InString<T> instring(string.begin(), string.end()); - LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); + // Because this overload doesn't support escapes, use simple InString to + // manage input range. + LLStringUtilBaseImpl::InString<T> instring(string.begin(), string.end()); + LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); } // static template <class T> void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes, const string_type& escapes) -{ - // This overload must deal with escapes. Delegate that to InEscString - // (unless there ARE no escapes). - std::unique_ptr< LLStringUtilBaseImpl::InString<T> > instrp; - if (escapes.empty()) - instrp.reset(new LLStringUtilBaseImpl::InString<T>(string.begin(), string.end())); - else - instrp.reset(new LLStringUtilBaseImpl::InEscString<T>(string.begin(), string.end(), escapes)); - LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes, const string_type& escapes) +{ + // This overload must deal with escapes. Delegate that to InEscString + // (unless there ARE no escapes). + std::unique_ptr< LLStringUtilBaseImpl::InString<T> > instrp; + if (escapes.empty()) + instrp.reset(new LLStringUtilBaseImpl::InString<T>(string.begin(), string.end())); + else + instrp.reset(new LLStringUtilBaseImpl::InEscString<T>(string.begin(), string.end(), escapes)); + LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); } // static -template<class T> +template<class T> S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs) -{ - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0]) - { - result = -1; - } - else - { - result = LLStringOps::collate(lhs, rhs); - } - return result; +{ + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0]) + { + result = -1; + } + else + { + result = LLStringOps::collate(lhs, rhs); + } + return result; } -//static -template<class T> +//static +template<class T> S32 LLStringUtilBase<T>::compareStrings(const string_type& lhs, const string_type& rhs) { - return LLStringOps::collate(lhs.c_str(), rhs.c_str()); + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); } // static -template<class T> +template<class T> S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs ) { - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0] ) - { - result = -1; - } - else - { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase<T>::toUpper(lhs_string); - LLStringUtilBase<T>::toUpper(rhs_string); - result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); - } - return result; + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0] ) + { + result = -1; + } + else + { + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); + result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + } + return result; } -//static -template<class T> +//static +template<class T> S32 LLStringUtilBase<T>::compareInsensitive(const string_type& lhs, const string_type& rhs) { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase<T>::toUpper(lhs_string); - LLStringUtilBase<T>::toUpper(rhs_string); - return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); + return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); } // Case sensitive comparison with good handling of numbers. Does not use current locale. // a.k.a. strdictcmp() -//static +//static template<class T> S32 LLStringUtilBase<T>::compareDict(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - S32 bias = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( bias==0 ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } - }else{ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai<bi ){ ca=0; break; } - if( bi<ai ){ cb=0; break; } - if( ca!=cb ) break; - cnt = ai; - } - }else if( ca!=cb ){ break; - } - ca = *(a++); - cb = *(b++); - } - if( ca==cb ) ca += bias; - return ca-cb; + const T* a = astr.c_str(); + const T* b = bstr.c_str(); + T ca, cb; + S32 ai, bi, cnt = 0; + S32 bias = 0; + + ca = *(a++); + cb = *(b++); + while( ca && cb ){ + if( bias==0 ){ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } + }else{ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } + } + if( LLStringOps::isDigit(ca) ){ + if( cnt-->0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai<bi ){ ca=0; break; } + if( bi<ai ){ cb=0; break; } + if( ca!=cb ) break; + cnt = ai; + } + }else if( ca!=cb ){ break; + } + ca = *(a++); + cb = *(b++); + } + if( ca==cb ) ca += bias; + return ca-cb; } // static template<class T> S32 LLStringUtilBase<T>::compareDictInsensitive(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai<bi ){ ca=0; break; } - if( bi<ai ){ cb=0; break; } - if( ca!=cb ) break; - cnt = ai; - } - }else if( ca!=cb ){ break; - } - ca = *(a++); - cb = *(b++); - } - return ca-cb; + const T* a = astr.c_str(); + const T* b = bstr.c_str(); + T ca, cb; + S32 ai, bi, cnt = 0; + + ca = *(a++); + cb = *(b++); + while( ca && cb ){ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } + if( LLStringOps::isDigit(ca) ){ + if( cnt-->0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai<bi ){ ca=0; break; } + if( bi<ai ){ cb=0; break; } + if( ca!=cb ) break; + cnt = ai; + } + }else if( ca!=cb ){ break; + } + ca = *(a++); + cb = *(b++); + } + return ca-cb; } // Puts compareDict() in a form appropriate for LL container classes to use for sorting. -// static -template<class T> +// static +template<class T> BOOL LLStringUtilBase<T>::precedesDict( const string_type& a, const string_type& b ) { - if( a.size() && b.size() ) - { - return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); - } - else - { - return (!b.empty()); - } + if( a.size() && b.size() ) + { + return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); + } + else + { + return (!b.empty()); + } } //static -template<class T> -void LLStringUtilBase<T>::toUpper(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toUpper); - } +template<class T> +void LLStringUtilBase<T>::toUpper(string_type& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toUpper); + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::toLower(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toLower); - } +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toLower); + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::trimHead(string_type& string) -{ - if( !string.empty() ) - { - size_type i = 0; - while( i < string.length() && LLStringOps::isSpace( string[i] ) ) - { - i++; - } - string.erase(0, i); - } +{ + if( !string.empty() ) + { + size_type i = 0; + while( i < string.length() && LLStringOps::isSpace( string[i] ) ) + { + i++; + } + string.erase(0, i); + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::trimTail(string_type& string) -{ - if( string.size() ) - { - size_type len = string.length(); - size_type i = len; - while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) - { - i--; - } - - string.erase( i, len - i ); - } +{ + if( string.size() ) + { + size_type len = string.length(); + size_type i = len; + while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) + { + i--; + } + + string.erase( i, len - i ); + } } @@ -1449,67 +1478,67 @@ void LLStringUtilBase<T>::trimTail(string_type& string) template<class T> void LLStringUtilBase<T>::addCRLF(string_type& string) { - const T LF = 10; - const T CR = 13; - - // Count the number of line feeds - size_type count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len; i++ ) - { - if( string[i] == LF ) - { - count++; - } - } - - // Insert a carriage return before each line feed - if( count ) - { - size_type size = len + count; - T *t = new T[size]; - size_type j = 0; - for( i = 0; i < len; ++i ) - { - if( string[i] == LF ) - { - t[j] = CR; - ++j; - } - t[j] = string[i]; - ++j; - } - - string.assign(t, size); - delete[] t; - } + const T LF = 10; + const T CR = 13; + + // Count the number of line feeds + size_type count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len; i++ ) + { + if( string[i] == LF ) + { + count++; + } + } + + // Insert a carriage return before each line feed + if( count ) + { + size_type size = len + count; + T *t = new T[size]; + size_type j = 0; + for( i = 0; i < len; ++i ) + { + if( string[i] == LF ) + { + t[j] = CR; + ++j; + } + t[j] = string[i]; + ++j; + } + + string.assign(t, size); + delete[] t; + } } // Remove all carriage returns //static -template<class T> +template<class T> void LLStringUtilBase<T>::removeCRLF(string_type& string) { - const T CR = 13; - - size_type cr_count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len - cr_count; i++ ) - { - if( string[i+cr_count] == CR ) - { - cr_count++; - } - - string[i] = string[i+cr_count]; - } - string.erase(i, cr_count); + const T CR = 13; + + size_type cr_count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len - cr_count; i++ ) + { + if( string[i+cr_count] == CR ) + { + cr_count++; + } + + string[i] = string[i+cr_count]; + } + string.erase(i, cr_count); } //static -template<class T> +template<class T> void LLStringUtilBase<T>::removeWindowsCR(string_type& string) { if (string.empty()) @@ -1538,269 +1567,269 @@ void LLStringUtilBase<T>::removeWindowsCR(string_type& string) template<class T> void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string[found_pos] = replacement; - found_pos++; // avoid infinite defeat if target == replacement - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::replaceString( string_type& string, string_type target, string_type replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string.replace( found_pos, target.length(), replacement ); - found_pos += replacement.length(); // avoid infinite defeat if replacement contains target - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::replaceNonstandardASCII( string_type& string, T replacement ) { - const char LF = 10; - const S8 MIN = 32; -// const S8 MAX = 127; - - size_type len = string.size(); - for( size_type i = 0; i < len; i++ ) - { - // No need to test MAX < mText[i] because we treat mText[i] as a signed char, - // which has a max value of 127. - if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) - { - string[i] = replacement; - } - } + const char LF = 10; + const S8 MIN = 32; +// const S8 MAX = 127; + + size_type len = string.size(); + for( size_type i = 0; i < len; i++ ) + { + // No need to test MAX < mText[i] because we treat mText[i] as a signed char, + // which has a max value of 127. + if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) + { + string[i] = replacement; + } + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spaces_per_tab ) { - const T TAB = '\t'; - const T SPACE = ' '; - - string_type out_str; - // Replace tabs with spaces - for (size_type i = 0; i < str.length(); i++) - { - if (str[i] == TAB) - { - for (size_type j = 0; j < spaces_per_tab; j++) - out_str += SPACE; - } - else - { - out_str += str[i]; - } - } - str = out_str; + const T TAB = '\t'; + const T SPACE = ' '; + + string_type out_str; + // Replace tabs with spaces + for (size_type i = 0; i < str.length(); i++) + { + if (str[i] == TAB) + { + for (size_type j = 0; j < spaces_per_tab; j++) + out_str += SPACE; + } + else + { + out_str += str[i]; + } + } + str = out_str; } //static template<class T> std::basic_string<T> LLStringUtilBase<T>::capitalize(const string_type& str) { - string_type result(str); - capitalize(result); - return result; + string_type result(str); + capitalize(result); + return result; } //static template<class T> void LLStringUtilBase<T>::capitalize(string_type& str) { - if (str.size()) - { - auto last = str[0] = toupper(str[0]); - for (U32 i = 1; i < str.size(); ++i) - { - last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; - } - } + if (str.size()) + { + auto last = str[0] = toupper(str[0]); + for (U32 i = 1; i < str.size(); ++i) + { + last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; + } + } } //static -template<class T> +template<class T> BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string) { - const char MIN = 32; - BOOL rv = FALSE; - for (size_type i = 0; i < string.size(); i++) - { - if(string[i] < MIN) - { - rv = TRUE; - break; - } - } - return rv; + const char MIN = 32; + BOOL rv = FALSE; + for (size_type i = 0; i < string.size(); i++) + { + if(string[i] < MIN) + { + rv = TRUE; + break; + } + } + return rv; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm //static -template<class T> +template<class T> void LLStringUtilBase<T>::stripNonprintable(string_type& string) { - const char MIN = 32; - size_type j = 0; - if (string.empty()) - { - return; - } - size_t src_size = string.size(); - char* c_string = new char[src_size + 1]; - if(c_string == NULL) - { - return; - } - copy(c_string, string.c_str(), src_size+1); - char* write_head = &c_string[0]; - for (size_type i = 0; i < src_size; i++) - { - char* read_head = &string[i]; - write_head = &c_string[j]; - if(!(*read_head < MIN)) - { - *write_head = *read_head; - ++j; - } - } - c_string[j]= '\0'; - string = c_string; - delete []c_string; + const char MIN = 32; + size_type j = 0; + if (string.empty()) + { + return; + } + size_t src_size = string.size(); + char* c_string = new char[src_size + 1]; + if(c_string == NULL) + { + return; + } + copy(c_string, string.c_str(), src_size+1); + char* write_head = &c_string[0]; + for (size_type i = 0; i < src_size; i++) + { + char* read_head = &string[i]; + write_head = &c_string[j]; + if(!(*read_head < MIN)) + { + *write_head = *read_head; + ++j; + } + } + c_string[j]= '\0'; + string = c_string; + delete []c_string; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm template<class T> std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str, - const string_type& triggers, - const string_type& escape) -{ - size_type len(str.length()); - // If the string is already quoted, assume user knows what s/he's doing. - if (len >= 2 && str[0] == '"' && str[len-1] == '"') - { - return str; - } - - // Not already quoted: do we need to? triggers.empty() is a special case - // meaning "always quote." - if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) - { - // no trigger characters, don't bother quoting - return str; - } - - // For whatever reason, we must quote this string. - string_type result; - result.push_back('"'); - for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) - { - if (*ci == '"') - { - result.append(escape); - } - result.push_back(*ci); - } - result.push_back('"'); - return result; + const string_type& triggers, + const string_type& escape) +{ + size_type len(str.length()); + // If the string is already quoted, assume user knows what s/he's doing. + if (len >= 2 && str[0] == '"' && str[len-1] == '"') + { + return str; + } + + // Not already quoted: do we need to? triggers.empty() is a special case + // meaning "always quote." + if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) + { + // no trigger characters, don't bother quoting + return str; + } + + // For whatever reason, we must quote this string. + string_type result; + result.push_back('"'); + for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) + { + if (*ci == '"') + { + result.append(escape); + } + result.push_back(*ci); + } + result.push_back('"'); + return result; } -template<class T> +template<class T> void LLStringUtilBase<T>::_makeASCII(string_type& string) { - // Replace non-ASCII chars with LL_UNKNOWN_CHAR - for (size_type i = 0; i < string.length(); i++) - { - if (string[i] > 0x7f) - { - string[i] = LL_UNKNOWN_CHAR; - } - } + // Replace non-ASCII chars with LL_UNKNOWN_CHAR + for (size_type i = 0; i < string.length(); i++) + { + if (string[i] > 0x7f) + { + string[i] = LL_UNKNOWN_CHAR; + } + } } // static -template<class T> +template<class T> void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size ) { - if( dst_size > 0 ) - { - size_type min_len = 0; - if( src ) - { - min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ - memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ - } - dst[min_len] = '\0'; - } + if( dst_size > 0 ) + { + size_type min_len = 0; + if( src ) + { + min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ + memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ + } + dst[min_len] = '\0'; + } } // static -template<class T> +template<class T> void LLStringUtilBase<T>::copyInto(string_type& dst, const string_type& src, size_type offset) { - if ( offset == dst.length() ) - { - // special case - append to end of string and avoid expensive - // (when strings are large) string manipulations - dst += src; - } - else - { - string_type tail = dst.substr(offset); - - dst = dst.substr(0, offset); - dst += src; - dst += tail; - }; + if ( offset == dst.length() ) + { + // special case - append to end of string and avoid expensive + // (when strings are large) string manipulations + dst += src; + } + else + { + string_type tail = dst.substr(offset); + + dst = dst.substr(0, offset); + dst += src; + dst += tail; + }; } // True if this is the head of s. //static -template<class T> -BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s ) -{ - if( string.empty() ) - { - // Early exit - return FALSE; - } - else - { - return (strncmp( s, string.c_str(), string.size() ) == 0); - } +template<class T> +BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s ) +{ + if( string.empty() ) + { + // Early exit + return FALSE; + } + else + { + return (strncmp( s, string.c_str(), string.size() ) == 0); + } } // static -template<class T> +template<class T> bool LLStringUtilBase<T>::startsWith( - const string_type& string, - const string_type& substr) + const string_type& string, + const string_type& substr) { - if(string.empty() || (substr.empty())) return false; - if (substr.length() > string.length()) return false; - if (0 == string.compare(0, substr.length(), substr)) return true; - return false; + if(string.empty() || (substr.empty())) return false; + if (substr.length() > string.length()) return false; + if (0 == string.compare(0, substr.length(), substr)) return true; + return false; } // static -template<class T> +template<class T> bool LLStringUtilBase<T>::endsWith( - const string_type& string, - const string_type& substr) -{ - if(string.empty() || (substr.empty())) return false; - size_t sub_len = substr.length(); - size_t str_len = string.length(); - if (sub_len > str_len) return false; - if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; - return false; + const string_type& string, + const string_type& substr) +{ + if(string.empty() || (substr.empty())) return false; + size_t sub_len = substr.length(); + size_t str_len = string.length(); + if (sub_len > str_len) return false; + if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; + return false; } // static @@ -1811,7 +1840,7 @@ auto LLStringUtilBase<T>::getoptenv(const std::string& key) -> boost::optional<s if (found) { // return populated boost::optional - return { ll_convert<string_type>(*found) }; + return { ll_convert_to<string_type>(*found) }; } else { @@ -1835,187 +1864,187 @@ auto LLStringUtilBase<T>::getenv(const std::string& key, const string_type& dflt } } -template<class T> +template<class T> BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - if( - (temp == "1") || - (temp == "T") || - (temp == "t") || - (temp == "TRUE") || - (temp == "true") || - (temp == "True") ) - { - value = TRUE; - return TRUE; - } - else - if( - (temp == "0") || - (temp == "F") || - (temp == "f") || - (temp == "FALSE") || - (temp == "false") || - (temp == "False") ) - { - value = FALSE; - return TRUE; - } - - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + if( + (temp == "1") || + (temp == "T") || + (temp == "t") || + (temp == "TRUE") || + (temp == "true") || + (temp == "True") ) + { + value = TRUE; + return TRUE; + } + else + if( + (temp == "0") || + (temp == "F") || + (temp == "f") || + (temp == "FALSE") || + (temp == "false") || + (temp == "False") ) + { + value = FALSE; + return TRUE; + } + + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) - { - value = (U8) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) + { + value = (U8) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) - { - value = (S8) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) + { + value = (S8) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) - { - value = (S16) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) + { + value = (S16) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) - { - value = (U16) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) + { + value = (U16) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - U32 v; - std::basic_istringstream<T> i_stream((string_type)temp); - if(i_stream >> v) - { - value = v; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + U32 v; + std::basic_istringstream<T> i_stream((string_type)temp); + if(i_stream >> v) + { + value = v; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - S32 v; - std::basic_istringstream<T> i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if((LONG_MAX == v) || (LONG_MIN == v)) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + S32 v; + std::basic_istringstream<T> i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if((LONG_MAX == v) || (LONG_MIN == v)) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value) -{ - F64 value64 = 0.0; - BOOL success = convertToF64(string, value64); - if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) - { - value = (F32) value64; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value) +{ + F64 value64 = 0.0; + BOOL success = convertToF64(string, value64); + if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) + { + value = (F32) value64; + return TRUE; + } + return FALSE; } -template<class T> +template<class T> BOOL LLStringUtilBase<T>::convertToF64(const string_type& string, F64& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - F64 v; - std::basic_istringstream<T> i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + F64 v; + std::basic_istringstream<T> i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template<class T> +template<class T> void LLStringUtilBase<T>::truncate(string_type& string, size_type count) { - size_type cur_size = string.size(); - string.resize(count < cur_size ? count : cur_size); + size_type cur_size = string.size(); + string.resize(count < cur_size ? count : cur_size); } // The good thing about *declaration* macros, vs. usage macros, is that now diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp new file mode 100644 index 0000000000..08bc65e0c5 --- /dev/null +++ b/indra/llcommon/lua_function.cpp @@ -0,0 +1,984 @@ +/** + * @file lua_function.cpp + * @author Nat Goodspeed + * @date 2024-02-05 + * @brief Implementation for lua_function. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lua_function.h" +// STL headers +// std headers +#include <algorithm> +#include <exception> +#include <iomanip> // std::quoted +#include <map> +#include <memory> // std::unique_ptr +#include <typeinfo> +// external library headers +// other Linden headers +#include "fsyspath.h" +#include "hexdump.h" +#include "lleventcoro.h" +#include "llsd.h" +#include "llsdutil.h" +#include "lualistener.h" +#include "stringize.h" + +const S32 INTERRUPTS_MAX_LIMIT = 20000; +const S32 INTERRUPTS_SUSPEND_LIMIT = 100; + +#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) +#define lua_rawlen lua_objlen + +/***************************************************************************** +* luau namespace +*****************************************************************************/ +namespace +{ + // can't specify free function free() as a unique_ptr deleter + struct freer + { + void operator()(void* ptr){ free(ptr); } + }; +} // anonymous namespace + +int lluau::dostring(lua_State* L, const std::string& desc, const std::string& text) +{ + auto r = loadstring(L, desc, text); + if (r != LUA_OK) + return r; + + // It's important to pass LUA_MULTRET as the expected number of return + // values: if we pass any fixed number, we discard any returned values + // beyond that number. + return lua_pcall(L, 0, LUA_MULTRET, 0); +} + +int lluau::loadstring(lua_State *L, const std::string &desc, const std::string &text) +{ + size_t bytecodeSize = 0; + // The char* returned by luau_compile() must be freed by calling free(). + // Use unique_ptr so the memory will be freed even if luau_load() throws. + std::unique_ptr<char[], freer> bytecode{ + luau_compile(text.data(), text.length(), nullptr, &bytecodeSize)}; + return luau_load(L, desc.data(), bytecode.get(), bytecodeSize, 0); +} + +fsyspath lluau::source_path(lua_State* 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); + return ar.source; +} + +void lluau::set_interrupts_counter(lua_State *L, S32 counter) +{ + luaL_checkstack(L, 2, nullptr); + lua_pushstring(L, "_INTERRUPTS"); + lua_pushinteger(L, counter); + lua_rawset(L, LUA_REGISTRYINDEX); +} + +void lluau::check_interrupts_counter(lua_State* L) +{ + luaL_checkstack(L, 1, nullptr); + lua_pushstring(L, "_INTERRUPTS"); + lua_rawget(L, LUA_REGISTRYINDEX); + S32 counter = lua_tointeger(L, -1); + lua_pop(L, 1); + + lluau::set_interrupts_counter(L, ++counter); + if (counter > INTERRUPTS_MAX_LIMIT) + { + lluau::error(L, "Possible infinite loop, terminated."); + } + else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0) + { + LL_DEBUGS("Lua") << LLCoros::getName() << " suspending at " << counter << " interrupts" + << LL_ENDL; + llcoro::suspend(); + } +} + +/***************************************************************************** +* Lua <=> C++ conversions +*****************************************************************************/ +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()); +} + +// 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) +{ + 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: + { + // Vanilla Lua supports lua_tointegerx(), which tells the caller + // whether the number at the specified stack index is or is not an + // integer. Apparently the function exists but does not work right in + // Luau: it reports even non-integer numbers as integers. + // Instead, check if integer truncation leaves the number intact. + lua_Number numval{ lua_tonumber(L, index) }; + lua_Integer intval{ narrow(numval) }; + if (lua_Number(intval) == numval) + { + return LLSD::Integer(intval); + } + else + { + return numval; + } + } + + 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); + 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 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) }; + 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 + return lluau::error(L, "Expected integer array key, got %f instead", + lua_tonumber(L, -2)); + } + if (intkey < 1) + { + return lluau::error(L, "array key %d out of bounds", int(intkey)); + } + + keys.push_back(LLSD::Integer(intkey)); + break; + } + + case LUA_TSTRING: + // break out strings specially to report the value + return lluau::error(L, "Cannot convert string array key '%s' to LLSD", + lua_tostring(L, -2)); + + default: + return lluau::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); + popper.disarm(); + // Table keys are all integers: are they reasonable integers? + // Arbitrary max: may bite us, but more likely to protect us + const size_t array_max{ 10000 }; + if (keys.size() > array_max) + { + return lluau::error(L, "Conversion from Lua to LLSD array limited to %d entries", + int(array_max)); + } + // 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. + return lluau::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[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) }; + // 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) + { + return lluau::error(L, "Cannot convert %s map key to LLSD", + lua_typename(L, mapkeytype)); + } + + auto key{ lua_tostdstring(L, -2) }; + 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 + return lluau::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 lluau::error(L, "Cannot convert type %s to LLSD", luaL_typename(L, index)); + } +} + +// 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; + } + } +} + +/***************************************************************************** +* LuaState class +*****************************************************************************/ +LuaState::LuaState(script_finished_fn cb): + mCallback(cb), + mState(nullptr) +{ + initLuaState(); +} + +void LuaState::initLuaState() +{ + if (mState) + { + lua_close(mState); + } + 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")); + // We don't want to have to prefix require(). + lua_register(mState, "require", LuaFunction::get("require")); +} + +LuaState::~LuaState() +{ + // Did somebody call obtainListener() on this LuaState? + // That is, is there a LuaListener key in its registry? + LuaListener::destruct(getListener()); + + lua_close(mState); + + if (mCallback) + { + // mError potentially set by previous checkLua() call(s) + mCallback(mError); + } +} + +bool LuaState::checkLua(const std::string& desc, int r) +{ + if (r != LUA_OK) + { + mError = lua_tostring(mState, -1); + lua_pop(mState, 1); + + LL_WARNS() << desc << ": " << mError << LL_ENDL; + return false; + } + return true; +} + +std::pair<int, LLSD> LuaState::expr(const std::string& desc, const std::string& text) +{ + lluau::set_interrupts_counter(mState, 0); + + lua_callbacks(mState)->interrupt = [](lua_State *L, int gc) + { + // skip if we're interrupting only for garbage collection + if (gc >= 0) + return; + + LLCoros::checkStop(); + lluau::check_interrupts_counter(L); + }; + + if (! checkLua(desc, lluau::dostring(mState, desc, text))) + { + LL_WARNS("Lua") << desc << " error: " << mError << LL_ENDL; + return { -1, mError }; + } + + // here we believe there was no error -- did the Lua fragment leave + // anything on the stack? + std::pair<int, LLSD> result{ lua_gettop(mState), {} }; + LL_INFOS("Lua") << desc << " done, " << result.first << " results." << LL_ENDL; + if (result.first) + { + // aha, at least one entry on the stack! + if (result.first == 1) + { + // Don't forget that lua_tollsd() can throw Lua errors. + try + { + result.second = lua_tollsd(mState, 1); + } + catch (const std::exception& error) + { + LL_WARNS("Lua") << desc << " error converting result: " << error.what() << LL_ENDL; + // lua_tollsd() is designed to be called from a lua_function(), + // that is, from a C++ function called by Lua. In case of error, + // it throws a Lua error to be caught by the Lua runtime. expr() + // is a peculiar use case in which our C++ code is calling + // lua_tollsd() after return from the Lua runtime. We must catch + // the exception thrown for a Lua error, else it will propagate + // out to the main coroutine and terminate the viewer -- but since + // we instead of the Lua runtime catch it, our lua_State retains + // its internal error status. Any subsequent lua_pcall() calls + // with this lua_State will report error regardless of whether the + // chunk runs successfully. Get a new lua_State(). + initLuaState(); + return { -1, stringize(LLError::Log::classname(error), ": ", error.what()) }; + } + } + else + { + // multiple entries on the stack + int index; + try + { + for (index = 1; index <= result.first; ++index) + { + result.second.append(lua_tollsd(mState, index)); + } + } + catch (const std::exception& error) + { + LL_WARNS("Lua") << desc << " error converting result " << index << ": " + << error.what() << LL_ENDL; + // see above comments regarding lua_State's error status + initLuaState(); + return { -1, stringize(LLError::Log::classname(error), ": ", error.what()) }; + } + } + } + // pop everything + lua_settop(mState, 0); + + // If we ran a script that loaded the fiber module, finish up with a call + // to fiber.run(). That allows a 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 appending a call to fiber.run(). run() ensures the + // rest of the fibers run to completion (or error). + luaL_checkstack(mState, 4, nullptr); + // Push _MODULES table on stack + luaL_findtable(mState, LUA_REGISTRYINDEX, "_MODULES", 1); + int index = lua_gettop(mState); + bool found = false; + // Did this chunk already require('fiber')? To find out, we must search + // the _MODULES table, because our require() implementation uses the + // pathname of the module file as the key. Push nil key to start. + lua_pushnil(mState); + while (lua_next(mState, index) != 0) + { + // key is at index -2, value at index -1 + // "While traversing a table, do not call lua_tolstring directly on a + // key, unless you know that the key is actually a string. Recall that + // lua_tolstring changes the value at the given index; this confuses + // the next call to lua_next." + // https://www.lua.org/manual/5.1/manual.html#lua_next + if (lua_type(mState, -2) == LUA_TSTRING && + fsyspath(lua_tostdstring(mState, -2)).stem() == "fiber") + { + found = true; + break; + } + // pop value so key is at top for lua_next() + lua_pop(mState, 1); + } + if (found) + { + // okay, index -1 is a table loaded from a file 'fiber.xxx' -- + // does it have a function named 'run'? + auto run_type{ lua_getfield(mState, -1, "run") }; + if (run_type == LUA_TFUNCTION) + { + // there's a fiber.run() function sitting on the top of the stack + // -- call it with no arguments, discarding anything it returns + LL_INFOS("Lua") << desc << " p.s. fiber.run()" << LL_ENDL; + if (! checkLua(desc, lua_pcall(mState, 0, 0, 0))) + { + LL_WARNS("Lua") << desc << " p.s. fiber.run() error: " << mError << LL_ENDL; + return { -1, mError }; + } + LL_INFOS("Lua") << desc << " p.s. done." << LL_ENDL; + } + } + // pop everything again + lua_settop(mState, 0); + return result; +} + +LuaListener::ptr_t LuaState::getListener(lua_State* L) +{ + // have to use one more stack slot + luaL_checkstack(L, 1, nullptr); + LuaListener::ptr_t listener; + // Does this lua_State already have a LuaListener stored in the registry? + auto keytype{ lua_getfield(L, 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(L, -1, &isint)); + // Nobody should have destroyed this LuaListener instance! + llassert(isint && listener); + } + // pop the int "event.listener" key + lua_pop(L, 1); + return listener; +} + +LuaListener::ptr_t LuaState::obtainListener(lua_State* L) +{ + auto listener{ getListener(L) }; + if (! listener) + { + // have to use one more stack slot + luaL_checkstack(L, 1, nullptr); + // instantiate a new LuaListener, binding the L state -- but use a + // no-op deleter: we do NOT want this ptr_t to manage the lifespan of + // this new LuaListener! + listener.reset(new LuaListener(L), [](LuaListener*){}); + // set its key in the field where we'll look for it later + lua_pushinteger(L, listener->getKey()); + lua_setfield(L, LUA_REGISTRYINDEX, "event.listener"); + } + return listener; +} + +/***************************************************************************** +* LuaPopper class +*****************************************************************************/ +LuaPopper::~LuaPopper() +{ + if (mCount) + { + lua_pop(mState, mCount); + } +} + +/***************************************************************************** +* LuaFunction class +*****************************************************************************/ +LuaFunction::LuaFunction(const std::string_view& name, lua_CFunction function, + const std::string_view& helptext) +{ + const auto& [registry, lookup] = getState(); + registry.emplace(name, Registry::mapped_type{ function, helptext }); + lookup.emplace(function, name); +} + +void LuaFunction::init(lua_State* L) +{ + const auto& [registry, lookup] = getRState(); + luaL_checkstack(L, 2, nullptr); + // create LL table -- + // it happens that we know exactly how many non-array members we want + lua_createtable(L, 0, int(narrow(lookup.size()))); + int idx = lua_gettop(L); + for (const auto& [name, pair]: registry) + { + const auto& [funcptr, helptext] = pair; + // store funcptr in LL table with saved name + lua_pushcfunction(L, funcptr, name.c_str()); + lua_setfield(L, idx, name.c_str()); + } + // store LL in new lua_State's globals + lua_setglobal(L, "LL"); +} + +lua_CFunction LuaFunction::get(const std::string& key) +{ + // use find() instead of subscripting to avoid creating an entry for + // unknown key + const auto& [registry, lookup] = getState(); + auto found{ registry.find(key) }; + return (found == registry.end())? nullptr : found->second.first; +} + +std::pair<LuaFunction::Registry&, LuaFunction::Lookup&> LuaFunction::getState() +{ + // use function-local statics to ensure they're initialized + static Registry registry; + static Lookup lookup; + return { registry, lookup }; +} + +/***************************************************************************** +* source_path() +*****************************************************************************/ +lua_function(source_path, "return the source path of the running Lua script") +{ + luaL_checkstack(L, 1, nullptr); + lua_pushstdstring(L, lluau::source_path(L).u8string()); + return 1; +} + +/***************************************************************************** +* source_dir() +*****************************************************************************/ +lua_function(source_dir, "return the source directory of the running Lua script") +{ + luaL_checkstack(L, 1, nullptr); + lua_pushstdstring(L, lluau::source_path(L).parent_path().u8string()); + return 1; +} + +/***************************************************************************** +* abspath() +*****************************************************************************/ +lua_function(abspath, + "for given filesystem path relative to running script, return absolute path") +{ + auto path{ lua_tostdstring(L, 1) }; + lua_pop(L, 1); + lua_pushstdstring(L, (lluau::source_path(L).parent_path() / path).u8string()); + return 1; +} + +/***************************************************************************** +* check_stop() +*****************************************************************************/ +lua_function(check_stop, "ensure that a Lua script responds to viewer shutdown") +{ + LLCoros::checkStop(); + return 0; +} + +/***************************************************************************** +* help() +*****************************************************************************/ +lua_function(help, + "help(): list viewer's Lua functions\n" + "help(function): show help string for specific function") +{ + auto& luapump{ LLEventPumps::instance().obtain("lua output") }; + const auto& [registry, lookup]{ LuaFunction::getRState() }; + if (! lua_gettop(L)) + { + // no arguments passed: list all lua_functions + for (const auto& [name, pair] : registry) + { + const auto& [fptr, helptext] = pair; + luapump.post(helptext); + } + } + else + { + // arguments passed: list each of the specified lua_functions + for (int idx = 1, top = lua_gettop(L); idx <= top; ++idx) + { + std::string arg{ stringize("<unknown ", lua_typename(L, lua_type(L, idx)), ">") }; + if (lua_type(L, idx) == LUA_TSTRING) + { + arg = lua_tostdstring(L, idx); + } + else if (lua_type(L, idx) == LUA_TFUNCTION) + { + // Caller passed the actual function instead of its string + // name. A Lua function is an anonymous callable object; it + // has a name only by assigment. You can't ask Lua for a + // function's name, which is why our constructor maintains a + // reverse Lookup map. + auto function{ lua_tocfunction(L, idx) }; + if (auto found = lookup.find(function); found != lookup.end()) + { + // okay, pass found name to lookup below + arg = found->second; + } + } + + if (auto found = registry.find(arg); found != registry.end()) + { + luapump.post(found->second.second); + } + else + { + luapump.post(arg + ": NOT FOUND"); + } + } + // pop all arguments + lua_settop(L, 0); + } + return 0; // void return +} + +/***************************************************************************** +* leaphelp() +*****************************************************************************/ +lua_function( + leaphelp, + "leaphelp(): list viewer's LEAP APIs\n" + "leaphelp(api): show help for specific api string name") +{ + LLSD request; + int top{ lua_gettop(L) }; + if (top) + { + request = llsd::map("op", "getAPI", "api", lua_tostdstring(L, 1)); + } + else + { + request = llsd::map("op", "getAPIs"); + } + // pop all args + lua_settop(L, 0); + + auto& outpump{ LLEventPumps::instance().obtain("lua output") }; + auto listener{ LuaState::obtainListener(L) }; + LLEventStream replyPump("leaphelp", true); + // ask the LuaListener's LeapListener and suspend calling coroutine until reply + auto reply{ llcoro::postAndSuspend(request, listener->getCommandName(), replyPump, "reply") }; + reply.erase("reqid"); + + if (auto error = reply["error"]; error.isString()) + { + outpump.post(error.asString()); + return 0; + } + + if (top) + { + // caller wants a specific API + outpump.post(stringize(reply["name"].asString(), ":\n", reply["desc"].asString())); + for (const auto& opmap : llsd::inArray(reply["ops"])) + { + std::ostringstream reqstr; + auto req{ opmap["required"] }; + if (req.isArray()) + { + const char* sep = " (requires "; + for (const auto& [reqkey, reqval] : llsd::inMap(req)) + { + reqstr << sep << reqkey; + sep = ", "; + } + reqstr << ")"; + } + outpump.post(stringize("---- ", reply["key"].asString(), " == '", + opmap["name"].asString(), "'", reqstr.str(), ":\n", + opmap["desc"].asString())); + } + } + else + { + // caller wants a list of APIs + for (const auto& [name, data] : llsd::inMap(reply)) + { + outpump.post(stringize("==== ", name, ":\n", data["desc"].asString())); + } + } + return 0; // void return +} + +/***************************************************************************** +* lua_what +*****************************************************************************/ +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; +} + +/***************************************************************************** +* lua_stack +*****************************************************************************/ +std::ostream& operator<<(std::ostream& out, const lua_stack& self) +{ + out << "stack: ["; + const char* sep = ""; + for (int index = 1; index <= lua_gettop(self.L); ++index) + { + out << sep << lua_what(self.L, index); + sep = ", "; + } + out << ']'; + return out; +} diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h new file mode 100644 index 0000000000..e7013f92c6 --- /dev/null +++ b/indra/llcommon/lua_function.h @@ -0,0 +1,259 @@ +/** + * @file lua_function.h + * @author Nat Goodspeed + * @date 2024-02-05 + * @brief Definitions useful for coding a new Luau entry point into C++ + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LUA_FUNCTION_H) +#define LL_LUA_FUNCTION_H + +#include "luau/luacode.h" +#include "luau/lua.h" +#include "luau/luaconf.h" +#include "luau/lualib.h" +#include "fsyspath.h" +#include "stringize.h" +#include <exception> // std::uncaught_exceptions() +#include <memory> // std::shared_ptr +#include <utility> // std::pair + +class LuaListener; + +namespace lluau +{ + // luau defines luaL_error() as void, but we want to use the Lua idiom of + // 'return error(...)'. Wrap luaL_error() in an int function. +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-security" +#endif // __clang__ + template<typename... Args> + int error(lua_State* L, const char* format, Args&&... args) + { + luaL_error(L, format, std::forward<Args>(args)...); +#ifndef LL_MSVC + return 0; +#endif + } +#if __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + + // luau removed lua_dostring(), but since we perform the equivalent luau + // sequence in multiple places, encapsulate it. desc and text are strings + // rather than string_views because dostring() needs pointers to nul- + // terminated char arrays. + int dostring(lua_State* L, const std::string& desc, const std::string& text); + int loadstring(lua_State* L, const std::string& desc, const std::string& text); + + fsyspath source_path(lua_State* L); + + void set_interrupts_counter(lua_State *L, S32 counter); + void check_interrupts_counter(lua_State* L); +} // namespace lluau + +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); + +/** + * RAII class to manage the lifespan of a lua_State + */ +class LuaState +{ +public: + typedef std::function<void(std::string msg)> script_finished_fn; + + LuaState(script_finished_fn cb={}); + + LuaState(const LuaState&) = delete; + LuaState& operator=(const LuaState&) = delete; + + ~LuaState(); + + void initLuaState(); + + bool checkLua(const std::string& desc, int r); + + // expr() is for when we want to capture any results left on the stack + // by a Lua expression, possibly including multiple return values. + // int < 0 means error, and LLSD::asString() is the error message. + // int == 0 with LLSD::isUndefined() means the Lua expression returned no + // results. + // int == 1 means the Lua expression returned one result. + // int > 1 with LLSD::isArray() means the Lua expression returned + // multiple results, represented as the entries of the array. + std::pair<int, LLSD> expr(const std::string& desc, const std::string& text); + + operator lua_State*() const { return mState; } + + // Return LuaListener for this LuaState if we already have one, else empty + // shared_ptr. + std::shared_ptr<LuaListener> getListener() { return getListener(mState); } + // Find or create LuaListener for this LuaState, returning its ptr_t. + std::shared_ptr<LuaListener> obtainListener() { return obtainListener(mState); } + // Return LuaListener for passed lua_State if we already have one, else + // empty shared_ptr. + static std::shared_ptr<LuaListener> getListener(lua_State* L); + // Find or create LuaListener for passed lua_State, returning its ptr_t. + static std::shared_ptr<LuaListener> obtainListener(lua_State* L); + +private: + script_finished_fn mCallback; + lua_State* mState; + std::string mError; +}; + +/** + * 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(); + + 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, + const std::string_view& helptext); + + static void init(lua_State* L); + + static lua_CFunction get(const std::string& key); + +protected: + using Registry = std::map<std::string, std::pair<lua_CFunction, std::string>>; + using Lookup = std::map<lua_CFunction, std::string>; + static std::pair<const Registry&, const Lookup&> getRState() { return getState(); } + +private: + static std::pair<Registry&, Lookup&> getState(); +}; + +/** + * lua_function(name, helptext) 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, helptext) \ +static struct name##_luasub : public LuaFunction \ +{ \ + name##_luasub(): LuaFunction(#name, &call, helptext) {} \ + static int call(lua_State* L); \ +} name##_lua; \ +int name##_luasub::call(lua_State* L) +// { +// ... supply method body here, referencing 'L' ... +// } + +// 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); + + 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); + + operator std::string() const { return stringize(*this); } + +private: + lua_State* L; +}; + +// adapted from indra/test/debug.h +// can't generalize Debug::operator() target because it's a variadic template +class LuaLog +{ +public: + template <typename... ARGS> + LuaLog(lua_State* L, ARGS&&... args): + L(L), + mBlock(stringize(std::forward<ARGS>(args)...)) + { + (*this)("entry ", lua_stack(L)); + } + + // non-copyable + LuaLog(const LuaLog&) = delete; + LuaLog& operator=(const LuaLog&) = delete; + + ~LuaLog() + { + auto exceptional{ std::uncaught_exceptions()? "exceptional " : "" }; + (*this)(exceptional, "exit ", lua_stack(L)); + } + + template <typename... ARGS> + void operator()(ARGS&&... args) + { + LL_INFOS("Lua") << mBlock << ' '; + stream_to(LL_CONT, std::forward<ARGS>(args)...); + LL_ENDL; + } + +private: + lua_State* L; + const std::string mBlock; +}; + +#endif /* ! defined(LL_LUA_FUNCTION_H) */ diff --git a/indra/llcommon/lualistener.cpp b/indra/llcommon/lualistener.cpp new file mode 100644 index 0000000000..5c4989e891 --- /dev/null +++ b/indra/llcommon/lualistener.cpp @@ -0,0 +1,114 @@ +/** + * @file lualistener.cpp + * @author Nat Goodspeed + * @date 2024-02-06 + * @brief Implementation for lualistener. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lualistener.h" +// STL headers +// std headers +#include <cstdlib> // std::rand() +#include <cstring> // std::memcpy() +// external library headers +#include "luau/lua.h" +// other Linden headers +#include "llerror.h" +#include "llleaplistener.h" +#include "lua_function.h" + +const int MAX_QSIZE = 1000; + +std::ostream& operator<<(std::ostream& out, const LuaListener& self) +{ + return out << "LuaListener(" << self.getReplyName() << ", " << self.getCommandName() << ")"; +} + +LuaListener::LuaListener(lua_State* L): + super(getUniqueKey()), + mCoroName(LLCoros::getName()), + mListener(new LLLeapListener( + "LuaListener", + [this](const std::string& pump, const LLSD& data) + { return queueEvent(pump, data); })), + // Listen for shutdown events. + mShutdownConnection( + LLCoros::getStopListener( + "LuaState", + mCoroName, + [this](const LLSD&) + { + // If a Lua script is still blocked in getNext() during + // viewer shutdown, close the queue to wake up getNext(). + mQueue.close(); + })) +{} + +LuaListener::~LuaListener() +{} + +int LuaListener::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; +} + +std::string LuaListener::getReplyName() const +{ + return mListener->getReplyPump().getName(); +} + +std::string LuaListener::getCommandName() const +{ + return mListener->getPumpName(); +} + +bool LuaListener::queueEvent(const std::string& pump, const LLSD& data) +{ + // Our Lua script might be stalled, or just fail to retrieve events. Don't + // grow this queue indefinitely. But don't set MAX_QSIZE as the queue + // capacity or we'd block the post() call trying to propagate this event! + if (auto size = mQueue.size(); size > MAX_QSIZE) + { + LL_WARNS("Lua") << "LuaListener queue for " << getReplyName() + << " exceeds " << MAX_QSIZE << ": " << size + << " -- discarding event" << LL_ENDL; + } + else + { + mQueue.push(decltype(mQueue)::value_type(pump, data)); + } + return false; +} + +LuaListener::PumpData LuaListener::getNext() +{ + try + { + LLCoros::TempStatus status("get_event_next()"); + return mQueue.pop(); + } + catch (const LLThreadSafeQueueInterrupt&) + { + // mQueue has been closed. The only way that happens is when we detect + // viewer shutdown. Terminate the calling coroutine. + LLCoros::checkStop(); + return {}; + } +} diff --git a/indra/llcommon/lualistener.h b/indra/llcommon/lualistener.h new file mode 100644 index 0000000000..85fb093cd6 --- /dev/null +++ b/indra/llcommon/lualistener.h @@ -0,0 +1,81 @@ +/** + * @file lualistener.h + * @author Nat Goodspeed + * @date 2024-02-06 + * @brief Define LuaListener class + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LUALISTENER_H) +#define LL_LUALISTENER_H + +#include "llevents.h" +#include "llinstancetracker.h" +#include "llsd.h" +#include "llthreadsafequeue.h" +#include <iosfwd> // std::ostream +#include <memory> // std::unique_ptr +#include <string> +#include <utility> // std::pair + +struct lua_State; +class LLLeapListener; + +/** + * 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 + * 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); + + LuaListener(const LuaListener&) = delete; + LuaListener& operator=(const LuaListener&) = delete; + + ~LuaListener(); + + std::string getReplyName() const; + std::string getCommandName() const; + + /** + * LuaListener enqueues reply events from its LLLeapListener on mQueue. + * Call getNext() to retrieve the next such event. Blocks the calling + * coroutine if the queue is empty. + */ + using PumpData = std::pair<std::string, LLSD>; + PumpData getNext(); + + friend std::ostream& operator<<(std::ostream& out, const LuaListener& self); + +private: + static int getUniqueKey(); + bool queueEvent(const std::string& pump, const LLSD& data); + + LLThreadSafeQueue<PumpData> mQueue; + + std::string mCoroName; + std::unique_ptr<LLLeapListener> mListener; + LLTempBoundListener mShutdownConnection; +}; + +#endif /* ! defined(LL_LUALISTENER_H) */ diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h index 536a18abc1..63d44a7272 100644 --- a/indra/llcommon/stringize.h +++ b/indra/llcommon/stringize.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-12-17 * @brief stringize(item) template function and STRINGIZE(expression) macro - * + * * $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$ */ @@ -88,13 +88,13 @@ struct gstringize_impl }; // partially specialize for a single STRING argument - -// note that ll_convert<T>(T) already handles the trivial case +// note that ll_convert_to<T>(T) already handles the trivial case template <typename OUTCHAR, typename INCHAR> struct gstringize_impl<OUTCHAR, std::basic_string<INCHAR>> { auto operator()(const std::basic_string<INCHAR>& arg) { - return ll_convert<std::basic_string<OUTCHAR>>(arg); + return ll_convert_to<std::basic_string<OUTCHAR>>(arg); } }; @@ -105,7 +105,7 @@ struct gstringize_impl<OUTCHAR, INCHAR*> { auto operator()(const INCHAR* arg) { - return ll_convert<std::basic_string<OUTCHAR>>(arg); + return ll_convert_to<std::basic_string<OUTCHAR>>(arg); } }; diff --git a/indra/llcommon/tests/StringVec.h b/indra/llcommon/tests/StringVec.h index 4311cba992..761956a012 100644 --- a/indra/llcommon/tests/StringVec.h +++ b/indra/llcommon/tests/StringVec.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-24 * @brief Extend TUT ensure_equals() to handle std::vector<std::string> - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ @@ -18,6 +18,16 @@ typedef std::vector<std::string> StringVec; +#if defined(LL_LLTUT_H) +// Modern compilers require us to define operator<<(std::ostream&, StringVec) +// before the definition of the ensure() template that engages it. The error +// stating that the compiler can't find a viable operator<<() is so perplexing +// that even though I've obviously hit it a couple times before, a new +// instance still caused much head-scratching. This warning is intended to +// demystify any inadvertent future recurrence. +#warning "StringVec.h must be #included BEFORE lltut.h for ensure() to work" +#endif + std::ostream& operator<<(std::ostream& out, const StringVec& strings) { out << '('; diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index a3c54ffaa2..e7674fde37 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-22 * @brief Test for coroutine. - * + * * $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$ */ @@ -113,14 +113,13 @@ namespace tut void test_data::explicit_wait(std::shared_ptr<LLCoros::Promise<std::string>>& cbp) { - BEGIN - { - mSync.bump(); - // The point of this test is to verify / illustrate suspending a - // coroutine for something other than an LLEventPump. In other - // words, this shows how to adapt to any async operation that - // provides a callback-style notification (and prove that it - // works). + DEBUG; + mSync.bump(); + // The point of this test is to verify / illustrate suspending a + // coroutine for something other than an LLEventPump. In other + // words, this shows how to adapt to any async operation that + // provides a callback-style notification (and prove that it + // works). // Perhaps we would send a request to a remote server and arrange // for cbp->set_value() to be called on response. @@ -130,13 +129,11 @@ namespace tut cbp = std::make_shared<LLCoros::Promise<std::string>>(); LLCoros::Future<std::string> future = LLCoros::getFuture(*cbp); - // calling get() on the future causes us to suspend - debug("about to suspend"); - stringdata = future.get(); - mSync.bump(); - ensure_equals("Got it", stringdata, "received"); - } - END + // calling get() on the future causes us to suspend + debug("about to suspend"); + stringdata = future.get(); + mSync.bump(); + ensure_equals("Got it", stringdata, "received"); } template<> template<> @@ -163,13 +160,9 @@ namespace tut void test_data::waitForEventOn1() { - BEGIN - { - mSync.bump(); - result = suspendUntilEventOn("source"); - mSync.bump(); - } - END + mSync.bump(); + result = suspendUntilEventOn("source"); + mSync.bump(); } template<> template<> @@ -189,15 +182,11 @@ namespace tut void test_data::coroPump() { - BEGIN - { - mSync.bump(); - LLCoroEventPump waiter; - replyName = waiter.getName(); - result = waiter.suspend(); - mSync.bump(); - } - END + mSync.bump(); + LLCoroEventPump waiter; + replyName = waiter.getName(); + result = waiter.suspend(); + mSync.bump(); } template<> template<> @@ -217,16 +206,12 @@ namespace tut void test_data::postAndWait1() { - BEGIN - { - mSync.bump(); - result = postAndSuspend(LLSDMap("value", 17), // request event - immediateAPI.getPump(), // requestPump - "reply1", // replyPump - "reply"); // request["reply"] = name - mSync.bump(); - } - END + mSync.bump(); + result = postAndSuspend(LLSDMap("value", 17), // request event + immediateAPI.getPump(), // requestPump + "reply1", // replyPump + "reply"); // request["reply"] = name + mSync.bump(); } template<> template<> @@ -240,15 +225,11 @@ namespace tut void test_data::coroPumpPost() { - BEGIN - { - mSync.bump(); - LLCoroEventPump waiter; - result = waiter.postAndSuspend(LLSDMap("value", 17), - immediateAPI.getPump(), "reply"); - mSync.bump(); - } - END + mSync.bump(); + LLCoroEventPump waiter; + result = waiter.postAndSuspend(LLSDMap("value", 17), + immediateAPI.getPump(), "reply"); + mSync.bump(); } template<> template<> diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index a99acba848..244cd07ac9 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-01-20 * @brief Test for lleventdispatcher. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ @@ -17,13 +17,13 @@ // std headers // external library headers // other Linden headers +#include "StringVec.h" #include "../test/lltut.h" #include "lleventfilter.h" #include "llsd.h" #include "llsdutil.h" #include "llevents.h" #include "stringize.h" -#include "StringVec.h" #include "tests/wrapllerrs.h" #include "../test/catch_and_store_what_in.h" #include "../test/debug.h" @@ -470,7 +470,7 @@ namespace tut params["a"], "\n" "params[\"b\"]:\n", params["b"]); - // default LLSD::Binary value + // default LLSD::Binary value std::vector<U8> binary; for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11) { diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index a01d7fe415..ed7cb56506 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-06 * @brief Test for lleventfilter. - * + * * $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$ */ @@ -34,10 +34,10 @@ // std headers // external library headers // other Linden headers +#include "listener.h" #include "../test/lltut.h" #include "stringize.h" #include "llsdutil.h" -#include "listener.h" #include "tests/wrapllerrs.h" #include <typeinfo> diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index fa48bcdefd..6fe9e3446f 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-21 * @brief Test for llleap. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ @@ -18,6 +18,7 @@ #include <functional> // external library headers // other Linden headers +#include "StringVec.h" #include "../test/lltut.h" #include "../test/namedtempfile.h" #include "../test/catch_and_store_what_in.h" @@ -26,7 +27,6 @@ #include "llprocess.h" #include "llstring.h" #include "stringize.h" -#include "StringVec.h" #if defined(LL_WINDOWS) #define sleep(secs) _sleep((secs) * 1000) diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 56fdc51e82..730731a927 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize_test.cpp * @date 2006-04 * @brief LLSDSerialize unit tests @@ -6,21 +6,21 @@ * $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$ */ @@ -52,11 +52,11 @@ typedef U32 uint32_t; #include "llformat.h" #include "llmemorystream.h" -#include "../test/hexdump.h" +#include "hexdump.h" +#include "StringVec.h" #include "../test/lltut.h" #include "../test/namedtempfile.h" #include "stringize.h" -#include "StringVec.h" #include <functional> typedef std::function<void(const LLSD& data, std::ostream& str)> FormatterFunction; @@ -64,313 +64,313 @@ typedef std::function<bool(std::istream& istr, LLSD& data, llssize max_bytes)> P std::vector<U8> string_to_vector(const std::string& str) { - return std::vector<U8>(str.begin(), str.end()); + return std::vector<U8>(str.begin(), str.end()); } namespace tut { - struct sd_xml_data - { - sd_xml_data() - { - mFormatter = new LLSDXMLFormatter; - } - LLSD mSD; - LLPointer<LLSDXMLFormatter> mFormatter; - void xml_test(const char* name, const std::string& expected) - { - std::ostringstream ostr; - mFormatter->format(mSD, ostr); - ensure_equals(name, ostr.str(), expected); - } - }; - - typedef test_group<sd_xml_data> sd_xml_test; - typedef sd_xml_test::object sd_xml_object; - tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); - - template<> template<> - void sd_xml_object::test<1>() - { - // random atomic tests - std::string expected; - - expected = "<llsd><undef /></llsd>\n"; - xml_test("undef", expected); - - mSD = 3463; - expected = "<llsd><integer>3463</integer></llsd>\n"; - xml_test("integer", expected); - - mSD = ""; - expected = "<llsd><string /></llsd>\n"; - xml_test("empty string", expected); - - mSD = "foobar"; - expected = "<llsd><string>foobar</string></llsd>\n"; - xml_test("string", expected); - - mSD = LLUUID::null; - expected = "<llsd><uuid /></llsd>\n"; - xml_test("null uuid", expected); - - mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); - expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n"; - xml_test("uuid", expected); - - mSD = LLURI("https://secondlife.com/login"); - expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n"; - xml_test("uri", expected); - - mSD = LLDate("2006-04-24T16:11:33Z"); - expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n"; - xml_test("date", expected); - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - std::vector<U8> hello; - hello.push_back('h'); - hello.push_back('e'); - hello.push_back('l'); - hello.push_back('l'); - hello.push_back('o'); - mSD = hello; - expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; - xml_test("binary", expected); - } - - template<> template<> - void sd_xml_object::test<2>() - { - // tests with boolean values. - std::string expected; - - mFormatter->boolalpha(true); - mSD = true; - expected = "<llsd><boolean>true</boolean></llsd>\n"; - xml_test("bool alpha true", expected); - mSD = false; - expected = "<llsd><boolean>false</boolean></llsd>\n"; - xml_test("bool alpha false", expected); - - mFormatter->boolalpha(false); - mSD = true; - expected = "<llsd><boolean>1</boolean></llsd>\n"; - xml_test("bool true", expected); - mSD = false; - expected = "<llsd><boolean>0</boolean></llsd>\n"; - xml_test("bool false", expected); - } - - - template<> template<> - void sd_xml_object::test<3>() - { - // tests with real values. - std::string expected; - - mFormatter->realFormat("%.2f"); - mSD = 1.0; - expected = "<llsd><real>1.00</real></llsd>\n"; - xml_test("real 1", expected); - - mSD = -34379.0438; - expected = "<llsd><real>-34379.04</real></llsd>\n"; - xml_test("real reduced precision", expected); - mFormatter->realFormat("%.4f"); - expected = "<llsd><real>-34379.0438</real></llsd>\n"; - xml_test("higher precision", expected); - - mFormatter->realFormat("%.0f"); - mSD = 0.0; - expected = "<llsd><real>0</real></llsd>\n"; - xml_test("no decimal 0", expected); - mSD = 3287.4387; - expected = "<llsd><real>3287</real></llsd>\n"; - xml_test("no decimal real number", expected); - } - - template<> template<> - void sd_xml_object::test<4>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyArray(); - expected = "<llsd><array /></llsd>\n"; - xml_test("empty array", expected); - - mSD.append(LLSD()); - expected = "<llsd><array><undef /></array></llsd>\n"; - xml_test("1 element array", expected); - - mSD.append(1); - expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n"; - xml_test("2 element array", expected); - } - - template<> template<> - void sd_xml_object::test<5>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyMap(); - expected = "<llsd><map /></llsd>\n"; - xml_test("empty map", expected); - - mSD["foo"] = "bar"; - expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n"; - xml_test("1 element map", expected); - - mSD["baz"] = LLSD(); - expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n"; - xml_test("2 element map", expected); - } - - template<> template<> - void sd_xml_object::test<6>() - { - // tests with binary - std::string expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - mSD = string_to_vector("hello"); - expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; - xml_test("binary", expected); - - mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; - xml_test("binary", expected); - } - - class TestLLSDSerializeData - { - public: - TestLLSDSerializeData(); - ~TestLLSDSerializeData(); - - void doRoundTripTests(const std::string&); - void checkRoundTrip(const std::string&, const LLSD& v); - - void setFormatterParser(LLPointer<LLSDFormatter> formatter, LLPointer<LLSDParser> parser) - { - mFormatter = [formatter](const LLSD& data, std::ostream& str) - { - formatter->format(data, str); - }; - // this lambda must be mutable since otherwise the bound 'parser' - // is assumed to point to a const LLSDParser - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable - { - // reset() call is needed since test code re-uses parser object - parser->reset(); - return (parser->parse(istr, data, max_bytes) > 0); - }; - } - - void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) - { - // why does LLSDSerialize::deserialize() reverse the parse() params?? - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) - { - return parser(data, istr, max_bytes); - }; - } - - FormatterFunction mFormatter; - ParserFunction mParser; - }; - - TestLLSDSerializeData::TestLLSDSerializeData() - { - } - - TestLLSDSerializeData::~TestLLSDSerializeData() - { - } - - void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) - { - std::stringstream stream; - mFormatter(v, stream); - //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; - LLSD w; - mParser(stream, w, stream.str().size()); - - try - { - ensure_equals(msg, w, v); - } - catch (...) - { - std::cerr << "the serialized string was:" << std::endl; - std::cerr << stream.str() << std::endl; - throw; - } - } - - static void fillmap(LLSD& root, U32 width, U32 depth) - { - if(depth == 0) - { - root["foo"] = "bar"; - return; - } - - for(U32 i = 0; i < width; ++i) - { - std::string key = llformat("child %d", i); - root[key] = LLSD::emptyMap(); - fillmap(root[key], width, depth - 1); - } - } - - void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) - { - LLSD v; - checkRoundTrip(msg + " undefined", v); - - v = true; - checkRoundTrip(msg + " true bool", v); - - v = false; - checkRoundTrip(msg + " false bool", v); - - v = 1; - checkRoundTrip(msg + " positive int", v); - - v = 0; - checkRoundTrip(msg + " zero int", v); - - v = -1; - checkRoundTrip(msg + " negative int", v); - - v = 1234.5f; - checkRoundTrip(msg + " positive float", v); - - v = 0.0f; - checkRoundTrip(msg + " zero float", v); - - v = -1234.5f; - checkRoundTrip(msg + " negative float", v); - - // FIXME: need a NaN test - - v = LLUUID::null; - checkRoundTrip(msg + " null uuid", v); - - LLUUID newUUID; - newUUID.generate(); - v = newUUID; - checkRoundTrip(msg + " new uuid", v); - - v = ""; - checkRoundTrip(msg + " empty string", v); - - v = "some string"; - checkRoundTrip(msg + " non-empty string", v); - - v = + struct sd_xml_data + { + sd_xml_data() + { + mFormatter = new LLSDXMLFormatter; + } + LLSD mSD; + LLPointer<LLSDXMLFormatter> mFormatter; + void xml_test(const char* name, const std::string& expected) + { + std::ostringstream ostr; + mFormatter->format(mSD, ostr); + ensure_equals(name, ostr.str(), expected); + } + }; + + typedef test_group<sd_xml_data> sd_xml_test; + typedef sd_xml_test::object sd_xml_object; + tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); + + template<> template<> + void sd_xml_object::test<1>() + { + // random atomic tests + std::string expected; + + expected = "<llsd><undef /></llsd>\n"; + xml_test("undef", expected); + + mSD = 3463; + expected = "<llsd><integer>3463</integer></llsd>\n"; + xml_test("integer", expected); + + mSD = ""; + expected = "<llsd><string /></llsd>\n"; + xml_test("empty string", expected); + + mSD = "foobar"; + expected = "<llsd><string>foobar</string></llsd>\n"; + xml_test("string", expected); + + mSD = LLUUID::null; + expected = "<llsd><uuid /></llsd>\n"; + xml_test("null uuid", expected); + + mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); + expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n"; + xml_test("uuid", expected); + + mSD = LLURI("https://secondlife.com/login"); + expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n"; + xml_test("uri", expected); + + mSD = LLDate("2006-04-24T16:11:33Z"); + expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n"; + xml_test("date", expected); + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + std::vector<U8> hello; + hello.push_back('h'); + hello.push_back('e'); + hello.push_back('l'); + hello.push_back('l'); + hello.push_back('o'); + mSD = hello; + expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; + xml_test("binary", expected); + } + + template<> template<> + void sd_xml_object::test<2>() + { + // tests with boolean values. + std::string expected; + + mFormatter->boolalpha(true); + mSD = true; + expected = "<llsd><boolean>true</boolean></llsd>\n"; + xml_test("bool alpha true", expected); + mSD = false; + expected = "<llsd><boolean>false</boolean></llsd>\n"; + xml_test("bool alpha false", expected); + + mFormatter->boolalpha(false); + mSD = true; + expected = "<llsd><boolean>1</boolean></llsd>\n"; + xml_test("bool true", expected); + mSD = false; + expected = "<llsd><boolean>0</boolean></llsd>\n"; + xml_test("bool false", expected); + } + + + template<> template<> + void sd_xml_object::test<3>() + { + // tests with real values. + std::string expected; + + mFormatter->realFormat("%.2f"); + mSD = 1.0; + expected = "<llsd><real>1.00</real></llsd>\n"; + xml_test("real 1", expected); + + mSD = -34379.0438; + expected = "<llsd><real>-34379.04</real></llsd>\n"; + xml_test("real reduced precision", expected); + mFormatter->realFormat("%.4f"); + expected = "<llsd><real>-34379.0438</real></llsd>\n"; + xml_test("higher precision", expected); + + mFormatter->realFormat("%.0f"); + mSD = 0.0; + expected = "<llsd><real>0</real></llsd>\n"; + xml_test("no decimal 0", expected); + mSD = 3287.4387; + expected = "<llsd><real>3287</real></llsd>\n"; + xml_test("no decimal real number", expected); + } + + template<> template<> + void sd_xml_object::test<4>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyArray(); + expected = "<llsd><array /></llsd>\n"; + xml_test("empty array", expected); + + mSD.append(LLSD()); + expected = "<llsd><array><undef /></array></llsd>\n"; + xml_test("1 element array", expected); + + mSD.append(1); + expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n"; + xml_test("2 element array", expected); + } + + template<> template<> + void sd_xml_object::test<5>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyMap(); + expected = "<llsd><map /></llsd>\n"; + xml_test("empty map", expected); + + mSD["foo"] = "bar"; + expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n"; + xml_test("1 element map", expected); + + mSD["baz"] = LLSD(); + expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n"; + xml_test("2 element map", expected); + } + + template<> template<> + void sd_xml_object::test<6>() + { + // tests with binary + std::string expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + mSD = string_to_vector("hello"); + expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; + xml_test("binary", expected); + + mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; + xml_test("binary", expected); + } + + class TestLLSDSerializeData + { + public: + TestLLSDSerializeData(); + ~TestLLSDSerializeData(); + + void doRoundTripTests(const std::string&); + void checkRoundTrip(const std::string&, const LLSD& v); + + void setFormatterParser(LLPointer<LLSDFormatter> formatter, LLPointer<LLSDParser> parser) + { + mFormatter = [formatter](const LLSD& data, std::ostream& str) + { + formatter->format(data, str); + }; + // this lambda must be mutable since otherwise the bound 'parser' + // is assumed to point to a const LLSDParser + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable + { + // reset() call is needed since test code re-uses parser object + parser->reset(); + return (parser->parse(istr, data, max_bytes) > 0); + }; + } + + void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) + { + // why does LLSDSerialize::deserialize() reverse the parse() params?? + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) + { + return parser(data, istr, max_bytes); + }; + } + + FormatterFunction mFormatter; + ParserFunction mParser; + }; + + TestLLSDSerializeData::TestLLSDSerializeData() + { + } + + TestLLSDSerializeData::~TestLLSDSerializeData() + { + } + + void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) + { + std::stringstream stream; + mFormatter(v, stream); + //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; + LLSD w; + mParser(stream, w, stream.str().size()); + + try + { + ensure_equals(msg, w, v); + } + catch (...) + { + std::cerr << "the serialized string was:" << std::endl; + std::cerr << stream.str() << std::endl; + throw; + } + } + + static void fillmap(LLSD& root, U32 width, U32 depth) + { + if(depth == 0) + { + root["foo"] = "bar"; + return; + } + + for(U32 i = 0; i < width; ++i) + { + std::string key = llformat("child %d", i); + root[key] = LLSD::emptyMap(); + fillmap(root[key], width, depth - 1); + } + } + + void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) + { + LLSD v; + checkRoundTrip(msg + " undefined", v); + + v = true; + checkRoundTrip(msg + " true bool", v); + + v = false; + checkRoundTrip(msg + " false bool", v); + + v = 1; + checkRoundTrip(msg + " positive int", v); + + v = 0; + checkRoundTrip(msg + " zero int", v); + + v = -1; + checkRoundTrip(msg + " negative int", v); + + v = 1234.5f; + checkRoundTrip(msg + " positive float", v); + + v = 0.0f; + checkRoundTrip(msg + " zero float", v); + + v = -1234.5f; + checkRoundTrip(msg + " negative float", v); + + // FIXME: need a NaN test + + v = LLUUID::null; + checkRoundTrip(msg + " null uuid", v); + + LLUUID newUUID; + newUUID.generate(); + v = newUUID; + checkRoundTrip(msg + " new uuid", v); + + v = ""; + checkRoundTrip(msg + " empty string", v); + + v = "some string"; + checkRoundTrip(msg + " non-empty string", v); + + v = "Second Life is a 3-D virtual world entirely built and owned by its residents. " "Since opening to the public in 2003, it has grown explosively and today is " "inhabited by nearly 100,000 people from around the globe.\n" @@ -390,437 +390,437 @@ namespace tut "currency exchanges.\n" "\n" "Welcome to Second Life. We look forward to seeing you in-world!\n" - ; - checkRoundTrip(msg + " long string", v); - - static const U32 block_size = 0x000020; - for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) - { - std::ostringstream out; - - for (U32 c = block; c < block + block_size; ++c) - { - if (c <= 0x000001f - && c != 0x000009 - && c != 0x00000a) - { - // see XML standard, sections 2.2 and 4.1 - continue; - } - if (0x00d800 <= c && c <= 0x00dfff) { continue; } - if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } - if ((c & 0x00fffe) == 0x00fffe) { continue; } - // see Unicode standard, section 15.8 - - if (c <= 0x00007f) - { - out << (char)(c & 0x7f); - } - else if (c <= 0x0007ff) - { - out << (char)(0xc0 | ((c >> 6) & 0x1f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else if (c <= 0x00ffff) - { - out << (char)(0xe0 | ((c >> 12) & 0x0f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else - { - out << (char)(0xf0 | ((c >> 18) & 0x07)); - out << (char)(0x80 | ((c >> 12) & 0x3f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - } - - v = out.str(); - - std::ostringstream blockmsg; - blockmsg << msg << " unicode string block 0x" << std::hex << block; - checkRoundTrip(blockmsg.str(), v); - } - - LLDate epoch; - v = epoch; - checkRoundTrip(msg + " epoch date", v); - - LLDate aDay("2002-12-07T05:07:15.00Z"); - v = aDay; - checkRoundTrip(msg + " date", v); - - LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); - v = path; - checkRoundTrip(msg + " url", v); - - const char source[] = "it must be a blue moon again"; - std::vector<U8> data; - // note, includes terminating '\0' - copy(&source[0], &source[sizeof(source)], back_inserter(data)); - - v = data; - checkRoundTrip(msg + " binary", v); - - v = LLSD::emptyMap(); - checkRoundTrip(msg + " empty map", v); - - v = LLSD::emptyMap(); - v["name"] = "luke"; //v.insert("name", "luke"); - v["age"] = 3; //v.insert("age", 3); - checkRoundTrip(msg + " map", v); - - v.clear(); - v["a"]["1"] = true; - v["b"]["0"] = false; - checkRoundTrip(msg + " nested maps", v); - - v = LLSD::emptyArray(); - checkRoundTrip(msg + " empty array", v); - - v = LLSD::emptyArray(); - v.append("ali"); - v.append(28); - checkRoundTrip(msg + " array", v); - - v.clear(); - v[0][0] = true; - v[1][0] = false; - checkRoundTrip(msg + " nested arrays", v); - - v = LLSD::emptyMap(); - fillmap(v, 10, 3); // 10^6 maps - checkRoundTrip(msg + " many nested maps", v); - } - - typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup; - typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; - TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); - - template<> template<> - void TestLLSDSerializeObject::test<1>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), - new LLSDNotationParser()); - doRoundTripTests("pretty binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<2>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - doRoundTripTests("raw binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<3>() - { - setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); - doRoundTripTests("xml serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<4>() - { - setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); - doRoundTripTests("binary serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<5>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_BINARY)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<6>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_XML)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<7>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); - }; - setParser(LLSDSerialize::deserialize); - // In this test, serialize(LLSD_NOTATION) emits a header recognized by - // deserialize(). - doRoundTripTests("serialize(LLSD_NOTATION)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<8>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDNotationFormatter does not - // emit an llsd/notation header. - doRoundTripTests("LLSDNotationFormatter -> deserialize"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<9>() - { - setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDXMLParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDXMLFormatter does not - // emit an LLSD/XML header. - doRoundTripTests("LLSDXMLFormatter -> deserialize"); - }; + ; + checkRoundTrip(msg + " long string", v); + + static const U32 block_size = 0x000020; + for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) + { + std::ostringstream out; + + for (U32 c = block; c < block + block_size; ++c) + { + if (c <= 0x000001f + && c != 0x000009 + && c != 0x00000a) + { + // see XML standard, sections 2.2 and 4.1 + continue; + } + if (0x00d800 <= c && c <= 0x00dfff) { continue; } + if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } + if ((c & 0x00fffe) == 0x00fffe) { continue; } + // see Unicode standard, section 15.8 + + if (c <= 0x00007f) + { + out << (char)(c & 0x7f); + } + else if (c <= 0x0007ff) + { + out << (char)(0xc0 | ((c >> 6) & 0x1f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else if (c <= 0x00ffff) + { + out << (char)(0xe0 | ((c >> 12) & 0x0f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else + { + out << (char)(0xf0 | ((c >> 18) & 0x07)); + out << (char)(0x80 | ((c >> 12) & 0x3f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + } + + v = out.str(); + + std::ostringstream blockmsg; + blockmsg << msg << " unicode string block 0x" << std::hex << block; + checkRoundTrip(blockmsg.str(), v); + } + + LLDate epoch; + v = epoch; + checkRoundTrip(msg + " epoch date", v); + + LLDate aDay("2002-12-07T05:07:15.00Z"); + v = aDay; + checkRoundTrip(msg + " date", v); + + LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); + v = path; + checkRoundTrip(msg + " url", v); + + const char source[] = "it must be a blue moon again"; + std::vector<U8> data; + // note, includes terminating '\0' + copy(&source[0], &source[sizeof(source)], back_inserter(data)); + + v = data; + checkRoundTrip(msg + " binary", v); + + v = LLSD::emptyMap(); + checkRoundTrip(msg + " empty map", v); + + v = LLSD::emptyMap(); + v["name"] = "luke"; //v.insert("name", "luke"); + v["age"] = 3; //v.insert("age", 3); + checkRoundTrip(msg + " map", v); + + v.clear(); + v["a"]["1"] = true; + v["b"]["0"] = false; + checkRoundTrip(msg + " nested maps", v); + + v = LLSD::emptyArray(); + checkRoundTrip(msg + " empty array", v); + + v = LLSD::emptyArray(); + v.append("ali"); + v.append(28); + checkRoundTrip(msg + " array", v); + + v.clear(); + v[0][0] = true; + v[1][0] = false; + checkRoundTrip(msg + " nested arrays", v); + + v = LLSD::emptyMap(); + fillmap(v, 10, 3); // 10^6 maps + checkRoundTrip(msg + " many nested maps", v); + } + + typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup; + typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; + TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); + + template<> template<> + void TestLLSDSerializeObject::test<1>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), + new LLSDNotationParser()); + doRoundTripTests("pretty binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<2>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + doRoundTripTests("raw binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<3>() + { + setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); + doRoundTripTests("xml serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<4>() + { + setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); + doRoundTripTests("binary serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<5>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_BINARY)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<6>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_XML)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<7>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); + }; + setParser(LLSDSerialize::deserialize); + // In this test, serialize(LLSD_NOTATION) emits a header recognized by + // deserialize(). + doRoundTripTests("serialize(LLSD_NOTATION)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<8>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDNotationFormatter does not + // emit an llsd/notation header. + doRoundTripTests("LLSDNotationFormatter -> deserialize"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<9>() + { + setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDXMLParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDXMLFormatter does not + // emit an LLSD/XML header. + doRoundTripTests("LLSDXMLFormatter -> deserialize"); + }; /*==========================================================================*| - // We do not expect this test to succeed. Without a header, neither - // notation LLSD nor binary LLSD reliably start with a distinct character, - // the way XML LLSD starts with '<'. By convention, we default to notation - // rather than binary. - template<> template<> - void TestLLSDSerializeObject::test<10>() - { - setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDBinaryParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDBinaryFormatter does not - // emit an LLSD/Binary header. - doRoundTripTests("LLSDBinaryFormatter -> deserialize"); - }; + // We do not expect this test to succeed. Without a header, neither + // notation LLSD nor binary LLSD reliably start with a distinct character, + // the way XML LLSD starts with '<'. By convention, we default to notation + // rather than binary. + template<> template<> + void TestLLSDSerializeObject::test<10>() + { + setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDBinaryParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDBinaryFormatter does not + // emit an LLSD/Binary header. + doRoundTripTests("LLSDBinaryFormatter -> deserialize"); + }; |*==========================================================================*/ - /** - * @class TestLLSDParsing - * @brief Base class for of a parse tester. - */ - template <class parser_t> - class TestLLSDParsing - { - public: - TestLLSDParsing() - { - mParser = new parser_t; - } - - void ensureParse( - const std::string& msg, - const std::string& in, - const LLSD& expected_value, - S32 expected_count, - S32 depth_limit = -1) - { - std::stringstream input; - input.str(in); - - LLSD parsed_result; - mParser->reset(); // reset() call is needed since test code re-uses mParser - S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); - ensure_equals(msg.c_str(), parsed_result, expected_value); - - // This count check is really only useful for expected - // parse failures, since the ensures equal will already - // require equality. - std::string count_msg(msg); - count_msg += " (count)"; - ensure_equals(count_msg, parsed_count, expected_count); - } - - LLPointer<parser_t> mParser; - }; - - - /** - * @class TestLLSDXMLParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDXMLParsing : public TestLLSDParsing<LLSDXMLParser> - { - public: - TestLLSDXMLParsing() {} - }; - - typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup; - typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; - TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); - - template<> template<> - void TestLLSDXMLParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed xml", - "<llsd><string>ha ha</string>", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "not llsd", - "<html><body><p>ha ha</p></body></html>", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "value without llsd", - "<string>ha ha</string>", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "key without llsd", - "<key>ha ha</key>", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - - template<> template<> - void TestLLSDXMLParsingObject::test<2>() - { - // test handling of unrecognized or unparseable llsd values - LLSD v; - v["amy"] = 23; - v["bob"] = LLSD(); - v["cam"] = 1.23; - - ensureParse( - "unknown data type", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<key>bob</key><bigint>99999999999999999</bigint>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<3>() - { - // test handling of nested bad data - - LLSD v; - v["amy"] = 23; - v["cam"] = 1.23; - - ensureParse( - "map with html", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<html><body>ha ha</body></html>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["cam"] = 1.23; - ensureParse( - "map with value for key", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<string>ha ha</string>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["bob"] = LLSD::emptyMap(); - v["cam"] = 1.23; - ensureParse( - "map with map of html", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<key>bob</key>" - "<map>" - "<html><body>ha ha</body></html>" - "</map>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD(); - v[2] = 1.23; - - ensureParse( - "array value of html", - "<llsd><array>" - "<integer>23</integer>" - "<html><body>ha ha</body></html>" - "<real>1.23</real>" - "</array></llsd>", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD::emptyMap(); - v[2] = 1.23; - ensureParse( - "array with map of html", - "<llsd><array>" - "<integer>23</integer>" - "<map>" - "<html><body>ha ha</body></html>" - "</map>" - "<real>1.23</real>" - "</array></llsd>", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<4>() - { - // test handling of binary object in XML - std::string xml; - LLSD expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - expected = string_to_vector("hello"); - xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; - ensureParse( - "the word 'hello' packed in binary encoded base64", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; - xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; - xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; - xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; - xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - } + /** + * @class TestLLSDParsing + * @brief Base class for of a parse tester. + */ + template <class parser_t> + class TestLLSDParsing + { + public: + TestLLSDParsing() + { + mParser = new parser_t; + } + + void ensureParse( + const std::string& msg, + const std::string& in, + const LLSD& expected_value, + S32 expected_count, + S32 depth_limit = -1) + { + std::stringstream input; + input.str(in); + + LLSD parsed_result; + mParser->reset(); // reset() call is needed since test code re-uses mParser + S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); + ensure_equals(msg.c_str(), parsed_result, expected_value); + + // This count check is really only useful for expected + // parse failures, since the ensures equal will already + // require equality. + std::string count_msg(msg); + count_msg += " (count)"; + ensure_equals(count_msg, parsed_count, expected_count); + } + + LLPointer<parser_t> mParser; + }; + + + /** + * @class TestLLSDXMLParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDXMLParsing : public TestLLSDParsing<LLSDXMLParser> + { + public: + TestLLSDXMLParsing() {} + }; + + typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup; + typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; + TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); + + template<> template<> + void TestLLSDXMLParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed xml", + "<llsd><string>ha ha</string>", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "not llsd", + "<html><body><p>ha ha</p></body></html>", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "value without llsd", + "<string>ha ha</string>", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "key without llsd", + "<key>ha ha</key>", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + + template<> template<> + void TestLLSDXMLParsingObject::test<2>() + { + // test handling of unrecognized or unparseable llsd values + LLSD v; + v["amy"] = 23; + v["bob"] = LLSD(); + v["cam"] = 1.23; + + ensureParse( + "unknown data type", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<key>bob</key><bigint>99999999999999999</bigint>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<3>() + { + // test handling of nested bad data + + LLSD v; + v["amy"] = 23; + v["cam"] = 1.23; + + ensureParse( + "map with html", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<html><body>ha ha</body></html>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["cam"] = 1.23; + ensureParse( + "map with value for key", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<string>ha ha</string>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["bob"] = LLSD::emptyMap(); + v["cam"] = 1.23; + ensureParse( + "map with map of html", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<key>bob</key>" + "<map>" + "<html><body>ha ha</body></html>" + "</map>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD(); + v[2] = 1.23; + + ensureParse( + "array value of html", + "<llsd><array>" + "<integer>23</integer>" + "<html><body>ha ha</body></html>" + "<real>1.23</real>" + "</array></llsd>", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD::emptyMap(); + v[2] = 1.23; + ensureParse( + "array with map of html", + "<llsd><array>" + "<integer>23</integer>" + "<map>" + "<html><body>ha ha</body></html>" + "</map>" + "<real>1.23</real>" + "</array></llsd>", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<4>() + { + // test handling of binary object in XML + std::string xml; + LLSD expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + expected = string_to_vector("hello"); + xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; + ensureParse( + "the word 'hello' packed in binary encoded base64", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; + xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; + xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; + xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; + xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + } template<> template<> void TestLLSDXMLParsingObject::test<5>() @@ -858,272 +858,272 @@ namespace tut } - /* - TODO: - test XML parsing - binary with unrecognized encoding - nested LLSD tags - multiple values inside an LLSD - */ - - - /** - * @class TestLLSDNotationParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDNotationParsing : public TestLLSDParsing<LLSDNotationParser> - { - public: - TestLLSDNotationParsing() {} - }; - - typedef tut::test_group<TestLLSDNotationParsing> TestLLSDNotationParsingGroup; - typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; - TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( - "llsd notation parsing"); - - template<> template<> - void TestLLSDNotationParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed notation map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad notation noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<2>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<3>() - { - LLSD val = false; - ensureParse("valid boolean false 0", "false", val, 1); - ensureParse("valid boolean false 1", "f", val, 1); - ensureParse("valid boolean false 2", "0", val, 1); - ensureParse("valid boolean false 3", "F", val, 1); - ensureParse("valid boolean false 4", "FALSE", val, 1); - val = true; - ensureParse("valid boolean true 0", "true", val, 1); - ensureParse("valid boolean true 1", "t", val, 1); - ensureParse("valid boolean true 2", "1", val, 1); - ensureParse("valid boolean true 3", "T", val, 1); - ensureParse("valid boolean true 4", "TRUE", val, 1); - - val.clear(); - ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<4>() - { - LLSD val = 123; - ensureParse("valid integer", "i123", val, 1); - val.clear(); - ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<5>() - { - LLSD val = 456.7; - ensureParse("valid real", "r456.7", val, 1); - val.clear(); - ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<6>() - { - LLUUID id; - LLSD val = id; - ensureParse( - "unparseable uuid", - "u123", - LLSD(), - LLSDParser::PARSE_FAILURE); - id.generate(); - val = id; - std::string uuid_str("u"); - uuid_str += id.asString(); - ensureParse("valid uuid", uuid_str.c_str(), val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<7>() - { - LLSD val = std::string("foolish"); - ensureParse("valid string 1", "\"foolish\"", val, 1); - val = std::string("g'day"); - ensureParse("valid string 2", "\"g'day\"", val, 1); - val = std::string("have a \"nice\" day"); - ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); - val = std::string("whatever"); - ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<8>() - { - ensureParse( - "invalid string 1", - "s(7)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid string 2", - "s(9)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<9>() - { - LLSD val = LLURI("http://www.google.com"); - ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<10>() - { - LLSD val = LLDate("2007-12-28T09:22:53.10Z"); - ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<11>() - { - std::vector<U8> vec; - vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); - vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); - LLSD val = vec; - ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); - ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); - ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<12>() - { - ensureParse( - "invalid -- binary length specified too long", - "b(7)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid -- binary length specified way too long", - "b(1000000)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<13>() - { - LLSD val; - val["amy"] = 23; - val["bob"] = LLSD(); - val["cam"] = 1.23; - ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); - - val["bob"] = LLSD::emptyMap(); - val["bob"]["vehicle"] = std::string("bicycle"); - ensureParse( - "nested map", - "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", - val, - 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<14>() - { - LLSD val; - val.append(23); - val.append(LLSD()); - val.append(1.23); - ensureParse("simple array", "[i23,!,r1.23]", val, 4); - val[1] = LLSD::emptyArray(); - val[1].append("bicycle"); - ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<15>() - { - LLSD val; - val["amy"] = 23; - val["bob"]["dogs"] = LLSD::emptyArray(); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][0]["name"] = std::string("groove"); - val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][1]["name"] = std::string("greyley"); - val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); - val["cam"] = 1.23; - ensureParse( - "nested notation", - "{'amy':i23," - " 'bob':{'dogs':[" - "{'name':'groove', 'breed':'samoyed'}," - "{'name':'greyley', 'breed':'chow/husky'}]}," - " 'cam':r1.23}", - val, - 11); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<16>() - { - // text to make sure that incorrect sizes bail because - std::string bad_str("s(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_str, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<17>() - { - // text to make sure that incorrect sizes bail because - std::string bad_bin("b(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_bin, - LLSD(), - LLSDParser::PARSE_FAILURE); - } + /* + TODO: + test XML parsing + binary with unrecognized encoding + nested LLSD tags + multiple values inside an LLSD + */ + + + /** + * @class TestLLSDNotationParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDNotationParsing : public TestLLSDParsing<LLSDNotationParser> + { + public: + TestLLSDNotationParsing() {} + }; + + typedef tut::test_group<TestLLSDNotationParsing> TestLLSDNotationParsingGroup; + typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; + TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( + "llsd notation parsing"); + + template<> template<> + void TestLLSDNotationParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed notation map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad notation noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<2>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<3>() + { + LLSD val = false; + ensureParse("valid boolean false 0", "false", val, 1); + ensureParse("valid boolean false 1", "f", val, 1); + ensureParse("valid boolean false 2", "0", val, 1); + ensureParse("valid boolean false 3", "F", val, 1); + ensureParse("valid boolean false 4", "FALSE", val, 1); + val = true; + ensureParse("valid boolean true 0", "true", val, 1); + ensureParse("valid boolean true 1", "t", val, 1); + ensureParse("valid boolean true 2", "1", val, 1); + ensureParse("valid boolean true 3", "T", val, 1); + ensureParse("valid boolean true 4", "TRUE", val, 1); + + val.clear(); + ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<4>() + { + LLSD val = 123; + ensureParse("valid integer", "i123", val, 1); + val.clear(); + ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<5>() + { + LLSD val = 456.7; + ensureParse("valid real", "r456.7", val, 1); + val.clear(); + ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<6>() + { + LLUUID id; + LLSD val = id; + ensureParse( + "unparseable uuid", + "u123", + LLSD(), + LLSDParser::PARSE_FAILURE); + id.generate(); + val = id; + std::string uuid_str("u"); + uuid_str += id.asString(); + ensureParse("valid uuid", uuid_str.c_str(), val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<7>() + { + LLSD val = std::string("foolish"); + ensureParse("valid string 1", "\"foolish\"", val, 1); + val = std::string("g'day"); + ensureParse("valid string 2", "\"g'day\"", val, 1); + val = std::string("have a \"nice\" day"); + ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); + val = std::string("whatever"); + ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<8>() + { + ensureParse( + "invalid string 1", + "s(7)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid string 2", + "s(9)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<9>() + { + LLSD val = LLURI("http://www.google.com"); + ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<10>() + { + LLSD val = LLDate("2007-12-28T09:22:53.10Z"); + ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<11>() + { + std::vector<U8> vec; + vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); + vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); + LLSD val = vec; + ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); + ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); + ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<12>() + { + ensureParse( + "invalid -- binary length specified too long", + "b(7)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid -- binary length specified way too long", + "b(1000000)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<13>() + { + LLSD val; + val["amy"] = 23; + val["bob"] = LLSD(); + val["cam"] = 1.23; + ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); + + val["bob"] = LLSD::emptyMap(); + val["bob"]["vehicle"] = std::string("bicycle"); + ensureParse( + "nested map", + "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", + val, + 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<14>() + { + LLSD val; + val.append(23); + val.append(LLSD()); + val.append(1.23); + ensureParse("simple array", "[i23,!,r1.23]", val, 4); + val[1] = LLSD::emptyArray(); + val[1].append("bicycle"); + ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<15>() + { + LLSD val; + val["amy"] = 23; + val["bob"]["dogs"] = LLSD::emptyArray(); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][0]["name"] = std::string("groove"); + val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][1]["name"] = std::string("greyley"); + val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); + val["cam"] = 1.23; + ensureParse( + "nested notation", + "{'amy':i23," + " 'bob':{'dogs':[" + "{'name':'groove', 'breed':'samoyed'}," + "{'name':'greyley', 'breed':'chow/husky'}]}," + " 'cam':r1.23}", + val, + 11); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<16>() + { + // text to make sure that incorrect sizes bail because + std::string bad_str("s(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_str, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<17>() + { + // text to make sure that incorrect sizes bail because + std::string bad_bin("b(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_bin, + LLSD(), + LLSDParser::PARSE_FAILURE); + } template<> template<> void TestLLSDNotationParsingObject::test<18>() { - LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; - LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; + LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; + LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; LLSD deep = LLSD::emptyMap(); deep["level_0"] = level_0; @@ -1168,7 +1168,7 @@ namespace tut template<> template<> void TestLLSDNotationParsingObject::test<20>() { - LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; + LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; LLSD level_49 = LLSD::emptyMap(); level_49["level_49"] = end; LLSD level_48 = LLSD::emptyMap(); level_48["level_48"] = level_49; @@ -1259,536 +1259,536 @@ namespace tut 9); } - /** - * @class TestLLSDBinaryParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDBinaryParsing : public TestLLSDParsing<LLSDBinaryParser> - { - public: - TestLLSDBinaryParsing() {} - }; - - typedef tut::test_group<TestLLSDBinaryParsing> TestLLSDBinaryParsingGroup; - typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; - TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( - "llsd binary parsing"); - - template<> template<> - void TestLLSDBinaryParsingObject::test<1>() - { - std::vector<U8> vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - std::string string_expected((char*)&vec[0], vec.size()); - LLSD value = string_expected; - - vec.resize(11); - vec[0] = 's'; // for string - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct string parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<2>() - { - std::vector<U8> vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - LLSD value = vec; - - vec.resize(11); - vec[0] = 'b'; // for binary - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct binary parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 1", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 2", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<3>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed binary map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - template<> template<> - void TestLLSDBinaryParsingObject::test<4>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<5>() - { - LLSD val = false; - ensureParse("valid boolean false 2", "0", val, 1); - val = true; - ensureParse("valid boolean true 2", "1", val, 1); - - val.clear(); - ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<6>() - { - std::vector<U8> vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('k'); - int key_size_loc = vec.size(); - size = htonl(1); // 1 too short - vec.resize(vec.size() + 4); - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); - vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid key size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing '}') - size = htonl(3); // correct size - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "valid key size, unterminated map", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val["amy"] = 23; - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid map", - str_good, - val, - 2); - - // check w/ incorrect sizes and correct map termination - size = htonl(0); // 1 too few (for the map entry) - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too long", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(2); // 1 too many - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_4((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too short", - str_bad_4, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<7>() - { - std::vector<U8> vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); // 1 too short - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); - vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid array size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing ']') - size = htonl(2); // correct size - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "unterminated array", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val.append("amy"); - val.append(23); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid array", - str_good, - val, - 3); - - // check with too many elements - size = htonl(3); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "array too short", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<8>() - { - std::vector<U8> vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyMap(); - ensureParse( - "empty map", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<9>() - { - std::vector<U8> vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyArray(); - ensureParse( - "empty array", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<10>() - { - std::vector<U8> vec; - vec.push_back('l'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(14); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); - vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); - vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); - vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); - vec.push_back('m'); - std::string str_bad((char*)&vec[0], vec.size()); - ensureParse( - "invalid uri length size", - str_bad, - LLSD(), - LLSDParser::PARSE_FAILURE); - - LLSD val; - val = LLURI("http://sl.com"); - size = htonl(13); // correct length - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid key size", - str_good, - val, - 1); - } + /** + * @class TestLLSDBinaryParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDBinaryParsing : public TestLLSDParsing<LLSDBinaryParser> + { + public: + TestLLSDBinaryParsing() {} + }; + + typedef tut::test_group<TestLLSDBinaryParsing> TestLLSDBinaryParsingGroup; + typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; + TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( + "llsd binary parsing"); + + template<> template<> + void TestLLSDBinaryParsingObject::test<1>() + { + std::vector<U8> vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + std::string string_expected((char*)&vec[0], vec.size()); + LLSD value = string_expected; + + vec.resize(11); + vec[0] = 's'; // for string + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct string parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<2>() + { + std::vector<U8> vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + LLSD value = vec; + + vec.resize(11); + vec[0] = 'b'; // for binary + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct binary parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 1", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 2", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<3>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed binary map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + template<> template<> + void TestLLSDBinaryParsingObject::test<4>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<5>() + { + LLSD val = false; + ensureParse("valid boolean false 2", "0", val, 1); + val = true; + ensureParse("valid boolean true 2", "1", val, 1); + + val.clear(); + ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<6>() + { + std::vector<U8> vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('k'); + int key_size_loc = vec.size(); + size = htonl(1); // 1 too short + vec.resize(vec.size() + 4); + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); + vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid key size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing '}') + size = htonl(3); // correct size + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "valid key size, unterminated map", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val["amy"] = 23; + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid map", + str_good, + val, + 2); + + // check w/ incorrect sizes and correct map termination + size = htonl(0); // 1 too few (for the map entry) + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too long", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(2); // 1 too many + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_4((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too short", + str_bad_4, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<7>() + { + std::vector<U8> vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); // 1 too short + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); + vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid array size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing ']') + size = htonl(2); // correct size + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "unterminated array", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val.append("amy"); + val.append(23); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid array", + str_good, + val, + 3); + + // check with too many elements + size = htonl(3); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "array too short", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<8>() + { + std::vector<U8> vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyMap(); + ensureParse( + "empty map", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<9>() + { + std::vector<U8> vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyArray(); + ensureParse( + "empty array", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<10>() + { + std::vector<U8> vec; + vec.push_back('l'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(14); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); + vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); + vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); + vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); + vec.push_back('m'); + std::string str_bad((char*)&vec[0], vec.size()); + ensureParse( + "invalid uri length size", + str_bad, + LLSD(), + LLSDParser::PARSE_FAILURE); + + LLSD val; + val = LLURI("http://sl.com"); + size = htonl(13); // correct length + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid key size", + str_good, + val, + 1); + } /* - template<> template<> - void TestLLSDBinaryParsingObject::test<11>() - { - } + template<> template<> + void TestLLSDBinaryParsingObject::test<11>() + { + } */ /** - * @class TestLLSDCrossCompatible - * @brief Miscellaneous serialization and parsing tests - */ - class TestLLSDCrossCompatible - { - public: - TestLLSDCrossCompatible() {} - - void ensureBinaryAndNotation( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation binary count", - count2, - count1); - - // to notation and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndNotation notation count1", - count3, - count2); - LLSD actual_value_notation; - S32 count4 = LLSDSerialize::fromNotation( - actual_value_notation, - str2, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation notation count2", - count4, - count3); - ensure_equals( - (msg + " (binaryandnotation)").c_str(), - actual_value_notation, - input); - } - - void ensureBinaryAndXML( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndXML binary count", - count2, - count1); - - // to xml and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndXML xml count1", - count3, - count2); - LLSD actual_value_xml; - S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); - ensure_equals( - "ensureBinaryAndXML xml count2", - count4, - count3); - ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); - } - }; - - typedef tut::test_group<TestLLSDCrossCompatible> TestLLSDCompatibleGroup; - typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; - TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( - "llsd serialize compatible"); - - template<> template<> - void TestLLSDCompatibleObject::test<1>() - { - LLSD test; - ensureBinaryAndNotation("undef", test); - ensureBinaryAndXML("undef", test); - test = true; - ensureBinaryAndNotation("boolean true", test); - ensureBinaryAndXML("boolean true", test); - test = false; - ensureBinaryAndNotation("boolean false", test); - ensureBinaryAndXML("boolean false", test); - test = 0; - ensureBinaryAndNotation("integer zero", test); - ensureBinaryAndXML("integer zero", test); - test = 1; - ensureBinaryAndNotation("integer positive", test); - ensureBinaryAndXML("integer positive", test); - test = -234567; - ensureBinaryAndNotation("integer negative", test); - ensureBinaryAndXML("integer negative", test); - test = 0.0; - ensureBinaryAndNotation("real zero", test); - ensureBinaryAndXML("real zero", test); - test = 1.0; - ensureBinaryAndNotation("real positive", test); - ensureBinaryAndXML("real positive", test); - test = -1.0; - ensureBinaryAndNotation("real negative", test); - ensureBinaryAndXML("real negative", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<2>() - { - LLSD test; - test = "foobar"; - ensureBinaryAndNotation("string", test); - ensureBinaryAndXML("string", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<3>() - { - LLSD test; - LLUUID id; - id.generate(); - test = id; - ensureBinaryAndNotation("uuid", test); - ensureBinaryAndXML("uuid", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<4>() - { - LLSD test; - test = LLDate(12345.0); - ensureBinaryAndNotation("date", test); - ensureBinaryAndXML("date", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<5>() - { - LLSD test; - test = LLURI("http://www.secondlife.com/"); - ensureBinaryAndNotation("uri", test); - ensureBinaryAndXML("uri", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<6>() - { - LLSD test; - typedef std::vector<U8> buf_t; - buf_t val; - for(int ii = 0; ii < 100; ++ii) - { - srand(ii); /* Flawfinder: ignore */ - S32 size = rand() % 100 + 10; - std::generate_n( - std::back_insert_iterator<buf_t>(val), - size, - rand); - } - test = val; - ensureBinaryAndNotation("binary", test); - ensureBinaryAndXML("binary", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<7>() - { - LLSD test; - test = LLSD::emptyArray(); - test.append(1); - test.append("hello"); - ensureBinaryAndNotation("array", test); - ensureBinaryAndXML("array", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<8>() - { - LLSD test; - test = LLSD::emptyArray(); - test["foo"] = "bar"; - test["baz"] = 100; - ensureBinaryAndNotation("map", test); - ensureBinaryAndXML("map", test); - } + * @class TestLLSDCrossCompatible + * @brief Miscellaneous serialization and parsing tests + */ + class TestLLSDCrossCompatible + { + public: + TestLLSDCrossCompatible() {} + + void ensureBinaryAndNotation( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation binary count", + count2, + count1); + + // to notation and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndNotation notation count1", + count3, + count2); + LLSD actual_value_notation; + S32 count4 = LLSDSerialize::fromNotation( + actual_value_notation, + str2, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation notation count2", + count4, + count3); + ensure_equals( + (msg + " (binaryandnotation)").c_str(), + actual_value_notation, + input); + } + + void ensureBinaryAndXML( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndXML binary count", + count2, + count1); + + // to xml and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndXML xml count1", + count3, + count2); + LLSD actual_value_xml; + S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); + ensure_equals( + "ensureBinaryAndXML xml count2", + count4, + count3); + ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); + } + }; + + typedef tut::test_group<TestLLSDCrossCompatible> TestLLSDCompatibleGroup; + typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; + TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( + "llsd serialize compatible"); + + template<> template<> + void TestLLSDCompatibleObject::test<1>() + { + LLSD test; + ensureBinaryAndNotation("undef", test); + ensureBinaryAndXML("undef", test); + test = true; + ensureBinaryAndNotation("boolean true", test); + ensureBinaryAndXML("boolean true", test); + test = false; + ensureBinaryAndNotation("boolean false", test); + ensureBinaryAndXML("boolean false", test); + test = 0; + ensureBinaryAndNotation("integer zero", test); + ensureBinaryAndXML("integer zero", test); + test = 1; + ensureBinaryAndNotation("integer positive", test); + ensureBinaryAndXML("integer positive", test); + test = -234567; + ensureBinaryAndNotation("integer negative", test); + ensureBinaryAndXML("integer negative", test); + test = 0.0; + ensureBinaryAndNotation("real zero", test); + ensureBinaryAndXML("real zero", test); + test = 1.0; + ensureBinaryAndNotation("real positive", test); + ensureBinaryAndXML("real positive", test); + test = -1.0; + ensureBinaryAndNotation("real negative", test); + ensureBinaryAndXML("real negative", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<2>() + { + LLSD test; + test = "foobar"; + ensureBinaryAndNotation("string", test); + ensureBinaryAndXML("string", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<3>() + { + LLSD test; + LLUUID id; + id.generate(); + test = id; + ensureBinaryAndNotation("uuid", test); + ensureBinaryAndXML("uuid", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<4>() + { + LLSD test; + test = LLDate(12345.0); + ensureBinaryAndNotation("date", test); + ensureBinaryAndXML("date", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<5>() + { + LLSD test; + test = LLURI("http://www.secondlife.com/"); + ensureBinaryAndNotation("uri", test); + ensureBinaryAndXML("uri", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<6>() + { + LLSD test; + typedef std::vector<U8> buf_t; + buf_t val; + for(int ii = 0; ii < 100; ++ii) + { + srand(ii); /* Flawfinder: ignore */ + S32 size = rand() % 100 + 10; + std::generate_n( + std::back_insert_iterator<buf_t>(val), + size, + rand); + } + test = val; + ensureBinaryAndNotation("binary", test); + ensureBinaryAndXML("binary", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<7>() + { + LLSD test; + test = LLSD::emptyArray(); + test.append(1); + test.append("hello"); + ensureBinaryAndNotation("array", test); + ensureBinaryAndXML("array", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<8>() + { + LLSD test; + test = LLSD::emptyArray(); + test["foo"] = "bar"; + test["baz"] = 100; + ensureBinaryAndNotation("map", test); + ensureBinaryAndXML("map", test); + } // helper for TestPythonCompatible static std::string import_llsd("import os.path\n" @@ -1921,12 +1921,12 @@ namespace tut int bufflen{ static_cast<int>(buffstr.length()) }; out.write(reinterpret_cast<const char*>(&bufflen), sizeof(bufflen)); LL_DEBUGS() << "Wrote length: " - << hexdump(reinterpret_cast<const char*>(&bufflen), - sizeof(bufflen)) + << LL::hexdump(reinterpret_cast<const char*>(&bufflen), + sizeof(bufflen)) << LL_ENDL; out.write(buffstr.c_str(), buffstr.length()); LL_DEBUGS() << "Wrote data: " - << hexmix(buffstr.c_str(), buffstr.length()) + << LL::hexmix(buffstr.c_str(), buffstr.length()) << LL_ENDL; } } @@ -2130,7 +2130,7 @@ namespace tut item.asReal(), 3.14, 7); // 7 bits ~= 0.01 ensure("Failed to read LLSD::String from Python", itemFromStream(inf, item, parse)); - ensure_equals(item.asString(), + ensure_equals(item.asString(), "This string\n" "has several\n" "lines."); diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index 302bbe6f8d..edccdb097b 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-21 * @brief Implementation for threadpool. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ @@ -18,6 +18,7 @@ // external library headers // other Linden headers #include "commoncontrol.h" +#include "llcoros.h" #include "llerror.h" #include "llevents.h" #include "llsd.h" @@ -90,20 +91,14 @@ void LL::ThreadPoolBase::start() return; } - // Listen on "LLApp", and when the app is shutting down, close the queue - // and join the workers. - LLEventPumps::instance().obtain("LLApp").listen( + // When the app is shutting down, close the queue and join the workers. + mStopListener = LLCoros::getStopListener( mName, - [this](const LLSD& stat) + [this](const LLSD& status) { - std::string status(stat["status"]); - if (status != "running") - { - // viewer is starting shutdown -- proclaim the end is nigh! - LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL; - close(); - } - return false; + // viewer is starting shutdown -- proclaim the end is nigh! + LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL; + close(); }); } diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index 0eb1891754..7ced7fbf9f 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -4,7 +4,7 @@ * @date 2021-10-21 * @brief ThreadPool configures a WorkQueue along with a pool of threads to * service it. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ @@ -13,6 +13,7 @@ #if ! defined(LL_THREADPOOL_H) #define LL_THREADPOOL_H +#include "llcoros.h" #include "threadpool_fwd.h" #include "workqueue.h" #include <memory> // std::unique_ptr @@ -52,8 +53,8 @@ namespace LL void start(); /** - * ThreadPool listens for application shutdown messages on the "LLApp" - * LLEventPump. Call close() to shut down this ThreadPool early. + * ThreadPool listens for application shutdown events. Call close() to + * shut down this ThreadPool early. */ virtual void close(); @@ -95,6 +96,7 @@ namespace LL std::string mName; size_t mThreadCount; + LLTempBoundListener mStopListener; }; /** diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index 6066e74fb5..800547084a 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-06 * @brief Implementation for WorkQueue. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ @@ -32,8 +32,11 @@ using Lock = LLCoros::LockType; LL::WorkQueueBase::WorkQueueBase(const std::string& name): super(makeName(name)) { - // TODO: register for "LLApp" events so we can implicitly close() on - // viewer shutdown. + // Register for status change events so we'll implicitly close() on viewer + // shutdown. + mStopListener = LLCoros::getStopListener( + "WorkQueue:" + getKey(), + [this](const LLSD&){ close(); }); } void LL::WorkQueueBase::runUntilClose() diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index 9d7bbfbf7a..4c46290f2a 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-30 * @brief Queue used for inter-thread work passing. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ @@ -13,6 +13,7 @@ #define LL_WORKQUEUE_H #include "llcoros.h" +#include "llevents.h" #include "llexception.h" #include "llinstancetracker.h" #include "llinstancetrackersubclass.h" @@ -194,6 +195,8 @@ namespace LL static std::string makeName(const std::string& name); void callWork(const Work& work); + LLTempBoundListener mStopListener; + private: virtual Work pop_() = 0; virtual bool tryPop_(Work&) = 0; diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index cbf4c1ffb8..750d4e21b9 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldir.cpp * @brief implementation of directory utilities base class * * $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$ */ @@ -37,7 +37,7 @@ #include "lldir.h" #include "llerror.h" -#include "lltimer.h" // ms_sleep() +#include "lltimer.h" // ms_sleep() #include "lluuid.h" #include "lldiriterator.h" @@ -69,28 +69,28 @@ LLDir *gDirUtilp = (LLDir *)&gDirUtil; /// Values for findSkinnedFilenames(subdir) parameter const char - *LLDir::XUI = "xui", - *LLDir::TEXTURES = "textures", - *LLDir::SKINBASE = ""; + *LLDir::XUI = "xui", + *LLDir::TEXTURES = "textures", + *LLDir::SKINBASE = ""; static const char* const empty = ""; std::string LLDir::sDumpDir = ""; LLDir::LLDir() -: mAppName(""), - mExecutablePathAndName(""), - mExecutableFilename(""), - mExecutableDir(""), - mAppRODataDir(""), - mOSUserDir(""), - mOSUserAppDir(""), - mLindenUserDir(""), - mOSCacheDir(""), - mCAFile(""), - mTempDir(""), - mDirDelimiter("/"), // fallback to forward slash if not overridden - mLanguage("en"), - mUserName("undefined") +: mAppName(""), + mExecutablePathAndName(""), + mExecutableFilename(""), + mExecutableDir(""), + mAppRODataDir(""), + mOSUserDir(""), + mOSUserAppDir(""), + mLindenUserDir(""), + mOSCacheDir(""), + mCAFile(""), + mTempDir(""), + mDirDelimiter("/"), // fallback to forward slash if not overridden + mLanguage("en"), + mUserName("undefined") { } @@ -109,7 +109,7 @@ std::vector<std::string> LLDir::getFilesInDir(const std::string &dirname) #endif std::vector<std::string> v; - + if (exists(p)) { if (is_directory(p)) @@ -127,188 +127,188 @@ std::vector<std::string> LLDir::getFilesInDir(const std::string &dirname) } } return v; -} - +} + S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { - S32 count = 0; - std::string filename; - std::string fullpath; - S32 result; - - // File masks starting with "/" will match nothing, so we consider them invalid. - if (LLStringUtil::startsWith(mask, getDirDelimiter())) - { - LL_WARNS() << "Invalid file mask: " << mask << LL_ENDL; - llassert(!"Invalid file mask"); - } - - LLDirIterator iter(dirname, mask); - while (iter.next(filename)) - { - fullpath = add(dirname, filename); - - if(LLFile::isdir(fullpath)) - { - // skipping directory traversal filenames - count++; - continue; - } - - S32 retry_count = 0; - while (retry_count < 5) - { - if (0 != LLFile::remove(fullpath)) - { - retry_count++; - result = errno; - LL_WARNS() << "Problem removing " << fullpath << " - errorcode: " - << result << " attempt " << retry_count << LL_ENDL; - - if(retry_count >= 5) - { - LL_WARNS() << "Failed to remove " << fullpath << LL_ENDL ; - return count ; - } - - ms_sleep(100); - } - else - { - if (retry_count) - { - LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL; - } - break; - } - } - count++; - } - return count; + S32 count = 0; + std::string filename; + std::string fullpath; + S32 result; + + // File masks starting with "/" will match nothing, so we consider them invalid. + if (LLStringUtil::startsWith(mask, getDirDelimiter())) + { + LL_WARNS() << "Invalid file mask: " << mask << LL_ENDL; + llassert(!"Invalid file mask"); + } + + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) + { + fullpath = add(dirname, filename); + + if(LLFile::isdir(fullpath)) + { + // skipping directory traversal filenames + count++; + continue; + } + + S32 retry_count = 0; + while (retry_count < 5) + { + if (0 != LLFile::remove(fullpath)) + { + retry_count++; + result = errno; + LL_WARNS() << "Problem removing " << fullpath << " - errorcode: " + << result << " attempt " << retry_count << LL_ENDL; + + if(retry_count >= 5) + { + LL_WARNS() << "Failed to remove " << fullpath << LL_ENDL ; + return count ; + } + + ms_sleep(100); + } + else + { + if (retry_count) + { + LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL; + } + break; + } + } + count++; + } + return count; } U32 LLDir::deleteDirAndContents(const std::string& dir_name) { //Removes the directory and its contents. Returns number of files deleted. + + U32 num_deleted = 0; - U32 num_deleted = 0; - - try - { + try + { #ifdef LL_WINDOWS // or BOOST_WINDOWS_API - boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name)); + boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name)); #else - boost::filesystem::path dir_path(dir_name); + boost::filesystem::path dir_path(dir_name); #endif - if (boost::filesystem::exists (dir_path)) - { - if (!boost::filesystem::is_empty (dir_path)) - { // Directory has content - num_deleted = boost::filesystem::remove_all (dir_path); - } - else - { // Directory is empty - boost::filesystem::remove (dir_path); - } - } - } - catch (boost::filesystem::filesystem_error &er) - { - LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; - } - return num_deleted; -} - -const std::string LLDir::findFile(const std::string &filename, - const std::string& searchPath1, - const std::string& searchPath2, - const std::string& searchPath3) const -{ - std::vector<std::string> search_paths; - search_paths.push_back(searchPath1); - search_paths.push_back(searchPath2); - search_paths.push_back(searchPath3); - return findFile(filename, search_paths); + if (boost::filesystem::exists (dir_path)) + { + if (!boost::filesystem::is_empty (dir_path)) + { // Directory has content + num_deleted = boost::filesystem::remove_all (dir_path); + } + else + { // Directory is empty + boost::filesystem::remove (dir_path); + } + } + } + catch (boost::filesystem::filesystem_error &er) + { + LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; + } + return num_deleted; +} + +const std::string LLDir::findFile(const std::string &filename, + const std::string& searchPath1, + const std::string& searchPath2, + const std::string& searchPath3) const +{ + std::vector<std::string> search_paths; + search_paths.push_back(searchPath1); + search_paths.push_back(searchPath2); + search_paths.push_back(searchPath3); + return findFile(filename, search_paths); } const std::string LLDir::findFile(const std::string& filename, const std::vector<std::string> search_paths) const { - std::vector<std::string>::const_iterator search_path_iter; - for (search_path_iter = search_paths.begin(); - search_path_iter != search_paths.end(); - ++search_path_iter) - { - if (!search_path_iter->empty()) - { - std::string filename_and_path = (*search_path_iter); - if (!filename.empty()) - { - filename_and_path += getDirDelimiter() + filename; - } - if (fileExists(filename_and_path)) - { - return filename_and_path; - } - } - } - return ""; + std::vector<std::string>::const_iterator search_path_iter; + for (search_path_iter = search_paths.begin(); + search_path_iter != search_paths.end(); + ++search_path_iter) + { + if (!search_path_iter->empty()) + { + std::string filename_and_path = (*search_path_iter); + if (!filename.empty()) + { + filename_and_path += getDirDelimiter() + filename; + } + if (fileExists(filename_and_path)) + { + return filename_and_path; + } + } + } + return ""; } const std::string &LLDir::getExecutablePathAndName() const { - return mExecutablePathAndName; + return mExecutablePathAndName; } const std::string &LLDir::getExecutableFilename() const { - return mExecutableFilename; + return mExecutableFilename; } const std::string &LLDir::getExecutableDir() const { - return mExecutableDir; + return mExecutableDir; } const std::string &LLDir::getWorkingDir() const { - return mWorkingDir; + return mWorkingDir; } const std::string &LLDir::getAppName() const { - return mAppName; + return mAppName; } const std::string &LLDir::getAppRODataDir() const { - return mAppRODataDir; + return mAppRODataDir; } const std::string &LLDir::getOSUserDir() const { - return mOSUserDir; + return mOSUserDir; } const std::string &LLDir::getOSUserAppDir() const { - return mOSUserAppDir; + return mOSUserAppDir; } const std::string &LLDir::getLindenUserDir() const { - if (mLindenUserDir.empty()) - { - LL_DEBUGS() << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << LL_ENDL; - } + if (mLindenUserDir.empty()) + { + LL_DEBUGS() << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << LL_ENDL; + } - return mLindenUserDir; + return mLindenUserDir; } const std::string& LLDir::getChatLogsDir() const { - return mChatLogsDir; + return mChatLogsDir; } void LLDir::setDumpDir( const std::string& path ) @@ -326,14 +326,14 @@ const std::string &LLDir::getDumpDir() const { LLUUID uid; uid.generate(); - + sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "dump-" + uid.asString(); - dir_exists_or_crash(sDumpDir); + dir_exists_or_crash(sDumpDir); } - return LLDir::sDumpDir; + return LLDir::sDumpDir; } bool LLDir::dumpDirExists() const @@ -343,80 +343,80 @@ bool LLDir::dumpDirExists() const const std::string &LLDir::getPerAccountChatLogsDir() const { - return mPerAccountChatLogsDir; + return mPerAccountChatLogsDir; } const std::string &LLDir::getTempDir() const { - return mTempDir; + return mTempDir; } const std::string LLDir::getCacheDir(bool get_default) const { - if (mCacheDir.empty() || get_default) - { - if (!mDefaultCacheDir.empty()) - { // Set at startup - can't set here due to const API - return mDefaultCacheDir; - } - - std::string res = buildSLOSCacheDir(); - return res; - } - else - { - return mCacheDir; - } + if (mCacheDir.empty() || get_default) + { + if (!mDefaultCacheDir.empty()) + { // Set at startup - can't set here due to const API + return mDefaultCacheDir; + } + + std::string res = buildSLOSCacheDir(); + return res; + } + else + { + return mCacheDir; + } } // Return the default cache directory std::string LLDir::buildSLOSCacheDir() const { - std::string res; - if (getOSCacheDir().empty()) - { - if (getOSUserAppDir().empty()) - { - res = "data"; - } - else - { - res = add(getOSUserAppDir(), "cache"); - } - } - else - { - res = add(getOSCacheDir(), "SecondLife"); - } - return res; + std::string res; + if (getOSCacheDir().empty()) + { + if (getOSUserAppDir().empty()) + { + res = "data"; + } + else + { + res = add(getOSUserAppDir(), "cache"); + } + } + else + { + res = add(getOSCacheDir(), "SecondLife"); + } + return res; } const std::string &LLDir::getOSCacheDir() const { - return mOSCacheDir; + return mOSCacheDir; } const std::string &LLDir::getCAFile() const { - return mCAFile; + return mCAFile; } const std::string &LLDir::getDirDelimiter() const { - return mDirDelimiter; + return mDirDelimiter; } const std::string& LLDir::getDefaultSkinDir() const { - return mDefaultSkinDir; + return mDefaultSkinDir; } const std::string &LLDir::getSkinDir() const { - return mSkinDir; + return mSkinDir; } const std::string &LLDir::getUserDefaultSkinDir() const @@ -426,258 +426,263 @@ const std::string &LLDir::getUserDefaultSkinDir() const const std::string &LLDir::getUserSkinDir() const { - return mUserSkinDir; + return mUserSkinDir; } const std::string LLDir::getSkinBaseDir() const { - return mSkinBaseDir; + return mSkinBaseDir; } const std::string &LLDir::getLLPluginDir() const { - return mLLPluginDir; + return mLLPluginDir; } const std::string &LLDir::getUserName() const { - return mUserName; + return mUserName; } static std::string ELLPathToString(ELLPath location) { - typedef std::map<ELLPath, const char*> ELLPathMap; + typedef std::map<ELLPath, const char*> ELLPathMap; #define ENT(symbol) (symbol, #symbol) - static const ELLPathMap sMap = map_list_of - ENT(LL_PATH_NONE) - ENT(LL_PATH_USER_SETTINGS) - ENT(LL_PATH_APP_SETTINGS) - ENT(LL_PATH_PER_SL_ACCOUNT) // returns/expands to blank string if we don't know the account name yet - ENT(LL_PATH_CACHE) - ENT(LL_PATH_CHARACTER) - ENT(LL_PATH_HELP) - ENT(LL_PATH_LOGS) - ENT(LL_PATH_TEMP) - ENT(LL_PATH_SKINS) - ENT(LL_PATH_TOP_SKIN) - ENT(LL_PATH_CHAT_LOGS) - ENT(LL_PATH_PER_ACCOUNT_CHAT_LOGS) - ENT(LL_PATH_USER_SKIN) - ENT(LL_PATH_LOCAL_ASSETS) - ENT(LL_PATH_EXECUTABLE) - ENT(LL_PATH_DEFAULT_SKIN) - ENT(LL_PATH_FONTS) - ENT(LL_PATH_LAST) - ; + static const ELLPathMap sMap = map_list_of + ENT(LL_PATH_NONE) + ENT(LL_PATH_USER_SETTINGS) + ENT(LL_PATH_APP_SETTINGS) + ENT(LL_PATH_PER_SL_ACCOUNT) // returns/expands to blank string if we don't know the account name yet + ENT(LL_PATH_CACHE) + ENT(LL_PATH_CHARACTER) + ENT(LL_PATH_HELP) + ENT(LL_PATH_LOGS) + ENT(LL_PATH_TEMP) + ENT(LL_PATH_SKINS) + ENT(LL_PATH_TOP_SKIN) + ENT(LL_PATH_CHAT_LOGS) + ENT(LL_PATH_PER_ACCOUNT_CHAT_LOGS) + ENT(LL_PATH_USER_SKIN) + ENT(LL_PATH_LOCAL_ASSETS) + ENT(LL_PATH_EXECUTABLE) + ENT(LL_PATH_DEFAULT_SKIN) + ENT(LL_PATH_FONTS) + ENT(LL_PATH_LAST) + ENT(LL_PATH_SCRIPTS) + ; #undef ENT - ELLPathMap::const_iterator found = sMap.find(location); - if (found != sMap.end()) - return found->second; - return STRINGIZE("Invalid ELLPath value " << location); + ELLPathMap::const_iterator found = sMap.find(location); + if (found != sMap.end()) + return found->second; + return STRINGIZE("Invalid ELLPath value " << location); } std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const { - return getExpandedFilename(location, "", filename); + return getExpandedFilename(location, "", filename); } std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir, const std::string& filename) const { - return getExpandedFilename(location, "", subdir, filename); + return getExpandedFilename(location, "", subdir, filename); } std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir1, const std::string& subdir2, const std::string& in_filename) const { - std::string prefix; - switch (location) - { - case LL_PATH_NONE: - // Do nothing - break; - - case LL_PATH_APP_SETTINGS: - prefix = add(getAppRODataDir(), "app_settings"); - break; - - case LL_PATH_CHARACTER: - prefix = add(getAppRODataDir(), "character"); - break; - - case LL_PATH_HELP: - prefix = "help"; - break; - - case LL_PATH_CACHE: - prefix = getCacheDir(); - break; - + std::string prefix; + switch (location) + { + case LL_PATH_NONE: + // Do nothing + break; + + case LL_PATH_APP_SETTINGS: + prefix = add(getAppRODataDir(), "app_settings"); + break; + + case LL_PATH_CHARACTER: + prefix = add(getAppRODataDir(), "character"); + break; + + case LL_PATH_HELP: + prefix = "help"; + break; + + case LL_PATH_CACHE: + prefix = getCacheDir(); + break; + case LL_PATH_DUMP: prefix=getDumpDir(); break; - - case LL_PATH_USER_SETTINGS: - prefix = add(getOSUserAppDir(), "user_settings"); - break; - - case LL_PATH_PER_SL_ACCOUNT: - prefix = getLindenUserDir(); - if (prefix.empty()) - { - // if we're asking for the per-SL-account directory but we haven't - // logged in yet (or otherwise don't know the account name from - // which to build this string), then intentionally return a blank - // string to the caller and skip the below warning about a blank - // prefix. - LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: " - << ELLPathToString(location) - << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "' => ''" << LL_ENDL; - return std::string(); - } - break; - - case LL_PATH_CHAT_LOGS: - prefix = getChatLogsDir(); - break; - - case LL_PATH_PER_ACCOUNT_CHAT_LOGS: - prefix = getPerAccountChatLogsDir(); - if (prefix.empty()) - { - // potentially directory was not set yet - // intentionally return a blank string to the caller - LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL; - return std::string(); - } - break; - - case LL_PATH_LOGS: - prefix = add(getOSUserAppDir(), "logs"); - break; - - case LL_PATH_TEMP: - prefix = getTempDir(); - break; - - case LL_PATH_TOP_SKIN: - prefix = getSkinDir(); - break; - - case LL_PATH_DEFAULT_SKIN: - prefix = getDefaultSkinDir(); - break; - - case LL_PATH_USER_SKIN: - prefix = getUserSkinDir(); - break; - - case LL_PATH_SKINS: - prefix = getSkinBaseDir(); - break; - - case LL_PATH_LOCAL_ASSETS: - prefix = add(getAppRODataDir(), "local_assets"); - break; - - case LL_PATH_EXECUTABLE: - prefix = getExecutableDir(); - break; - - case LL_PATH_FONTS: - prefix = add(getAppRODataDir(), "fonts"); + + case LL_PATH_USER_SETTINGS: + prefix = add(getOSUserAppDir(), "user_settings"); + break; + + case LL_PATH_PER_SL_ACCOUNT: + prefix = getLindenUserDir(); + if (prefix.empty()) + { + // if we're asking for the per-SL-account directory but we haven't + // logged in yet (or otherwise don't know the account name from + // which to build this string), then intentionally return a blank + // string to the caller and skip the below warning about a blank + // prefix. + LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: " + << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "' => ''" << LL_ENDL; + return std::string(); + } + break; + + case LL_PATH_CHAT_LOGS: + prefix = getChatLogsDir(); + break; + + case LL_PATH_PER_ACCOUNT_CHAT_LOGS: + prefix = getPerAccountChatLogsDir(); + if (prefix.empty()) + { + // potentially directory was not set yet + // intentionally return a blank string to the caller + LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL; + return std::string(); + } + break; + + case LL_PATH_LOGS: + prefix = add(getOSUserAppDir(), "logs"); + break; + + case LL_PATH_TEMP: + prefix = getTempDir(); + break; + + case LL_PATH_TOP_SKIN: + prefix = getSkinDir(); + break; + + case LL_PATH_DEFAULT_SKIN: + prefix = getDefaultSkinDir(); + break; + + case LL_PATH_USER_SKIN: + prefix = getUserSkinDir(); + break; + + case LL_PATH_SKINS: + prefix = getSkinBaseDir(); + break; + + case LL_PATH_LOCAL_ASSETS: + prefix = add(getAppRODataDir(), "local_assets"); + break; + + case LL_PATH_EXECUTABLE: + prefix = getExecutableDir(); + break; + + case LL_PATH_FONTS: + prefix = add(getAppRODataDir(), "fonts"); + break; + + case LL_PATH_SCRIPTS: + prefix = add(getAppRODataDir(), "scripts"); break; - - default: - llassert(0); - } - - if (prefix.empty()) - { - LL_WARNS() << ELLPathToString(location) - << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "': prefix is empty, possible bad filename" << LL_ENDL; - } - - std::string expanded_filename = add(prefix, subdir1, subdir2); - if (expanded_filename.empty() && in_filename.empty()) - { - return ""; - } - // Use explicit concatenation here instead of another add() call. Callers - // passing in_filename as "" expect to obtain a pathname ending with - // mDirSeparator so they can later directly concatenate with a specific - // filename. A caller using add() doesn't care, but there's still code - // loose in the system that uses std::string::operator+(). - expanded_filename += mDirDelimiter; - expanded_filename += in_filename; - - LL_DEBUGS("LLDir") << ELLPathToString(location) - << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "' => '" << expanded_filename << "'" << LL_ENDL; - return expanded_filename; + + default: + llassert(0); + } + + if (prefix.empty()) + { + LL_WARNS() << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "': prefix is empty, possible bad filename" << LL_ENDL; + } + + std::string expanded_filename = add(prefix, subdir1, subdir2); + if (expanded_filename.empty() && in_filename.empty()) + { + return ""; + } + // Use explicit concatenation here instead of another add() call. Callers + // passing in_filename as "" expect to obtain a pathname ending with + // mDirSeparator so they can later directly concatenate with a specific + // filename. A caller using add() doesn't care, but there's still code + // loose in the system that uses std::string::operator+(). + expanded_filename += mDirDelimiter; + expanded_filename += in_filename; + + LL_DEBUGS("LLDir") << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "' => '" << expanded_filename << "'" << LL_ENDL; + return expanded_filename; } std::string LLDir::getBaseFileName(const std::string& filepath, bool strip_exten) const { - std::size_t offset = filepath.find_last_of(getDirDelimiter()); - offset = (offset == std::string::npos) ? 0 : offset+1; - std::string res = filepath.substr(offset, std::string::npos); - if (strip_exten) - { - offset = res.find_last_of('.'); - if (offset != std::string::npos && - offset != 0) // if basename STARTS with '.', don't strip - { - res = res.substr(0, offset); - } - } - return res; + std::size_t offset = filepath.find_last_of(getDirDelimiter()); + offset = (offset == std::string::npos) ? 0 : offset+1; + std::string res = filepath.substr(offset, std::string::npos); + if (strip_exten) + { + offset = res.find_last_of('.'); + if (offset != std::string::npos && + offset != 0) // if basename STARTS with '.', don't strip + { + res = res.substr(0, offset); + } + } + return res; } std::string LLDir::getDirName(const std::string& filepath) const { - std::size_t offset = filepath.find_last_of(getDirDelimiter()); - S32 len = (offset == std::string::npos) ? 0 : offset; - std::string dirname = filepath.substr(0, len); - return dirname; + std::size_t offset = filepath.find_last_of(getDirDelimiter()); + S32 len = (offset == std::string::npos) ? 0 : offset; + std::string dirname = filepath.substr(0, len); + return dirname; } std::string LLDir::getExtension(const std::string& filepath) const { - if (filepath.empty()) - return std::string(); - std::string basename = getBaseFileName(filepath, false); - std::size_t offset = basename.find_last_of('.'); - std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1); - LLStringUtil::toLower(exten); - return exten; + if (filepath.empty()) + return std::string(); + std::string basename = getBaseFileName(filepath, false); + std::size_t offset = basename.find_last_of('.'); + std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1); + LLStringUtil::toLower(exten); + return exten; } std::string LLDir::findSkinnedFilenameBaseLang(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint) const + const std::string &filename, + ESkinConstraint constraint) const { - // This implementation is basically just as described in the declaration comments. - std::vector<std::string> found(findSkinnedFilenames(subdir, filename, constraint)); - if (found.empty()) - { - return ""; - } - return found.front(); + // This implementation is basically just as described in the declaration comments. + std::vector<std::string> found(findSkinnedFilenames(subdir, filename, constraint)); + if (found.empty()) + { + return ""; + } + return found.front(); } std::string LLDir::findSkinnedFilename(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint) const + const std::string &filename, + ESkinConstraint constraint) const { - // This implementation is basically just as described in the declaration comments. - std::vector<std::string> found(findSkinnedFilenames(subdir, filename, constraint)); - if (found.empty()) - { - return ""; - } - return found.back(); + // This implementation is basically just as described in the declaration comments. + std::vector<std::string> found(findSkinnedFilenames(subdir, filename, constraint)); + if (found.empty()) + { + return ""; + } + return found.back(); } // This method exists because the two code paths for @@ -686,210 +691,210 @@ std::string LLDir::findSkinnedFilename(const std::string &subdir, // difference is in the body of the inner loop. template <typename FUNCTION> void LLDir::walkSearchSkinDirs(const std::string& subdir, - const std::vector<std::string>& subsubdirs, - const std::string& filename, - const FUNCTION& function) const -{ - for (const std::string& skindir : mSearchSkinDirs) - { - std::string subdir_path(add(skindir, subdir)); - for (const std::string& subsubdir : subsubdirs) - { - std::string full_path(add(subdir_path, subsubdir, filename)); - if (fileExists(full_path)) - { - function(subsubdir, full_path); - } - } - } + const std::vector<std::string>& subsubdirs, + const std::string& filename, + const FUNCTION& function) const +{ + for (const std::string& skindir : mSearchSkinDirs) + { + std::string subdir_path(add(skindir, subdir)); + for (const std::string& subsubdir : subsubdirs) + { + std::string full_path(add(subdir_path, subsubdir, filename)); + if (fileExists(full_path)) + { + function(subsubdir, full_path); + } + } + } } // ridiculous little helper function that should go away when we can use lambda inline void push_back(std::vector<std::string>& vector, const std::string& value) { - vector.push_back(value); + vector.push_back(value); } typedef std::map<std::string, std::string> StringMap; // ridiculous little helper function that should go away when we can use lambda inline void store_in_map(StringMap& map, const std::string& key, const std::string& value) { - map[key] = value; + map[key] = value; } std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir, - const std::string& filename, - ESkinConstraint constraint) const -{ - // Recognize subdirs that have no localization. - static const std::set<std::string> sUnlocalized = list_of - ("") // top-level directory not localized - ("textures") // textures not localized - ; - - LL_DEBUGS("LLDir") << "subdir '" << subdir << "', filename '" << filename - << "', constraint " - << ((constraint == CURRENT_SKIN)? "CURRENT_SKIN" : "ALL_SKINS") - << LL_ENDL; - - // Build results vector. - std::vector<std::string> results; - // Disallow filenames that may escape subdir - if (filename.find("..") != std::string::npos) - { - LL_WARNS("LLDir") << "Ignoring potentially relative filename '" << filename << "'" << LL_ENDL; - return results; - } - - // Cache the default language directory for each subdir we've encountered. - // A cache entry whose value is the empty string means "not localized, - // don't bother checking again." - static StringMap sLocalized; - - // Check whether we've already discovered if this subdir is localized. - StringMap::const_iterator found = sLocalized.find(subdir); - if (found == sLocalized.end()) - { - // We have not yet determined that. Is it one of the subdirs "known" - // to be unlocalized? - if (sUnlocalized.find(subdir) != sUnlocalized.end()) - { - // This subdir is known to be unlocalized. Remember that. - found = sLocalized.insert(StringMap::value_type(subdir, "")).first; - } - else - { - // We do not recognize this subdir. Investigate. - std::string subdir_path(add(getDefaultSkinDir(), subdir)); - if (fileExists(add(subdir_path, "en"))) - { - // defaultSkinDir/subdir contains subdir "en". That's our - // default language; this subdir is localized. - found = sLocalized.insert(StringMap::value_type(subdir, "en")).first; - } - else if (fileExists(add(subdir_path, "en-us"))) - { - // defaultSkinDir/subdir contains subdir "en-us" but not "en". - // Set as default language; this subdir is localized. - found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first; - } - else - { - // defaultSkinDir/subdir contains neither "en" nor "en-us". - // Assume it's not localized. Remember that assumption. - found = sLocalized.insert(StringMap::value_type(subdir, "")).first; - } - } - } - // Every code path above should have resulted in 'found' becoming a valid - // iterator to an entry in sLocalized. - llassert(found != sLocalized.end()); - - // Now -- is this subdir localized, or not? The answer determines what - // subdirectories we check (under subdir) for the requested filename. - std::vector<std::string> subsubdirs; - if (found->second.empty()) - { - // subdir is not localized. filename should be located directly within it. - subsubdirs.push_back(""); - } - else - { - // subdir is localized, and found->second is the default language - // directory within it. Check both the default language and the - // current language -- if it differs from the default, of course. - subsubdirs.push_back(found->second); - if (mLanguage != found->second) - { - subsubdirs.push_back(mLanguage); - } - } - - // The process we use depends on 'constraint'. - if (constraint != CURRENT_SKIN) // meaning ALL_SKINS - { - // ALL_SKINS is simpler: just return every pathname generated by - // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its - // FUNCTION the subsubdir as well as the full pathname. We just want - // the full pathname. - walkSearchSkinDirs(subdir, subsubdirs, filename, - boost::bind(push_back, boost::ref(results), _2)); - } - else // CURRENT_SKIN - { - // CURRENT_SKIN turns out to be a bit of a misnomer because we might - // still return files from two different skins. In any case, this - // value of 'constraint' means we will return at most two paths: one - // for the default language, one for the current language (supposing - // those differ). - // It is important to allow a user to override only the localization - // for a particular file, for all viewer installs, without also - // overriding the default-language file. - // It is important to allow a user to override only the default- - // language file, for all viewer installs, without also overriding the - // applicable localization of that file. - // Therefore, treat the default language and the current language as - // two separate cases. For each, capture the most-specialized file - // that exists. - // Use a map keyed by subsubdir (i.e. language code). This allows us - // to handle the case of a single subsubdirs entry with the same logic - // that handles two. For every real file path generated by - // walkSearchSkinDirs(), update the map entry for its subsubdir. - StringMap path_for; - walkSearchSkinDirs(subdir, subsubdirs, filename, - boost::bind(store_in_map, boost::ref(path_for), _1, _2)); - // Now that we have a path for each of the default language and the - // current language, copy them -- in proper order -- into results. - // Don't drive this by walking the map itself: it matters that we - // generate results in the same order as subsubdirs. - for (const std::string& subsubdir : subsubdirs) - { - StringMap::const_iterator found(path_for.find(subsubdir)); - if (found != path_for.end()) - { - results.push_back(found->second); - } - } - } - - LL_DEBUGS("LLDir") << empty; - const char* comma = ""; - for (const std::string& path : results) - { - LL_CONT << comma << "'" << path << "'"; - comma = ", "; - } - LL_CONT << LL_ENDL; - - return results; + const std::string& filename, + ESkinConstraint constraint) const +{ + // Recognize subdirs that have no localization. + static const std::set<std::string> sUnlocalized = list_of + ("") // top-level directory not localized + ("textures") // textures not localized + ; + + LL_DEBUGS("LLDir") << "subdir '" << subdir << "', filename '" << filename + << "', constraint " + << ((constraint == CURRENT_SKIN)? "CURRENT_SKIN" : "ALL_SKINS") + << LL_ENDL; + + // Build results vector. + std::vector<std::string> results; + // Disallow filenames that may escape subdir + if (filename.find("..") != std::string::npos) + { + LL_WARNS("LLDir") << "Ignoring potentially relative filename '" << filename << "'" << LL_ENDL; + return results; + } + + // Cache the default language directory for each subdir we've encountered. + // A cache entry whose value is the empty string means "not localized, + // don't bother checking again." + static StringMap sLocalized; + + // Check whether we've already discovered if this subdir is localized. + StringMap::const_iterator found = sLocalized.find(subdir); + if (found == sLocalized.end()) + { + // We have not yet determined that. Is it one of the subdirs "known" + // to be unlocalized? + if (sUnlocalized.find(subdir) != sUnlocalized.end()) + { + // This subdir is known to be unlocalized. Remember that. + found = sLocalized.insert(StringMap::value_type(subdir, "")).first; + } + else + { + // We do not recognize this subdir. Investigate. + std::string subdir_path(add(getDefaultSkinDir(), subdir)); + if (fileExists(add(subdir_path, "en"))) + { + // defaultSkinDir/subdir contains subdir "en". That's our + // default language; this subdir is localized. + found = sLocalized.insert(StringMap::value_type(subdir, "en")).first; + } + else if (fileExists(add(subdir_path, "en-us"))) + { + // defaultSkinDir/subdir contains subdir "en-us" but not "en". + // Set as default language; this subdir is localized. + found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first; + } + else + { + // defaultSkinDir/subdir contains neither "en" nor "en-us". + // Assume it's not localized. Remember that assumption. + found = sLocalized.insert(StringMap::value_type(subdir, "")).first; + } + } + } + // Every code path above should have resulted in 'found' becoming a valid + // iterator to an entry in sLocalized. + llassert(found != sLocalized.end()); + + // Now -- is this subdir localized, or not? The answer determines what + // subdirectories we check (under subdir) for the requested filename. + std::vector<std::string> subsubdirs; + if (found->second.empty()) + { + // subdir is not localized. filename should be located directly within it. + subsubdirs.push_back(""); + } + else + { + // subdir is localized, and found->second is the default language + // directory within it. Check both the default language and the + // current language -- if it differs from the default, of course. + subsubdirs.push_back(found->second); + if (mLanguage != found->second) + { + subsubdirs.push_back(mLanguage); + } + } + + // The process we use depends on 'constraint'. + if (constraint != CURRENT_SKIN) // meaning ALL_SKINS + { + // ALL_SKINS is simpler: just return every pathname generated by + // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its + // FUNCTION the subsubdir as well as the full pathname. We just want + // the full pathname. + walkSearchSkinDirs(subdir, subsubdirs, filename, + boost::bind(push_back, boost::ref(results), _2)); + } + else // CURRENT_SKIN + { + // CURRENT_SKIN turns out to be a bit of a misnomer because we might + // still return files from two different skins. In any case, this + // value of 'constraint' means we will return at most two paths: one + // for the default language, one for the current language (supposing + // those differ). + // It is important to allow a user to override only the localization + // for a particular file, for all viewer installs, without also + // overriding the default-language file. + // It is important to allow a user to override only the default- + // language file, for all viewer installs, without also overriding the + // applicable localization of that file. + // Therefore, treat the default language and the current language as + // two separate cases. For each, capture the most-specialized file + // that exists. + // Use a map keyed by subsubdir (i.e. language code). This allows us + // to handle the case of a single subsubdirs entry with the same logic + // that handles two. For every real file path generated by + // walkSearchSkinDirs(), update the map entry for its subsubdir. + StringMap path_for; + walkSearchSkinDirs(subdir, subsubdirs, filename, + boost::bind(store_in_map, boost::ref(path_for), _1, _2)); + // Now that we have a path for each of the default language and the + // current language, copy them -- in proper order -- into results. + // Don't drive this by walking the map itself: it matters that we + // generate results in the same order as subsubdirs. + for (const std::string& subsubdir : subsubdirs) + { + StringMap::const_iterator found(path_for.find(subsubdir)); + if (found != path_for.end()) + { + results.push_back(found->second); + } + } + } + + LL_DEBUGS("LLDir") << empty; + const char* comma = ""; + for (const std::string& path : results) + { + LL_CONT << comma << "'" << path << "'"; + comma = ", "; + } + LL_CONT << LL_ENDL; + + return results; } std::string LLDir::getTempFilename() const { - LLUUID random_uuid; - std::string uuid_str; + LLUUID random_uuid; + std::string uuid_str; - random_uuid.generate(); - random_uuid.toString(uuid_str); + random_uuid.generate(); + random_uuid.toString(uuid_str); - return add(getTempDir(), uuid_str + ".tmp"); + return add(getTempDir(), uuid_str + ".tmp"); } // static std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) { - std::string name(uncleanFileName); - const std::string illegalChars(getForbiddenFileChars()); - // replace any illegal file chars with and underscore '_' - for( unsigned int i = 0; i < illegalChars.length(); i++ ) - { - int j = -1; - while((j = name.find(illegalChars[i])) > -1) - { - name[j] = '_'; - } - } - return name; + std::string name(uncleanFileName); + const std::string illegalChars(getForbiddenFileChars()); + // replace any illegal file chars with and underscore '_' + for( unsigned int i = 0; i < illegalChars.length(); i++ ) + { + int j = -1; + while((j = name.find(illegalChars[i])) > -1) + { + name[j] = '_'; + } + } + return name; } std::string LLDir::getDumpLogsDirPath(const std::string &file_name) @@ -900,241 +905,241 @@ std::string LLDir::getDumpLogsDirPath(const std::string &file_name) // static std::string LLDir::getForbiddenFileChars() { - return "\\/:*?\"<>|"; + return "\\/:*?\"<>|"; } void LLDir::setLindenUserDir(const std::string &username) { - // if the username isn't set, that's bad - if (!username.empty()) - { - // some platforms have case-sensitive filesystems, so be - // utterly consistent with our firstname/lastname case. - std::string userlower(username); - LLStringUtil::toLower(userlower); - LLStringUtil::replaceChar(userlower, ' ', '_'); - mLindenUserDir = add(getOSUserAppDir(), userlower); - } - else - { - LL_ERRS() << "NULL name for LLDir::setLindenUserDir" << LL_ENDL; - } + // if the username isn't set, that's bad + if (!username.empty()) + { + // some platforms have case-sensitive filesystems, so be + // utterly consistent with our firstname/lastname case. + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); + mLindenUserDir = add(getOSUserAppDir(), userlower); + } + else + { + LL_ERRS() << "NULL name for LLDir::setLindenUserDir" << LL_ENDL; + } - dumpCurrentDirectories(); + dumpCurrentDirectories(); } void LLDir::setChatLogsDir(const std::string &path) { - if (!path.empty() ) - { - mChatLogsDir = path; - } - else - { - LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL; - } + if (!path.empty() ) + { + mChatLogsDir = path; + } + else + { + LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL; + } } void LLDir::updatePerAccountChatLogsDir() { - mPerAccountChatLogsDir = add(getChatLogsDir(), mUserName); + mPerAccountChatLogsDir = add(getChatLogsDir(), mUserName); } void LLDir::setPerAccountChatLogsDir(const std::string &username) { - // if both first and last aren't set, assume we're grabbing the cached dir - if (!username.empty()) - { - // some platforms have case-sensitive filesystems, so be - // utterly consistent with our firstname/lastname case. - std::string userlower(username); - LLStringUtil::toLower(userlower); - LLStringUtil::replaceChar(userlower, ' ', '_'); - - mUserName = userlower; - updatePerAccountChatLogsDir(); - } - else - { - LL_ERRS() << "NULL name for LLDir::setPerAccountChatLogsDir" << LL_ENDL; - } + // if both first and last aren't set, assume we're grabbing the cached dir + if (!username.empty()) + { + // some platforms have case-sensitive filesystems, so be + // utterly consistent with our firstname/lastname case. + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); + + mUserName = userlower; + updatePerAccountChatLogsDir(); + } + else + { + LL_ERRS() << "NULL name for LLDir::setPerAccountChatLogsDir" << LL_ENDL; + } } void LLDir::setSkinFolder(const std::string &skin_folder, const std::string& language) { - LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'" - << LL_ENDL; - mSkinName = skin_folder; - mLanguage = language; - - // This method is called multiple times during viewer initialization. Each - // time it's called, reset mSearchSkinDirs. - mSearchSkinDirs.clear(); - - // base skin which is used as fallback for all skinned files - // e.g. c:\program files\secondlife\skins\default - mDefaultSkinDir = getSkinBaseDir(); - append(mDefaultSkinDir, "default"); - // This is always the most general of the search skin directories. - addSearchSkinDir(mDefaultSkinDir); - - mSkinDir = getSkinBaseDir(); - append(mSkinDir, skin_folder); - // Next level of generality is a skin installed with the viewer. - addSearchSkinDir(mSkinDir); - - // user modifications to skins, current and default - // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle - mUserSkinDir = getOSUserAppDir(); - append(mUserSkinDir, "skins"); - mUserDefaultSkinDir = mUserSkinDir; - append(mUserDefaultSkinDir, "default"); - append(mUserSkinDir, skin_folder); - // Next level of generality is user modifications to default skin... - addSearchSkinDir(mUserDefaultSkinDir); - // then user-defined skins. - addSearchSkinDir(mUserSkinDir); + LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'" + << LL_ENDL; + mSkinName = skin_folder; + mLanguage = language; + + // This method is called multiple times during viewer initialization. Each + // time it's called, reset mSearchSkinDirs. + mSearchSkinDirs.clear(); + + // base skin which is used as fallback for all skinned files + // e.g. c:\program files\secondlife\skins\default + mDefaultSkinDir = getSkinBaseDir(); + append(mDefaultSkinDir, "default"); + // This is always the most general of the search skin directories. + addSearchSkinDir(mDefaultSkinDir); + + mSkinDir = getSkinBaseDir(); + append(mSkinDir, skin_folder); + // Next level of generality is a skin installed with the viewer. + addSearchSkinDir(mSkinDir); + + // user modifications to skins, current and default + // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle + mUserSkinDir = getOSUserAppDir(); + append(mUserSkinDir, "skins"); + mUserDefaultSkinDir = mUserSkinDir; + append(mUserDefaultSkinDir, "default"); + append(mUserSkinDir, skin_folder); + // Next level of generality is user modifications to default skin... + addSearchSkinDir(mUserDefaultSkinDir); + // then user-defined skins. + addSearchSkinDir(mUserSkinDir); } void LLDir::addSearchSkinDir(const std::string& skindir) { - if (std::find(mSearchSkinDirs.begin(), mSearchSkinDirs.end(), skindir) == mSearchSkinDirs.end()) - { - LL_DEBUGS("LLDir") << "search skin: '" << skindir << "'" << LL_ENDL; - mSearchSkinDirs.push_back(skindir); - } + if (std::find(mSearchSkinDirs.begin(), mSearchSkinDirs.end(), skindir) == mSearchSkinDirs.end()) + { + LL_DEBUGS("LLDir") << "search skin: '" << skindir << "'" << LL_ENDL; + mSearchSkinDirs.push_back(skindir); + } } std::string LLDir::getSkinFolder() const { - return mSkinName; + return mSkinName; } std::string LLDir::getLanguage() const { - return mLanguage; + return mLanguage; } bool LLDir::setCacheDir(const std::string &path) { - if (path.empty() ) - { - // reset to default - mCacheDir = ""; - return true; - } - else - { - LLFile::mkdir(path); - std::string tempname = add(path, "temp"); - LLFILE* file = LLFile::fopen(tempname,"wt"); - if (file) - { - fclose(file); - LLFile::remove(tempname); - mCacheDir = path; - return true; - } - return false; - } + if (path.empty() ) + { + // reset to default + mCacheDir = ""; + return true; + } + else + { + LLFile::mkdir(path); + std::string tempname = add(path, "temp"); + LLFILE* file = LLFile::fopen(tempname,"wt"); + if (file) + { + fclose(file); + LLFile::remove(tempname); + mCacheDir = path; + return true; + } + return false; + } } void LLDir::dumpCurrentDirectories(LLError::ELevel level) { - LL_VLOGS(level, "AppInit","Directories") << "Current Directories:" << LL_ENDL; - - LL_VLOGS(level, "AppInit", "Directories") << " CurPath: " << getCurPath() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " AppName: " << getAppName() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " TempDir: " << getTempDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " CAFile: " << getCAFile() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; + LL_VLOGS(level, "AppInit","Directories") << "Current Directories:" << LL_ENDL; + + LL_VLOGS(level, "AppInit", "Directories") << " CurPath: " << getCurPath() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " AppName: " << getAppName() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " TempDir: " << getTempDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " CAFile: " << getCAFile() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; } void LLDir::append(std::string& destpath, const std::string& name) const { - // Delegate question of whether we need a separator to helper method. - SepOff sepoff(needSep(destpath, name)); - if (sepoff.first) // do we need a separator? - { - destpath += mDirDelimiter; - } - // If destpath ends with a separator, AND name starts with one, skip - // name's leading separator. - destpath += name.substr(sepoff.second); + // Delegate question of whether we need a separator to helper method. + SepOff sepoff(needSep(destpath, name)); + if (sepoff.first) // do we need a separator? + { + destpath += mDirDelimiter; + } + // If destpath ends with a separator, AND name starts with one, skip + // name's leading separator. + destpath += name.substr(sepoff.second); } LLDir::SepOff LLDir::needSep(const std::string& path, const std::string& name) const { - if (path.empty() || name.empty()) - { - // If either path or name are empty, we do not need a separator - // between them. - return SepOff(false, 0); - } - // Here we know path and name are both non-empty. But if path already ends - // with a separator, or if name already starts with a separator, we need - // not add one. - std::string::size_type seplen(mDirDelimiter.length()); - bool path_ends_sep(path.substr(path.length() - seplen) == mDirDelimiter); - bool name_starts_sep(name.substr(0, seplen) == mDirDelimiter); - if ((! path_ends_sep) && (! name_starts_sep)) - { - // If neither path nor name brings a separator to the junction, then - // we need one. - return SepOff(true, 0); - } - if (path_ends_sep && name_starts_sep) - { - // But if BOTH path and name bring a separator, we need not add one. - // Moreover, we should actually skip the leading separator of 'name'. - return SepOff(false, (unsigned short)seplen); - } - // Here we know that either path_ends_sep or name_starts_sep is true -- - // but not both. So don't add a separator, and don't skip any characters: - // simple concatenation will do the trick. - return SepOff(false, 0); + if (path.empty() || name.empty()) + { + // If either path or name are empty, we do not need a separator + // between them. + return SepOff(false, 0); + } + // Here we know path and name are both non-empty. But if path already ends + // with a separator, or if name already starts with a separator, we need + // not add one. + std::string::size_type seplen(mDirDelimiter.length()); + bool path_ends_sep(path.substr(path.length() - seplen) == mDirDelimiter); + bool name_starts_sep(name.substr(0, seplen) == mDirDelimiter); + if ((! path_ends_sep) && (! name_starts_sep)) + { + // If neither path nor name brings a separator to the junction, then + // we need one. + return SepOff(true, 0); + } + if (path_ends_sep && name_starts_sep) + { + // But if BOTH path and name bring a separator, we need not add one. + // Moreover, we should actually skip the leading separator of 'name'. + return SepOff(false, (unsigned short)seplen); + } + // Here we know that either path_ends_sep or name_starts_sep is true -- + // but not both. So don't add a separator, and don't skip any characters: + // simple concatenation will do the trick. + return SepOff(false, 0); } void dir_exists_or_crash(const std::string &dir_name) { #if LL_WINDOWS - // *FIX: lame - it doesn't do the same thing on windows. not so - // important since we don't deploy simulator to windows boxes. - LLFile::mkdir(dir_name, 0700); + // *FIX: lame - it doesn't do the same thing on windows. not so + // important since we don't deploy simulator to windows boxes. + LLFile::mkdir(dir_name, 0700); #else - struct stat dir_stat; - if(0 != LLFile::stat(dir_name, &dir_stat)) - { - S32 stat_rv = errno; - if(ENOENT == stat_rv) - { - if(0 != LLFile::mkdir(dir_name, 0700)) // octal - { - LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL; - } - } - else - { - LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv - << LL_ENDL; - } - } - else - { - // data_dir exists, make sure it's a directory. - if(!S_ISDIR(dir_stat.st_mode)) - { - LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL; - } - } + struct stat dir_stat; + if(0 != LLFile::stat(dir_name, &dir_stat)) + { + S32 stat_rv = errno; + if(ENOENT == stat_rv) + { + if(0 != LLFile::mkdir(dir_name, 0700)) // octal + { + LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL; + } + } + else + { + LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv + << LL_ENDL; + } + } + else + { + // data_dir exists, make sure it's a directory. + if(!S_ISDIR(dir_stat.st_mode)) + { + LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL; + } + } #endif } diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h index be82f55e46..7d418159d1 100644 --- a/indra/llfilesystem/lldir.h +++ b/indra/llfilesystem/lldir.h @@ -1,25 +1,25 @@ -/** +/** * @file lldir.h * @brief Definition of directory utilities class * * $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$ */ @@ -30,245 +30,246 @@ // these numbers are read from settings_files.xml, so we need to be explicit typedef enum ELLPath { - LL_PATH_NONE = 0, - LL_PATH_USER_SETTINGS = 1, - LL_PATH_APP_SETTINGS = 2, - LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet - LL_PATH_CACHE = 4, - LL_PATH_CHARACTER = 5, - LL_PATH_HELP = 6, - LL_PATH_LOGS = 7, - LL_PATH_TEMP = 8, - LL_PATH_SKINS = 9, - LL_PATH_TOP_SKIN = 10, - LL_PATH_CHAT_LOGS = 11, - LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12, - LL_PATH_USER_SKIN = 14, - LL_PATH_LOCAL_ASSETS = 15, - LL_PATH_EXECUTABLE = 16, - LL_PATH_DEFAULT_SKIN = 17, - LL_PATH_FONTS = 18, + LL_PATH_NONE = 0, + LL_PATH_USER_SETTINGS = 1, + LL_PATH_APP_SETTINGS = 2, + LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet + LL_PATH_CACHE = 4, + LL_PATH_CHARACTER = 5, + LL_PATH_HELP = 6, + LL_PATH_LOGS = 7, + LL_PATH_TEMP = 8, + LL_PATH_SKINS = 9, + LL_PATH_TOP_SKIN = 10, + LL_PATH_CHAT_LOGS = 11, + LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12, + LL_PATH_USER_SKIN = 14, + LL_PATH_LOCAL_ASSETS = 15, + LL_PATH_EXECUTABLE = 16, + LL_PATH_DEFAULT_SKIN = 17, + LL_PATH_FONTS = 18, LL_PATH_DUMP = 19, - LL_PATH_LAST + LL_PATH_SCRIPTS = 20, + LL_PATH_LAST } ELLPath; /// Directory operations class LLDir { public: - LLDir(); - virtual ~LLDir(); + LLDir(); + virtual ~LLDir(); - // app_name - Usually SecondLife, used for creating settings directories - // in OS-specific location, such as C:\Documents and Settings - // app_read_only_data_dir - Usually the source code directory, used - // for test applications to read newview data files. - virtual void initAppDirs(const std::string &app_name, - const std::string& app_read_only_data_dir = "") = 0; + // app_name - Usually SecondLife, used for creating settings directories + // in OS-specific location, such as C:\Documents and Settings + // app_read_only_data_dir - Usually the source code directory, used + // for test applications to read newview data files. + virtual void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir = "") = 0; - virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); + virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); U32 deleteDirAndContents(const std::string& dir_name); std::vector<std::string> getFilesInDir(const std::string &dirname); // pure virtual functions - virtual std::string getCurPath() = 0; - virtual bool fileExists(const std::string &filename) const = 0; + virtual std::string getCurPath() = 0; + virtual bool fileExists(const std::string &filename) const = 0; - const std::string findFile(const std::string& filename, const std::vector<std::string> filenames) const; - const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; + const std::string findFile(const std::string& filename, const std::vector<std::string> filenames) const; + const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; - virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell - virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') + virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell + virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') - const std::string &getExecutablePathAndName() const; // Full pathname of the executable - const std::string &getAppName() const; // install directory under progams/ ie "SecondLife" - const std::string &getExecutableDir() const; // Directory where the executable is located - const std::string &getExecutableFilename() const;// Filename of .exe - const std::string &getWorkingDir() const; // Current working directory - const std::string &getAppRODataDir() const; // Location of read-only data files - const std::string &getOSUserDir() const; // Location of the os-specific user dir - const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir - const std::string &getLindenUserDir() const; // Location of the Linden user dir. - const std::string &getChatLogsDir() const; // Location of the chat logs dir. - const std::string &getDumpDir() const; // Location of the per-run dump dir. - bool dumpDirExists() const; - const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. - const std::string &getTempDir() const; // Common temporary directory - const std::string getCacheDir(bool get_default = false) const; // Location of the cache. - const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string) - const std::string &getCAFile() const; // File containing TLS certificate authorities - const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') - const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default - const std::string &getSkinDir() const; // User-specified skin folder. - const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin - const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin - const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins - const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell - const std::string &getUserName() const; + const std::string &getExecutablePathAndName() const; // Full pathname of the executable + const std::string &getAppName() const; // install directory under progams/ ie "SecondLife" + const std::string &getExecutableDir() const; // Directory where the executable is located + const std::string &getExecutableFilename() const;// Filename of .exe + const std::string &getWorkingDir() const; // Current working directory + const std::string &getAppRODataDir() const; // Location of read-only data files + const std::string &getOSUserDir() const; // Location of the os-specific user dir + const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir + const std::string &getLindenUserDir() const; // Location of the Linden user dir. + const std::string &getChatLogsDir() const; // Location of the chat logs dir. + const std::string &getDumpDir() const; // Location of the per-run dump dir. + bool dumpDirExists() const; + const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. + const std::string &getTempDir() const; // Common temporary directory + const std::string getCacheDir(bool get_default = false) const; // Location of the cache. + const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string) + const std::string &getCAFile() const; // File containing TLS certificate authorities + const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') + const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default + const std::string &getSkinDir() const; // User-specified skin folder. + const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin + const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin + const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins + const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell + const std::string &getUserName() const; - // Expanded filename - std::string getExpandedFilename(ELLPath location, const std::string &filename) const; - std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const; - std::string getExpandedFilename(ELLPath location, const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; + // Expanded filename + std::string getExpandedFilename(ELLPath location, const std::string &filename) const; + std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const; + std::string getExpandedFilename(ELLPath location, const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; - // Base and Directory name extraction - std::string getBaseFileName(const std::string& filepath, bool strip_exten = false) const; - std::string getDirName(const std::string& filepath) const; - std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav" + // Base and Directory name extraction + std::string getBaseFileName(const std::string& filepath, bool strip_exten = false) const; + std::string getDirName(const std::string& filepath) const; + std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav" - // these methods search the various skin paths for the specified file in the following order: - // getUserSkinDir(), getUserDefaultSkinDir(), getSkinDir(), getDefaultSkinDir() - /// param value for findSkinnedFilenames(), explained below - enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS }; - /** - * Given a filename within skin, return an ordered sequence of paths to - * search. Nonexistent files will be filtered out -- which means that the - * vector might be empty. - * - * @param subdir Identify top-level skin subdirectory by passing one of - * LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file - * lives under "textures" subtree), LLDir::SKINBASE (file lives at top - * level of skin subdirectory). - * @param filename Desired filename within subdir within skin, e.g. - * "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language. - * @param constraint Callers perform two different kinds of processing. - * When fetching a XUI file, for instance, the existence of @a filename in - * the specified skin completely supercedes any @a filename in the default - * skin. For that case, leave the default @a constraint=CURRENT_SKIN. The - * returned vector will contain only - * ".../<i>current_skin</i>/xui/en/<i>filename</i>", - * ".../<i>current_skin</i>/xui/<i>current_language</i>/<i>filename</i>". - * But for (e.g.) "strings.xml", we want a given skin to be able to - * override only specific entries from the default skin. Any string not - * defined in the specified skin will be sought in the default skin. For - * that case, pass @a constraint=ALL_SKINS. The returned vector will - * contain at least ".../default/xui/en/strings.xml", - * ".../default/xui/<i>current_language</i>/strings.xml", - * ".../<i>current_skin</i>/xui/en/strings.xml", - * ".../<i>current_skin</i>/xui/<i>current_language</i>/strings.xml". - */ - std::vector<std::string> findSkinnedFilenames(const std::string& subdir, - const std::string& filename, - ESkinConstraint constraint=CURRENT_SKIN) const; - /// Values for findSkinnedFilenames(subdir) parameter - static const char *XUI, *TEXTURES, *SKINBASE; - /** - * Return the base-language pathname from findSkinnedFilenames(), or - * the empty string if no such file exists. Parameters are identical to - * findSkinnedFilenames(). This is shorthand for capturing the vector - * returned by findSkinnedFilenames(), checking for empty() and then - * returning front(). - */ - std::string findSkinnedFilenameBaseLang(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint=CURRENT_SKIN) const; - /** - * Return the "most localized" pathname from findSkinnedFilenames(), or - * the empty string if no such file exists. Parameters are identical to - * findSkinnedFilenames(). This is shorthand for capturing the vector - * returned by findSkinnedFilenames(), checking for empty() and then - * returning back(). - */ - std::string findSkinnedFilename(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint=CURRENT_SKIN) const; + // these methods search the various skin paths for the specified file in the following order: + // getUserSkinDir(), getUserDefaultSkinDir(), getSkinDir(), getDefaultSkinDir() + /// param value for findSkinnedFilenames(), explained below + enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS }; + /** + * Given a filename within skin, return an ordered sequence of paths to + * search. Nonexistent files will be filtered out -- which means that the + * vector might be empty. + * + * @param subdir Identify top-level skin subdirectory by passing one of + * LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file + * lives under "textures" subtree), LLDir::SKINBASE (file lives at top + * level of skin subdirectory). + * @param filename Desired filename within subdir within skin, e.g. + * "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language. + * @param constraint Callers perform two different kinds of processing. + * When fetching a XUI file, for instance, the existence of @a filename in + * the specified skin completely supercedes any @a filename in the default + * skin. For that case, leave the default @a constraint=CURRENT_SKIN. The + * returned vector will contain only + * ".../<i>current_skin</i>/xui/en/<i>filename</i>", + * ".../<i>current_skin</i>/xui/<i>current_language</i>/<i>filename</i>". + * But for (e.g.) "strings.xml", we want a given skin to be able to + * override only specific entries from the default skin. Any string not + * defined in the specified skin will be sought in the default skin. For + * that case, pass @a constraint=ALL_SKINS. The returned vector will + * contain at least ".../default/xui/en/strings.xml", + * ".../default/xui/<i>current_language</i>/strings.xml", + * ".../<i>current_skin</i>/xui/en/strings.xml", + * ".../<i>current_skin</i>/xui/<i>current_language</i>/strings.xml". + */ + std::vector<std::string> findSkinnedFilenames(const std::string& subdir, + const std::string& filename, + ESkinConstraint constraint=CURRENT_SKIN) const; + /// Values for findSkinnedFilenames(subdir) parameter + static const char *XUI, *TEXTURES, *SKINBASE; + /** + * Return the base-language pathname from findSkinnedFilenames(), or + * the empty string if no such file exists. Parameters are identical to + * findSkinnedFilenames(). This is shorthand for capturing the vector + * returned by findSkinnedFilenames(), checking for empty() and then + * returning front(). + */ + std::string findSkinnedFilenameBaseLang(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint=CURRENT_SKIN) const; + /** + * Return the "most localized" pathname from findSkinnedFilenames(), or + * the empty string if no such file exists. Parameters are identical to + * findSkinnedFilenames(). This is shorthand for capturing the vector + * returned by findSkinnedFilenames(), checking for empty() and then + * returning back(). + */ + std::string findSkinnedFilename(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint=CURRENT_SKIN) const; - // random filename in common temporary directory - std::string getTempFilename() const; + // random filename in common temporary directory + std::string getTempFilename() const; static std::string getDumpLogsDirPath(const std::string &file_name = ""); - // For producing safe download file names from potentially unsafe ones - static std::string getScrubbedFileName(const std::string uncleanFileName); - static std::string getForbiddenFileChars(); + // For producing safe download file names from potentially unsafe ones + static std::string getScrubbedFileName(const std::string uncleanFileName); + static std::string getForbiddenFileChars(); void setDumpDir( const std::string& path ); - virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir - virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory. - virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir - virtual void setSkinFolder(const std::string &skin_folder, const std::string& language); - virtual std::string getSkinFolder() const; - virtual std::string getLanguage() const; - virtual bool setCacheDir(const std::string &path); - virtual void updatePerAccountChatLogsDir(); + virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir + virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory. + virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir + virtual void setSkinFolder(const std::string &skin_folder, const std::string& language); + virtual std::string getSkinFolder() const; + virtual std::string getLanguage() const; + virtual bool setCacheDir(const std::string &path); + virtual void updatePerAccountChatLogsDir(); - virtual void dumpCurrentDirectories(LLError::ELevel level = LLError::LEVEL_DEBUG); + virtual void dumpCurrentDirectories(LLError::ELevel level = LLError::LEVEL_DEBUG); - // Utility routine - std::string buildSLOSCacheDir() const; + // Utility routine + std::string buildSLOSCacheDir() const; - /// Append specified @a name to @a destpath, separated by getDirDelimiter() - /// if both are non-empty. - void append(std::string& destpath, const std::string& name) const; - /// Variadic form: append @a name0 and @a name1 and arbitrary other @a - /// names to @a destpath, separated by getDirDelimiter() as needed. - template <typename... NAMES> - void append(std::string& destpath, const std::string& name0, const std::string& name1, - const NAMES& ... names) const - { - // In a typical recursion case, we'd accept (destpath, name0, names). - // We accept (destpath, name0, name1, names) because it's important to - // delegate the two-argument case to the non-template implementation. - append(destpath, name0); - append(destpath, name1, names...); - } + /// Append specified @a name to @a destpath, separated by getDirDelimiter() + /// if both are non-empty. + void append(std::string& destpath, const std::string& name) const; + /// Variadic form: append @a name0 and @a name1 and arbitrary other @a + /// names to @a destpath, separated by getDirDelimiter() as needed. + template <typename... NAMES> + void append(std::string& destpath, const std::string& name0, const std::string& name1, + const NAMES& ... names) const + { + // In a typical recursion case, we'd accept (destpath, name0, names). + // We accept (destpath, name0, name1, names) because it's important to + // delegate the two-argument case to the non-template implementation. + append(destpath, name0); + append(destpath, name1, names...); + } - /// Append specified @a names to @a path, separated by getDirDelimiter() - /// as needed. Return result, leaving @a path unmodified. - template <typename... NAMES> - std::string add(const std::string& path, const NAMES& ... names) const - { - std::string destpath(path); - append(destpath, names...); - return destpath; - } + /// Append specified @a names to @a path, separated by getDirDelimiter() + /// as needed. Return result, leaving @a path unmodified. + template <typename... NAMES> + std::string add(const std::string& path, const NAMES& ... names) const + { + std::string destpath(path); + append(destpath, names...); + return destpath; + } protected: - // Does an add() or append() call need a directory delimiter? - typedef std::pair<bool, unsigned short> SepOff; - SepOff needSep(const std::string& path, const std::string& name) const; - // build mSearchSkinDirs without adding duplicates - void addSearchSkinDir(const std::string& skindir); + // Does an add() or append() call need a directory delimiter? + typedef std::pair<bool, unsigned short> SepOff; + SepOff needSep(const std::string& path, const std::string& name) const; + // build mSearchSkinDirs without adding duplicates + void addSearchSkinDir(const std::string& skindir); - // Internal to findSkinnedFilenames() - template <typename FUNCTION> - void walkSearchSkinDirs(const std::string& subdir, - const std::vector<std::string>& subsubdirs, - const std::string& filename, - const FUNCTION& function) const; + // Internal to findSkinnedFilenames() + template <typename FUNCTION> + void walkSearchSkinDirs(const std::string& subdir, + const std::vector<std::string>& subsubdirs, + const std::string& filename, + const FUNCTION& function) const; - std::string mAppName; // install directory under progams/ ie "SecondLife" - std::string mExecutablePathAndName; // full path + Filename of .exe - std::string mExecutableFilename; // Filename of .exe - std::string mExecutableDir; // Location of executable - std::string mWorkingDir; // Current working directory - std::string mAppRODataDir; // Location for static app data - std::string mOSUserDir; // OS Specific user directory - std::string mOSUserAppDir; // OS Specific user app directory - std::string mLindenUserDir; // Location for Linden user-specific data - std::string mPerAccountChatLogsDir; // Location for chat logs. - std::string mChatLogsDir; // Location for chat logs. - std::string mCAFile; // Location of the TLS certificate authority PEM file. - std::string mTempDir; - std::string mCacheDir; // cache directory as set by user preference - std::string mDefaultCacheDir; // default cache diretory - std::string mOSCacheDir; // operating system cache dir - std::string mDirDelimiter; - std::string mSkinName; // caller-specified skin name - std::string mSkinBaseDir; // Base for skins paths. - std::string mDefaultSkinDir; // Location for default skin info. - std::string mSkinDir; // Location for current skin info. - std::string mUserDefaultSkinDir; // Location for default skin info. - std::string mUserSkinDir; // Location for user-modified skin info. - // Skin directories to search, most general to most specific. This order - // works well for composing fine-grained files, in which an individual item - // in a specific file overrides the corresponding item in more general - // files. Of course, for a file-level search, iterate backwards. - std::vector<std::string> mSearchSkinDirs; - std::string mLanguage; // Current viewer language - std::string mLLPluginDir; // Location for plugins and plugin shell + std::string mAppName; // install directory under progams/ ie "SecondLife" + std::string mExecutablePathAndName; // full path + Filename of .exe + std::string mExecutableFilename; // Filename of .exe + std::string mExecutableDir; // Location of executable + std::string mWorkingDir; // Current working directory + std::string mAppRODataDir; // Location for static app data + std::string mOSUserDir; // OS Specific user directory + std::string mOSUserAppDir; // OS Specific user app directory + std::string mLindenUserDir; // Location for Linden user-specific data + std::string mPerAccountChatLogsDir; // Location for chat logs. + std::string mChatLogsDir; // Location for chat logs. + std::string mCAFile; // Location of the TLS certificate authority PEM file. + std::string mTempDir; + std::string mCacheDir; // cache directory as set by user preference + std::string mDefaultCacheDir; // default cache diretory + std::string mOSCacheDir; // operating system cache dir + std::string mDirDelimiter; + std::string mSkinName; // caller-specified skin name + std::string mSkinBaseDir; // Base for skins paths. + std::string mDefaultSkinDir; // Location for default skin info. + std::string mSkinDir; // Location for current skin info. + std::string mUserDefaultSkinDir; // Location for default skin info. + std::string mUserSkinDir; // Location for user-modified skin info. + // Skin directories to search, most general to most specific. This order + // works well for composing fine-grained files, in which an individual item + // in a specific file overrides the corresponding item in more general + // files. Of course, for a file-level search, iterate backwards. + std::vector<std::string> mSearchSkinDirs; + std::string mLanguage; // Current viewer language + std::string mLLPluginDir; // Location for plugins and plugin shell static std::string sDumpDir; // Per-run crash report subdir of log directory. - std::string mUserName; // Current user name + std::string mUserName; // Current user name }; void dir_exists_or_crash(const std::string &dir_name); diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index 49fc1afd82..ffcd7d257f 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llimageworker_test.cpp * @author Merov Linden * @date 2009-04-28 @@ -6,28 +6,28 @@ * $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$ */ // Precompiled header: almost always required for newview cpp files #include "linden_common.h" -// Class to test +// Class to test #include "../llimageworker.h" // For timer class #include "../llcommon/lltimer.h" @@ -38,13 +38,13 @@ // ------------------------------------------------------------------------------------------- // Stubbing: Declarations required to link and run the class being tested -// Notes: +// Notes: // * Add here stubbed implementation of the few classes and methods used in the class to be tested // * Add as little as possible (let the link errors guide you) // * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code) // * A simulator for a class can be implemented here. Please comment and document thoroughly. -LLImageBase::LLImageBase() +LLImageBase::LLImageBase() : mData(NULL), mDataSize(0), mWidth(0), @@ -78,91 +78,91 @@ U8* LLImageBase::getData() { return NULL; } namespace tut { - // Test wrapper declarations + // Test wrapper declarations - // Note: We derive the responder class for 2 reasons: - // 1. It's a pure virtual class and we can't compile without completed() being implemented - // 2. We actually need a responder to test that the thread work test completed - // We implement this making no assumption on what's done in the thread or worker - // though, just that the responder's completed() method is called in the end. - // Note on responders: responders are ref counted and *will* be deleted by the request they are - // attached to when the queued request is deleted. The recommended way of using them is to - // create them when creating a request, put a callback method in completed() and not rely on - // anything to survive in the responder object once completed() has been called. Let the request - // do the deletion and clean up itself. - class responder_test : public LLImageDecodeThread::Responder - { - public: - responder_test(bool* res) - { - done = res; - *done = false; - } - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32) - { - *done = true; - } - private: - // This is what can be thought of as the minimal implementation of a responder - // Done will be switched to true when completed() is called and can be tested - // outside the responder. A better way of doing this is to store a callback here. - bool* done; - }; + // Note: We derive the responder class for 2 reasons: + // 1. It's a pure virtual class and we can't compile without completed() being implemented + // 2. We actually need a responder to test that the thread work test completed + // We implement this making no assumption on what's done in the thread or worker + // though, just that the responder's completed() method is called in the end. + // Note on responders: responders are ref counted and *will* be deleted by the request they are + // attached to when the queued request is deleted. The recommended way of using them is to + // create them when creating a request, put a callback method in completed() and not rely on + // anything to survive in the responder object once completed() has been called. Let the request + // do the deletion and clean up itself. + class responder_test : public LLImageDecodeThread::Responder + { + public: + responder_test(bool* res) + { + done = res; + *done = false; + } + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32) + { + *done = true; + } + private: + // This is what can be thought of as the minimal implementation of a responder + // Done will be switched to true when completed() is called and can be tested + // outside the responder. A better way of doing this is to store a callback here. + bool* done; + }; - // Test wrapper declaration : decode thread - struct imagedecodethread_test - { - // Instance to be tested - LLImageDecodeThread* mThread; - // Constructor and destructor of the test wrapper - imagedecodethread_test() - { - mThread = NULL; - } - ~imagedecodethread_test() - { - delete mThread; - } - }; + // Test wrapper declaration : decode thread + struct imagedecodethread_test + { + // Instance to be tested + LLImageDecodeThread* mThread; + // Constructor and destructor of the test wrapper + imagedecodethread_test() + { + mThread = NULL; + } + ~imagedecodethread_test() + { + delete mThread; + } + }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group<imagedecodethread_test> imagedecodethread_t; - typedef imagedecodethread_t::object imagedecodethread_object_t; - tut::imagedecodethread_t tut_imagedecodethread("LLImageDecodeThread"); + // Tut templating thingamagic: test group, object and test instance + typedef test_group<imagedecodethread_test> imagedecodethread_t; + typedef imagedecodethread_t::object imagedecodethread_object_t; + tut::imagedecodethread_t tut_imagedecodethread("LLImageDecodeThread"); - // --------------------------------------------------------------------------------------- - // Test functions - // Notes: - // * Test as many as you possibly can without requiring a full blown simulation of everything - // * The tests are executed in sequence so the test instance state may change between calls - // * Remember that you cannot test private methods with tut - // --------------------------------------------------------------------------------------- + // --------------------------------------------------------------------------------------- + // Test functions + // Notes: + // * Test as many as you possibly can without requiring a full blown simulation of everything + // * The tests are executed in sequence so the test instance state may change between calls + // * Remember that you cannot test private methods with tut + // --------------------------------------------------------------------------------------- - // --------------------------------------------------------------------------------------- - // Test the LLImageDecodeThread interface - // --------------------------------------------------------------------------------------- + // --------------------------------------------------------------------------------------- + // Test the LLImageDecodeThread interface + // --------------------------------------------------------------------------------------- - template<> template<> - void imagedecodethread_object_t::test<1>() - { - // Test a *threaded* instance of the class - mThread = new LLImageDecodeThread(true); - ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL); - // Insert something in the queue - bool done = false; - LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done)); - // Verifies we get back a valid handle - ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0); - // Wait till the thread has time to handle the work order (though it doesn't do much per work order...) - const U32 INCREMENT_TIME = 500; // 500 milliseconds - const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more - U32 total_time = 0; - while ((done == false) && (total_time < MAX_TIME)) - { - ms_sleep(INCREMENT_TIME); - total_time += INCREMENT_TIME; - } - // Verifies that the responder has now been called - ensure("LLImageDecodeThread: threaded work unit not processed", done == true); - } + template<> template<> + void imagedecodethread_object_t::test<1>() + { + // Test a *threaded* instance of the class + mThread = new LLImageDecodeThread(true); + ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL); + // Insert something in the queue + bool done = false; + LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done)); + // Verifies we get back a valid handle + ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0); + // Wait till the thread has time to handle the work order (though it doesn't do much per work order...) + const U32 INCREMENT_TIME = 500; // 500 milliseconds + const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more + U32 total_time = 0; + while ((done == false) && (total_time < MAX_TIME)) + { + ms_sleep(INCREMENT_TIME); + total_time += INCREMENT_TIME; + } + // Verifies that the responder has now been called + ensure("LLImageDecodeThread: threaded work unit not processed", done == true); + } } diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 959cfb2762..c1c1db7437 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -41,7 +41,7 @@ //========================================================================= // Map of pool sizes for known pools static const std::map<std::string, U32> DefaultPoolSizes{ - {std::string("Upload"), 1}, + {std::string("Upload"), 1}, {std::string("AIS"), 1}, // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. }; @@ -61,11 +61,11 @@ public: LLCoprocedurePool(const std::string &name, size_t size); ~LLCoprocedurePool(); - /// Places the coprocedure on the queue for processing. - /// + /// Places the coprocedure on the queue for processing. + /// /// @param name Is used for debugging and should identify this coroutine. - /// @param proc Is a bound function to be executed - /// + /// @param proc Is a bound function to be executed + /// /// @return This method returns a UUID that can be used later to cancel execution. LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc); @@ -91,7 +91,7 @@ public: } void close(); - + private: struct QueuedCoproc { @@ -108,7 +108,7 @@ private: CoProcedure_t mProc; }; - // we use a buffered_channel here rather than unbuffered_channel since we want to be able to + // we use a buffered_channel here rather than unbuffered_channel since we want to be able to // push values without blocking,even if there's currently no one calling a pop operation (due to // fiber running right now) typedef boost::fibers::buffered_channel<QueuedCoproc::ptr_t> CoprocQueue_t; @@ -167,7 +167,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) if (size == 0) { - // if not found grab the know default... if there is no known + // if not found grab the know default... if there is no known // default use a reasonable number like 5. auto it = DefaultPoolSizes.find(poolName); size = (it != DefaultPoolSizes.end()) ? it->second : DEFAULT_POOL_SIZE; @@ -190,7 +190,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) //------------------------------------------------------------------------- LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc) { - // Attempt to find the pool and enqueue the procedure. If the pool does + // Attempt to find the pool and enqueue the procedure. If the pool does // not exist, create it. poolMap_t::iterator it = mPoolMap.find(pool); @@ -307,25 +307,20 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): { try { - // store in our LLTempBoundListener so that when the LLCoprocedurePool is - // destroyed, we implicitly disconnect from this LLEventPump - // Monitores application status - mStatusListener = LLEventPumps::instance().obtain("LLApp").listen( + // Store in our LLTempBoundListener so that when the LLCoprocedurePool is + // destroyed, we implicitly disconnect from this LLEventPump. + // Monitors application status. + mStatusListener = LLCoros::getStopListener( poolName + "_pool", // Make sure it won't repeat names from lleventcoro - [pendingCoprocs = mPendingCoprocs, poolName](const LLSD& status) - { - auto& statsd = status["status"]; - if (statsd.asString() != "running") + [pendingCoprocs = mPendingCoprocs, poolName](const LLSD& event) { LL_INFOS("CoProcMgr") << "Pool " << poolName - << " closing queue because status " << statsd + << " closing queue because status " << event << LL_ENDL; // This should ensure that all waiting coprocedures in this // pool will wake up and terminate. pendingCoprocs->close(); - } - return false; - }); + }); } catch (const LLEventPump::DupListenerName &) { @@ -334,7 +329,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): // // If this somehow happens again it is better to crash later on shutdown due to pump // not stopping coroutine and see warning in logs than on startup or during login. - LL_WARNS("CoProcMgr") << "Attempted to register dupplicate listener name: " << poolName + LL_WARNS("CoProcMgr") << "Attempted to register duplicate listener name: " << poolName << "_pool. Failed to start listener." << LL_ENDL; llassert(0); // Fix Me! Ignoring missing listener! @@ -355,7 +350,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; } -LLCoprocedurePool::~LLCoprocedurePool() +LLCoprocedurePool::~LLCoprocedurePool() { } diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp index 143cf8e9c0..823a36ec3a 100644 --- a/indra/llprimitive/tests/llgltfmaterial_test.cpp +++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llgltfmaterial_test.cpp * - * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * $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$ + * $/LicenseInfo$ */ #include "linden_common.h" @@ -143,7 +143,7 @@ namespace tut #if LL_WINDOWS // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial) // This test result will vary between compilers, so only test a single platform - ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 216); + ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 232); #endif #endif ensure_equals("LLGLTFMaterial texture info count", (U32)LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, 4); diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index a0314cb5f2..69e1b57245 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -49,6 +49,7 @@ set(llui_SOURCE_FILES lllineeditor.cpp llloadingindicator.cpp lllocalcliprect.cpp + llluafloater.cpp llmenubutton.cpp llmenugl.cpp llmodaldialog.cpp @@ -164,6 +165,7 @@ set(llui_HEADER_FILES lllineeditor.h llloadingindicator.h lllocalcliprect.h + llluafloater.h llmenubutton.h llmenugl.h llmodaldialog.h diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index aa3d1a1171..8316101264 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-12 * @brief Implementation for llfloaterreglistener. - * + * * $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$ */ @@ -37,6 +37,7 @@ #include "llfloaterreg.h" #include "llfloater.h" #include "llbutton.h" +#include "llluafloater.h" LLFloaterRegListener::LLFloaterRegListener(): LLEventAPI("LLFloaterReg", @@ -72,6 +73,13 @@ LLFloaterRegListener::LLFloaterRegListener(): "Simulate clicking the named [\"button\"] in the visible floater named in [\"name\"]", &LLFloaterRegListener::clickButton, requiredNameButton); + + add("showLuaFloater", + "Open the new floater using XML file specified in [\"xml_path\"] with ID in [\"reqid\"]", + &LLLuaFloater::showLuaFloater, {llsd::map("xml_path", LLSD(), "reqid", LLSD())}); + add("getFloaterEvents", + "Return the table of Lua Floater events which are send to the script", + &LLFloaterRegListener::getLuaFloaterEvents); } void LLFloaterRegListener::getBuildMap(const LLSD& event) const @@ -154,3 +162,9 @@ void LLFloaterRegListener::clickButton(const LLSD& event) const LLEventPumps::instance().obtain(replyPump).post(reply); } } + +void LLFloaterRegListener::getLuaFloaterEvents(const LLSD &event) const +{ + Response response(llsd::map("events", LLLuaFloater::getEventsData()), event); +} + diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index a36072892c..9cb0af2de5 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-12 * @brief Wrap (subset of) LLFloaterReg API with an event API - * + * * $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$ */ @@ -49,6 +49,8 @@ private: void toggleInstance(const LLSD& event) const; void instanceVisible(const LLSD& event) const; void clickButton(const LLSD& event) const; + + void getLuaFloaterEvents(const LLSD &event) const; }; #endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */ diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp new file mode 100644 index 0000000000..e584a67a00 --- /dev/null +++ b/indra/llui/llluafloater.cpp @@ -0,0 +1,295 @@ +/** + * @file llluafloater.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 "llluafloater.h" + +#include "fsyspath.h" +#include "llevents.h" + +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llscrolllistctrl.h" +#include "lltexteditor.h" + +const std::string LISTENER_NAME("LLLuaFloater"); + +std::set<std::string> EVENT_LIST = { + "commit", + "double_click", + "mouse_enter", + "mouse_leave", + "mouse_down", + "mouse_up", + "right_mouse_down", + "right_mouse_up", + "post_build", + "floater_close", + "keystroke" +}; + +LLLuaFloater::LLLuaFloater(const LLSD &key) : + LLFloater(key), + mDispatchListener(LLUUID::generateNewID().asString(), "action"), + mReplyPumpName(key["reply"].asString()), + mReqID(key) +{ + auto ctrl_lookup = [this](const LLSD &event, std::function<LLSD(LLUICtrl*,const LLSD&)> cb) + { + LLUICtrl *ctrl = getChild<LLUICtrl>(event["ctrl_name"].asString()); + if (!ctrl) + { + LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL; + return LLSD(); + } + return cb(ctrl, event); + }; + + LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD()); + mDispatchListener.add("set_enabled", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setEnabled(event["value"].asBoolean()); return LLSD(); }); + }, requiredParams); + mDispatchListener.add("set_visible", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setVisible(event["value"].asBoolean()); return LLSD(); }); + }, requiredParams); + mDispatchListener.add("set_value", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setValue(event["value"]); return LLSD(); }); + }, requiredParams); + + mDispatchListener.add("add_list_element", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString()); + if(ctrl) + { + LLSD element_data = event["value"]; + if (element_data.isArray()) + { + for (const auto &row : llsd::inArray(element_data)) + { + ctrl->addElement(row); + } + } + else + { + ctrl->addElement(element_data); + } + } + }, requiredParams); + + mDispatchListener.add("add_text", "", [this](const LLSD &event) + { + LLTextEditor *editor = getChild<LLTextEditor>(event["ctrl_name"].asString()); + if (editor) + { + editor->pasteTextWithLinebreaks(stringize(event["value"])); + editor->addLineBreakChar(true); + } + }, requiredParams); + + mDispatchListener.add("set_title", "", [this](const LLSD &event) + { + setTitle(event["value"].asString()); + }, llsd::map("value", LLSD())); + + mDispatchListener.add("get_value", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { return llsd::map("value", ctrl->getValue()); }); + }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); +} + +LLLuaFloater::~LLLuaFloater() +{ + //post empty LLSD() to indicate done, in case it wasn't handled by the script after CLOSE_EVENT + post(LLSD()); +} + +BOOL LLLuaFloater::postBuild() +{ + for (LLView *view : *getChildList()) + { + LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(view); + if (ctrl) + { + LLSD data; + data["ctrl_name"] = view->getName(); + + ctrl->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) + { + LLSD event(data); + event["value"] = ctrl->getValue(); + postEvent(event, "commit"); + }); + } + } + + //optional field to send additional specified events to the script + if (mKey.has("extra_events")) + { + //the first value is ctrl name, the second contains array of events to send + for (const auto &[name, data] : llsd::inMap(mKey["extra_events"])) + { + for (const auto &event : llsd::inArray(data)) + { + registerCallback(name, event); + } + } + } + + //send pump name to the script after the floater is built + postEvent(llsd::map("command_name", mDispatchListener.getPumpName()), "post_build"); + + return true; +} + +void LLLuaFloater::onClose(bool app_quitting) +{ + postEvent(llsd::map("app_quitting", app_quitting), "floater_close"); +} + +bool event_is(const std::string &event_name, const std::string &list_event) +{ + llassert(EVENT_LIST.find(list_event) != EVENT_LIST.end()); + return (event_name == list_event); +} + +void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::string &event) +{ + LLUICtrl *ctrl = getChild<LLUICtrl>(ctrl_name); + if (!ctrl) return; + + LLSD data; + data["ctrl_name"] = ctrl_name; + data["event"] = event; + + auto mouse_event_cb = [this, data](LLUICtrl *ctrl, const LLSD ¶m) { post(data); }; + + auto mouse_event_coords_cb = [this, data](LLUICtrl *ctrl, S32 x, S32 y, MASK mask) + { + LLSD event(data); + post(event.with("x", x).with("y", y)); + }; + + auto post_with_value = [this, data](LLSD value) + { + LLSD event(data); + post(event.with("value", value)); + }; + + if (event_is(event, "mouse_enter")) + { + ctrl->setMouseEnterCallback(mouse_event_cb); + } + else if (event_is(event, "mouse_leave")) + { + ctrl->setMouseLeaveCallback(mouse_event_cb); + } + else if (event_is(event, "mouse_down")) + { + ctrl->setMouseDownCallback(mouse_event_coords_cb); + } + else if (event_is(event, "mouse_up")) + { + ctrl->setMouseUpCallback(mouse_event_coords_cb); + } + else if (event_is(event, "right_mouse_down")) + { + ctrl->setRightMouseDownCallback(mouse_event_coords_cb); + } + else if (event_is(event, "right_mouse_up")) + { + ctrl->setRightMouseUpCallback(mouse_event_coords_cb); + } + else if (event_is(event, "double_click")) + { + LLScrollListCtrl *list = dynamic_cast<LLScrollListCtrl *>(ctrl); + if (list) + { + list->setDoubleClickCallback( [post_with_value, list](){ post_with_value(LLSD(list->getCurrentID())); }); + } + else + { + ctrl->setDoubleClickCallback(mouse_event_coords_cb); + } + } + else if (event_is(event, "keystroke")) + { + LLTextEditor* text_editor = dynamic_cast<LLTextEditor*>(ctrl); + if (text_editor) + { + text_editor->setKeystrokeCallback([post_with_value](LLTextEditor *editor) { post_with_value(editor->getValue()); }); + } + LLLineEditor* line_editor = dynamic_cast<LLLineEditor*>(ctrl); + if (line_editor) + { + line_editor->setKeystrokeCallback([post_with_value](LLLineEditor *editor, void* userdata) { post_with_value(editor->getValue()); }, NULL); + } + } + else + { + LL_WARNS("LuaFloater") << "Can't register callback for unknown event: " << event << " , control: " << ctrl_name << LL_ENDL; + } +} + +void LLLuaFloater::post(const LLSD &data) +{ + // send event data to the script signed with ["reqid"] key + LLSD stamped_data(data); + mReqID.stamp(stamped_data); + LLEventPumps::instance().obtain(mReplyPumpName).post(stamped_data); +} + +void LLLuaFloater::postEvent(LLSD data, const std::string &event_name) +{ + llassert(EVENT_LIST.find(event_name) != EVENT_LIST.end()); + post(data.with("event", event_name)); +} + +void LLLuaFloater::showLuaFloater(const LLSD &data) +{ + fsyspath fs_path(data["xml_path"].asString()); + std::string path = fs_path.lexically_normal().u8string(); + if (!fs_path.is_absolute()) + { + std::string lib_path = gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"); + path = (fsyspath(lib_path) / path).u8string(); + } + + LLLuaFloater *floater = new LLLuaFloater(data); + floater->buildFromFile(path); + floater->openFloater(floater->getKey()); +} + +LLSD LLLuaFloater::getEventsData() +{ + LLSD event_data; + for (auto &it : EVENT_LIST) + { + event_data.append(it); + } + return event_data; +} diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h new file mode 100644 index 0000000000..ccc3ccb39b --- /dev/null +++ b/indra/llui/llluafloater.h @@ -0,0 +1,54 @@ +/** + * @file llluafloater.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_LLLUAFLOATER_H +#define LL_LLLUAFLOATER_H + +#include "llfloater.h" +#include "lleventdispatcher.h" +#include "llevents.h" + +class LLLuaFloater : public LLFloater +{ +public: + LLLuaFloater(const LLSD &key); + BOOL postBuild(); + virtual ~LLLuaFloater(); + + void registerCallback(const std::string &ctrl_name, const std::string &event); + void onClose(bool app_quitting); + + void post(const LLSD &data); + void postEvent(LLSD data, const std::string &event); + static void showLuaFloater(const LLSD &data); + static LLSD getEventsData(); + +private: + LLReqID mReqID; + LLDispatchListener mDispatchListener; + + std::string mReplyPumpName; +}; +#endif diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 72e041672a..fdbfb38474 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -1,25 +1,25 @@ -/** +/** * @file llmenugl.h * @brief Declaration of the opengl based menu system. * * $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$ */ @@ -45,183 +45,183 @@ extern S32 MENU_BAR_WIDTH; class LLMenuKeyboardBinding { public: - KEY mKey; - MASK mMask; + KEY mKey; + MASK mMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // -// The LLMenuItemGL represents a single menu item in a menu. +// The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<std::string> shortcut; - Optional<KEY> jump_key; - Optional<bool> use_mac_ctrl, - allow_key_repeat; - - Ignored rect, - left, - top, - right, - bottom, - width, - height, - bottom_delta, - left_delta; - - Optional<LLUIColor> enabled_color, - disabled_color, - highlight_bg_color, - highlight_fg_color; - - - Params(); - }; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<std::string> shortcut; + Optional<KEY> jump_key; + Optional<bool> use_mac_ctrl, + allow_key_repeat; + + Ignored rect, + left, + top, + right, + bottom, + width, + height, + bottom_delta, + left_delta; + + Optional<LLUIColor> enabled_color, + disabled_color, + highlight_bg_color, + highlight_fg_color; + + + Params(); + }; protected: - LLMenuItemGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemGL(const Params&); + friend class LLUICtrlFactory; public: - // LLView overrides - /*virtual*/ void onVisibilityChange(BOOL new_visibility); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - - // LLUICtrl overrides - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ LLSD getValue() const; - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } - - void setJumpKey(KEY key); - KEY getJumpKey() const { return mJumpKey; } - - // set the font used by this item. - void setFont(const LLFontGL* font) { mFont = font; } - const LLFontGL* getFont() const { return mFont; } - - // returns the height in pixels for the current font. - virtual U32 getNominalHeight( void ) const; - - // Marks item as not needing space for check marks or accelerator keys - virtual void setBriefItem(BOOL brief); - virtual BOOL isBriefItem() const; - - virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp); - void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } - BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } - - // change the label - void setLabel( const LLStringExplicit& label ) { mLabel = label; } - std::string getLabel( void ) const { return mLabel.getString(); } - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - - // Get the parent menu for this item - virtual class LLMenuGL* getMenu() const; - - // returns the normal width of this control in pixels - this is - // used for calculating the widest item, as well as for horizontal - // arrangement. - virtual U32 getNominalWidth( void ) const; - - // buildDrawLabel() - constructs the string used during the draw() - // function. This reduces the overall string manipulation, but can - // lead to visual errors if the state of the object changes - // without the knowledge of the menu item. For example, if a - // boolean being watched is changed outside of the menu item's - // onCommit() function, the draw buffer will not be updated and will - // reflect the wrong value. If this ever becomes an issue, there - // are ways to fix this. - // Returns the enabled state of the item. - virtual void buildDrawLabel( void ); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateBranchParent( LLView* parentp ){}; - - virtual void onCommit( void ); - - virtual void setHighlight( BOOL highlight ); - virtual BOOL getHighlight() const { return mHighlight; } - - // determine if this represents an active sub-menu - virtual BOOL isActive( void ) const { return FALSE; } - - // determine if this represents an open sub-menu - virtual BOOL isOpen( void ) const { return FALSE; } - - virtual void setEnabledSubMenus(BOOL enable){}; - - // LLView Functionality - virtual BOOL handleKeyHere( KEY key, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - - virtual void draw( void ); - - BOOL getHover() const { return mGotHover; } - - void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } - BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } + // LLView overrides + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + + // LLUICtrl overrides + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } + + void setJumpKey(KEY key); + KEY getJumpKey() const { return mJumpKey; } + + // set the font used by this item. + void setFont(const LLFontGL* font) { mFont = font; } + const LLFontGL* getFont() const { return mFont; } + + // returns the height in pixels for the current font. + virtual U32 getNominalHeight( void ) const; + + // Marks item as not needing space for check marks or accelerator keys + virtual void setBriefItem(BOOL brief); + virtual BOOL isBriefItem() const; + + virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp); + void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } + BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } + + // change the label + void setLabel( const LLStringExplicit& label ) { mLabel = label; } + std::string getLabel( void ) const { return mLabel.getString(); } + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + + // Get the parent menu for this item + virtual class LLMenuGL* getMenu() const; + + // returns the normal width of this control in pixels - this is + // used for calculating the widest item, as well as for horizontal + // arrangement. + virtual U32 getNominalWidth( void ) const; + + // buildDrawLabel() - constructs the string used during the draw() + // function. This reduces the overall string manipulation, but can + // lead to visual errors if the state of the object changes + // without the knowledge of the menu item. For example, if a + // boolean being watched is changed outside of the menu item's + // onCommit() function, the draw buffer will not be updated and will + // reflect the wrong value. If this ever becomes an issue, there + // are ways to fix this. + // Returns the enabled state of the item. + virtual void buildDrawLabel( void ); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateBranchParent( LLView* parentp ){}; + + virtual void onCommit( void ); + + virtual void setHighlight( BOOL highlight ); + virtual BOOL getHighlight() const { return mHighlight; } + + // determine if this represents an active sub-menu + virtual BOOL isActive( void ) const { return FALSE; } + + // determine if this represents an open sub-menu + virtual BOOL isOpen( void ) const { return FALSE; } + + virtual void setEnabledSubMenus(BOOL enable){}; + + // LLView Functionality + virtual BOOL handleKeyHere( KEY key, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + virtual void draw( void ); + + BOOL getHover() const { return mGotHover; } + + void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } + BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } protected: - void setHover(BOOL hover) { mGotHover = hover; } + void setHover(BOOL hover) { mGotHover = hover; } - // This function appends the character string representation of - // the current accelerator key and mask to the provided string. - void appendAcceleratorString( std::string& st ) const; + // This function appends the character string representation of + // the current accelerator key and mask to the provided string. + void appendAcceleratorString( std::string& st ) const; - virtual std::string _getSearchText() const - { - return mLabel.getString(); - } + virtual std::string _getSearchText() const + { + return mLabel.getString(); + } protected: - KEY mAcceleratorKey; - MASK mAcceleratorMask; - // mLabel contains the actual label specified by the user. - LLUIString mLabel; - - // The draw labels contain some of the labels that we draw during - // the draw() routine. This optimizes away some of the string - // manipulation. - LLUIString mDrawBoolLabel; - LLUIString mDrawAccelLabel; - LLUIString mDrawBranchLabel; - - LLUIColor mEnabledColor; - LLUIColor mDisabledColor; - LLUIColor mHighlightBackground; - LLUIColor mHighlightForeground; - - BOOL mHighlight; + KEY mAcceleratorKey; + MASK mAcceleratorMask; + // mLabel contains the actual label specified by the user. + LLUIString mLabel; + + // The draw labels contain some of the labels that we draw during + // the draw() routine. This optimizes away some of the string + // manipulation. + LLUIString mDrawBoolLabel; + LLUIString mDrawAccelLabel; + LLUIString mDrawBranchLabel; + + LLUIColor mEnabledColor; + LLUIColor mDisabledColor; + LLUIColor mHighlightBackground; + LLUIColor mHighlightForeground; + + BOOL mHighlight; private: - // Keyboard and mouse variables - BOOL mAllowKeyRepeat; - BOOL mGotHover; + // Keyboard and mouse variables + BOOL mAllowKeyRepeat; + BOOL mGotHover; - // If true, suppress normal space for check marks on the left and accelerator - // keys on the right. - BOOL mBriefItem; + // If true, suppress normal space for check marks on the left and accelerator + // keys on the right. + BOOL mBriefItem; - // Font for this item - const LLFontGL* mFont; - BOOL mDrawTextDisabled; + // Font for this item + const LLFontGL* mFont; + BOOL mDrawTextDisabled; - KEY mJumpKey; + KEY mJumpKey; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,22 +232,22 @@ private: class LLMenuItemSeparatorGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { Optional<EnableCallbackParam > on_visible; Params(); - }; + }; LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params()); - /*virtual*/ void draw( void ); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void draw( void ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); virtual void buildDrawLabel(); - /*virtual*/ U32 getNominalHeight( void ) const; + /*virtual*/ U32 getNominalHeight( void ) const; private: enable_signal_t mVisibleSignal; @@ -263,49 +263,49 @@ private: class LLMenuItemCallGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { - Optional<EnableCallbackParam > on_enable; - Optional<CommitCallbackParam > on_click; - Optional<EnableCallbackParam > on_visible; - Params() - : on_enable("on_enable"), - on_click("on_click"), - on_visible("on_visible") - {} - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { + Optional<EnableCallbackParam > on_enable; + Optional<CommitCallbackParam > on_click; + Optional<EnableCallbackParam > on_visible; + Params() + : on_enable("on_enable"), + on_click("on_click"), + on_visible("on_visible") + {} + }; protected: - LLMenuItemCallGL(const Params&); - friend class LLUICtrlFactory; - void updateEnabled( void ); - void updateVisible( void ); + LLMenuItemCallGL(const Params&); + friend class LLUICtrlFactory; + void updateEnabled( void ); + void updateVisible( void ); public: - void initFromParams(const Params& p); - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - virtual void onCommit( void ); - - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - //virtual void draw(); - - boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) - { - return setCommitCallback(cb); - } - - boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) - { - return mEnableSignal.connect(cb); - } - + void initFromParams(const Params& p); + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + virtual void onCommit( void ); + + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + //virtual void draw(); + + boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) + { + return setCommitCallback(cb); + } + + boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) + { + return mEnableSignal.connect(cb); + } + private: - enable_signal_t mEnableSignal; - enable_signal_t mVisibleSignal; + enable_signal_t mEnableSignal; + enable_signal_t mVisibleSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -318,40 +318,40 @@ private: // EFFICIENT because it may need to be checked a lot. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemCheckGL -: public LLMenuItemCallGL +class LLMenuItemCheckGL +: public LLMenuItemCallGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params> - { - Optional<EnableCallbackParam > on_check; - Params() - : on_check("on_check") - {} - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params> + { + Optional<EnableCallbackParam > on_check; + Params() + : on_check("on_check") + {} + }; protected: - LLMenuItemCheckGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemCheckGL(const Params&); + friend class LLUICtrlFactory; public: - - void initFromParams(const Params& p); - - virtual void onCommit( void ); - - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) - { - return mCheckSignal.connect(cb); - } - + + void initFromParams(const Params& p); + + virtual void onCommit( void ); + + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) + { + return mCheckSignal.connect(cb); + } + private: - enable_signal_t mCheckSignal; + enable_signal_t mCheckSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -368,233 +368,234 @@ private: // child widget registry struct MenuRegistry : public LLChildRegistry<MenuRegistry> { - LLSINGLETON_EMPTY_CTOR(MenuRegistry); + LLSINGLETON_EMPTY_CTOR(MenuRegistry); }; -class LLMenuGL -: public LLUICtrl +class LLMenuGL +: public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<KEY> jump_key; - Optional<bool> horizontal_layout, - can_tear_off, - drop_shadow, - bg_visible, - create_jump_keys, - keep_fixed_size, - scrollable; - Optional<U32> max_scrollable_items; - Optional<U32> preferred_width; - Optional<LLUIColor> bg_color; - Optional<S32> shortcut_pad; - - Params() - : jump_key("jump_key", KEY_NONE), - horizontal_layout("horizontal_layout"), - can_tear_off("tear_off", false), - drop_shadow("drop_shadow", true), - bg_visible("bg_visible", true), - create_jump_keys("create_jump_keys", false), - keep_fixed_size("keep_fixed_size", false), - bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), - scrollable("scrollable", false), - max_scrollable_items("max_scrollable_items", U32_MAX), - preferred_width("preferred_width", U32_MAX), - shortcut_pad("shortcut_pad") - { - addSynonym(bg_visible, "opaque"); - addSynonym(bg_color, "color"); - addSynonym(can_tear_off, "can_tear_off"); - } - }; - - // my valid children are contained in MenuRegistry - typedef MenuRegistry child_registry_t; - - void initFromParams(const Params&); - - // textual artwork which menugl-imitators may want to match - static const std::string BOOLEAN_TRUE_PREFIX; - static const std::string BRANCH_SUFFIX; - static const std::string ARROW_UP; - static const std::string ARROW_DOWN; - - // for scrollable menus - typedef enum e_scrolling_direction - { - SD_UP = 0, - SD_DOWN = 1, - SD_BEGIN = 2, - SD_END = 3 - } EScrollingDirection; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<KEY> jump_key; + Optional<bool> horizontal_layout, + can_tear_off, + drop_shadow, + bg_visible, + create_jump_keys, + keep_fixed_size, + scrollable; + Optional<U32> max_scrollable_items; + Optional<U32> preferred_width; + Optional<LLUIColor> bg_color; + Optional<S32> shortcut_pad; + + Params() + : jump_key("jump_key", KEY_NONE), + horizontal_layout("horizontal_layout"), + can_tear_off("tear_off", false), + drop_shadow("drop_shadow", true), + bg_visible("bg_visible", true), + create_jump_keys("create_jump_keys", false), + keep_fixed_size("keep_fixed_size", false), + bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), + scrollable("scrollable", false), + max_scrollable_items("max_scrollable_items", U32_MAX), + preferred_width("preferred_width", U32_MAX), + shortcut_pad("shortcut_pad") + { + addSynonym(bg_visible, "opaque"); + addSynonym(bg_color, "color"); + addSynonym(can_tear_off, "can_tear_off"); + } + }; + + // my valid children are contained in MenuRegistry + typedef MenuRegistry child_registry_t; + + void initFromParams(const Params&); + + // textual artwork which menugl-imitators may want to match + static const std::string BOOLEAN_TRUE_PREFIX; + static const std::string BRANCH_SUFFIX; + static const std::string ARROW_UP; + static const std::string ARROW_DOWN; + + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; protected: - LLMenuGL(const LLMenuGL::Params& p); - friend class LLUICtrlFactory; - // let branching menu items use my protected traversal methods - friend class LLMenuItemBranchGL; + LLMenuGL(const LLMenuGL::Params& p); + friend class LLUICtrlFactory; + // let branching menu items use my protected traversal methods + friend class LLMenuItemBranchGL; public: - virtual ~LLMenuGL( void ); - - void parseChildXML(LLXMLNodePtr child, LLView* parent); - - // LLView Functionality - /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - /*virtual*/ void draw( void ); - /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + virtual ~LLMenuGL( void ); + + void parseChildXML(LLXMLNodePtr child, LLView* parent); + + // LLView Functionality + /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + /*virtual*/ void draw( void ); + /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void deleteAllChildren(); - /*virtual*/ void removeChild( LLView* ctrl); - /*virtual*/ BOOL postBuild(); - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; - - BOOL clearHoverItem(); - - // return the name label - const std::string& getLabel( void ) const { return mLabel.getString(); } - void setLabel(const LLStringExplicit& label) { mLabel = label; } - - // background colors - void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } - const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } - void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - void setCanTearOff(BOOL tear_off); - - // add a separator to this menu - virtual BOOL addSeparator(); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateParent( LLView* parentp ); - - // setItemEnabled() - pass the name and the enable flag for a - // menu item. TRUE will make sure it's enabled, FALSE will disable - // it. - void setItemEnabled( const std::string& name, BOOL enable ); - - // propagate message to submenus - void setEnabledSubMenus(BOOL enable); - - void setItemVisible( const std::string& name, BOOL visible); + /*virtual*/ void removeChild( LLView* ctrl); + /*virtual*/ BOOL postBuild(); + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; + + BOOL clearHoverItem(); + + // return the name label + const std::string& getLabel( void ) const { return mLabel.getString(); } + void setLabel(const LLStringExplicit& label) { mLabel = label; } + + // background colors + void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } + const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } + void setBackgroundVisible( BOOL b ) { mBgVisible = b; } + void setCanTearOff(BOOL tear_off); + + // add a separator to this menu + virtual BOOL addSeparator(); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateParent( LLView* parentp ); + + // setItemEnabled() - pass the name and the enable flag for a + // menu item. TRUE will make sure it's enabled, FALSE will disable + // it. + void setItemEnabled( const std::string& name, BOOL enable ); + + // propagate message to submenus + void setEnabledSubMenus(BOOL enable); + + void setItemVisible( const std::string& name, BOOL visible); void setItemLabel(const std::string &name, const std::string &label); + + // sets the left,bottom corner of menu, useful for popups + void setLeftAndBottom(S32 left, S32 bottom); - // sets the left,bottom corner of menu, useful for popups - void setLeftAndBottom(S32 left, S32 bottom); - - virtual BOOL handleJumpKey(KEY key); + virtual BOOL handleJumpKey(KEY key); - virtual BOOL jumpKeysActive(); + virtual BOOL jumpKeysActive(); - virtual BOOL isOpen(); + virtual BOOL isOpen(); - void needsArrange() { mNeedsArrange = TRUE; } - // Shape this menu to fit the current state of the children, and - // adjust the child rects to fit. This is called automatically - // when you add items. *FIX: We may need to deal with visibility - // arrangement. - virtual void arrange( void ); - void arrangeAndClear( void ); + void needsArrange() { mNeedsArrange = TRUE; } + // Shape this menu to fit the current state of the children, and + // adjust the child rects to fit. This is called automatically + // when you add items. *FIX: We may need to deal with visibility + // arrangement. + virtual void arrange( void ); + void arrangeAndClear( void ); - // remove all items on the menu - void empty( void ); + // remove all items on the menu + void empty( void ); - // erase group of items from menu - void erase( S32 begin, S32 end, bool arrange = true ); + // erase group of items from menu + void erase( S32 begin, S32 end, bool arrange = true ); - // add new item at position - void insert( S32 begin, LLView * ctrl, bool arrange = true ); + // add new item at position + void insert( S32 begin, LLView * ctrl, bool arrange = true ); - void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items - LLMenuItemGL* getItem(S32 number); // 0 = first item + void setItemLastSelected(LLMenuItemGL* item); // must be in menu + U32 getItemCount(); // number of menu items + LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getItem(std::string name); - LLMenuItemGL* getHighlightedItem(); + LLMenuItemGL* getHighlightedItem(); - LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - void buildDrawLabels(); - void createJumpKeys(); + void buildDrawLabels(); + void createJumpKeys(); - // Show popup at a specific location, in the spawn_view's coordinate frame - static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); + // Show popup at a specific location, in the spawn_view's coordinate frame + static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); - // Whether to drop shadow menu bar - void setDropShadowed( const BOOL shadowed ); + // Whether to drop shadow menu bar + void setDropShadowed( const BOOL shadowed ); - void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } - LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); } + void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } + LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); } - void setTornOff(BOOL torn_off); - BOOL getTornOff() { return mTornOff; } + void setTornOff(BOOL torn_off); + BOOL getTornOff() { return mTornOff; } - BOOL getCanTearOff() { return mTearOffItem != NULL; } + BOOL getCanTearOff() { return mTearOffItem != NULL; } - KEY getJumpKey() const { return mJumpKey; } - void setJumpKey(KEY key) { mJumpKey = key; } + KEY getJumpKey() const { return mJumpKey; } + void setJumpKey(KEY key) { mJumpKey = key; } - static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } - static BOOL getKeyboardMode() { return sKeyboardMode; } + static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } + static BOOL getKeyboardMode() { return sKeyboardMode; } - S32 getShortcutPad() { return mShortcutPad; } + S32 getShortcutPad() { return mShortcutPad; } - bool scrollItems(EScrollingDirection direction); - BOOL isScrollable() const { return mScrollable; } + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } - static class LLMenuHolderGL* sMenuContainer; + static class LLMenuHolderGL* sMenuContainer; + + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } - void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } - bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } + void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } + BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } - void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } - BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } + // add a context menu branch + BOOL appendContextSubMenu(LLMenuGL *menu); - // add a context menu branch - BOOL appendContextSubMenu(LLMenuGL *menu); - - const LLFontGL *getFont() const { return mFont; } - - protected: - void createSpilloverBranch(); - void cleanupSpilloverBranch(); // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); // add a menu - this will create a cascading menu - virtual BOOL appendMenu( LLMenuGL* menu ); - - // Used in LLContextMenu and in LLTogleableMenu - // to add an item of context menu branch - bool addContextChild(LLView* view, S32 tab_group); - - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; - item_list_t mItems; - LLMenuItemGL*mFirstVisibleItem; - LLMenuItemGL *mArrowUpItem, *mArrowDownItem; - - typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t; - navigation_key_map_t mJumpKeys; - S32 mLastMouseX; - S32 mLastMouseY; - S32 mMouseVelX; - S32 mMouseVelY; - U32 mMaxScrollableItems; - U32 mPreferredWidth; - BOOL mHorizontalLayout; - BOOL mScrollable; - BOOL mKeepFixedSize; - BOOL mNeedsArrange; + virtual BOOL appendMenu(LLMenuGL *menu); + + const LLFontGL *getFont() const { return mFont; } + +protected: + void createSpilloverBranch(); + void cleanupSpilloverBranch(); + + // Used in LLContextMenu and in LLTogleableMenu + // to add an item of context menu branch + bool addContextChild(LLView* view, S32 tab_group); + + // TODO: create accessor methods for these? + typedef std::list< LLMenuItemGL* > item_list_t; + item_list_t mItems; + LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; + + typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t; + navigation_key_map_t mJumpKeys; + S32 mLastMouseX; + S32 mLastMouseY; + S32 mMouseVelX; + S32 mMouseVelY; + U32 mMaxScrollableItems; + U32 mPreferredWidth; + BOOL mHorizontalLayout; + BOOL mScrollable; + BOOL mKeepFixedSize; + BOOL mNeedsArrange; // Font for top menu items only const LLFontGL* mFont; @@ -602,27 +603,27 @@ public: private: - static LLColor4 sDefaultBackgroundColor; - static BOOL sKeyboardMode; - - BOOL mAlwaysShowMenu; - - LLUIColor mBackgroundColor; - BOOL mBgVisible; - LLHandle<LLView> mParentMenuItem; - LLUIString mLabel; - BOOL mDropShadowed; // Whether to drop shadow - bool mHasSelection; - LLFrameTimer mFadeTimer; - LLTimer mScrollItemsTimer; - BOOL mTornOff; - class LLMenuItemTearOffGL* mTearOffItem; - class LLMenuItemBranchGL* mSpilloverBranch; - LLMenuGL* mSpilloverMenu; - KEY mJumpKey; - BOOL mCreateJumpKeys; - S32 mShortcutPad; - bool mResetScrollPositionOnShow; + static LLColor4 sDefaultBackgroundColor; + static BOOL sKeyboardMode; + + BOOL mAlwaysShowMenu; + + LLUIColor mBackgroundColor; + BOOL mBgVisible; + LLHandle<LLView> mParentMenuItem; + LLUIString mLabel; + BOOL mDropShadowed; // Whether to drop shadow + bool mHasSelection; + LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; + BOOL mTornOff; + class LLMenuItemTearOffGL* mTearOffItem; + class LLMenuItemBranchGL* mSpilloverBranch; + LLMenuGL* mSpilloverMenu; + KEY mJumpKey; + BOOL mCreateJumpKeys; + S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL @@ -637,61 +638,61 @@ private: class LLMenuItemBranchGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { - Optional<LLMenuGL*> branch; - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { + Optional<LLMenuGL*> branch; + }; protected: - LLMenuItemBranchGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemBranchGL(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMenuItemBranchGL(); - - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual ~LLMenuItemBranchGL(); + + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp); + // check if we've used these accelerators already + virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - virtual void onCommit( void ); + virtual void onCommit( void ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - // set the hover status (called by it's menu) and if the object is - // active. This is used for behavior transfer. - virtual void setHighlight( BOOL highlight ); + // set the hover status (called by it's menu) and if the object is + // active. This is used for behavior transfer. + virtual void setHighlight( BOOL highlight ); - virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL isActive() const; + virtual BOOL isActive() const; - virtual BOOL isOpen() const; + virtual BOOL isOpen() const; - LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } + LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } - virtual void updateBranchParent( LLView* parentp ); + virtual void updateBranchParent( LLView* parentp ); - // LLView Functionality - virtual void onVisibilityChange( BOOL curVisibilityIn ); + // LLView Functionality + virtual void onVisibilityChange( BOOL curVisibilityIn ); - virtual void draw(); + virtual void draw(); - virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } + virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } - virtual void openMenu(); + virtual void openMenu(); - virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; private: - LLHandle<LLView> mBranchHandle; + LLHandle<LLView> mBranchHandle; }; // end class LLMenuItemBranchGL @@ -704,44 +705,44 @@ class LLContextMenu : public LLMenuGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> - { - Params() - { - changeDefault(visible, false); - } - }; + struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> + { + Params() + { + changeDefault(visible, false); + } + }; protected: - LLContextMenu(const Params& p); - friend class LLUICtrlFactory; + LLContextMenu(const Params& p); + friend class LLUICtrlFactory; public: - virtual ~LLContextMenu() {} - - // LLView Functionality - // can't set visibility directly, must call show or hide - virtual void setVisible (BOOL visible); + virtual ~LLContextMenu() {} - virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); - virtual void hide (); + // LLView Functionality + // can't set visibility directly, must call show or hide + virtual void setVisible (BOOL visible); + + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); + virtual void hide (); - virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); - virtual bool addChild (LLView* view, S32 tab_group = 0); + virtual bool addChild (LLView* view, S32 tab_group = 0); - LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); } + LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); } - LLView* getSpawningView() const { return mSpawningViewHandle.get(); } - void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; } protected: - BOOL mHoveredAnyItem; - LLMenuItemGL* mHoverItem; - LLRootHandle<LLContextMenu> mHandle; - LLHandle<LLView> mSpawningViewHandle; + BOOL mHoveredAnyItem; + LLMenuItemGL* mHoverItem; + LLRootHandle<LLContextMenu> mHandle; + LLHandle<LLView> mSpawningViewHandle; }; //----------------------------------------------------------------------------- @@ -751,28 +752,28 @@ protected: class LLContextMenuBranch : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { - Mandatory<LLContextMenu*> branch; - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { + Mandatory<LLContextMenu*> branch; + }; - LLContextMenuBranch(const Params&); + LLContextMenuBranch(const Params&); - virtual ~LLContextMenuBranch(); + virtual ~LLContextMenuBranch(); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - // onCommit() - do the primary funcationality of the menu item. - virtual void onCommit( void ); + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); - LLContextMenu* getBranch() { return mBranch.get(); } - void setHighlight( BOOL highlight ); + LLContextMenu* getBranch() { return mBranch.get(); } + void setHighlight( BOOL highlight ); protected: - void showSubMenu(); + void showSubMenu(); - LLHandle<LLContextMenu> mBranch; + LLHandle<LLContextMenu> mBranch; }; @@ -785,42 +786,43 @@ protected: class LLMenuBarGL : public LLMenuGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> - {}; - LLMenuBarGL( const Params& p ); - virtual ~LLMenuBarGL(); + struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> + {}; + LLMenuBarGL( const Params& p ); + virtual ~LLMenuBarGL(); - /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleJumpKey(KEY key); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleJumpKey(KEY key); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ BOOL jumpKeysActive(); + /*virtual*/ void draw(); + /*virtual*/ BOOL jumpKeysActive(); - // add a vertical separator to this menu - virtual BOOL addSeparator(); + // add a vertical separator to this menu + virtual BOOL addSeparator(); - // LLView Functionality - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + // LLView Functionality + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - // Returns x position of rightmost child, usually Help menu - S32 getRightmostMenuEdge(); + // Returns x position of rightmost child, usually Help menu + S32 getRightmostMenuEdge(); - void resetMenuTrigger() { mAltKeyTrigger = FALSE; } + void resetMenuTrigger() { mAltKeyTrigger = FALSE; } -private: // add a menu - this will create a drop down menu. - virtual BOOL appendMenu( LLMenuGL* menu ); - // rearrange the child rects so they fit the shape of the menu - // bar. - virtual void arrange( void ); + virtual BOOL appendMenu(LLMenuGL *menu); - void checkMenuTrigger(); +private: + // rearrange the child rects so they fit the shape of the menu + // bar. + virtual void arrange( void ); - std::list <LLMenuKeyboardBinding*> mAccelerators; - BOOL mAltKeyTrigger; + void checkMenuTrigger(); + + std::list <LLMenuKeyboardBinding*> mAccelerators; + BOOL mAltKeyTrigger; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -831,39 +833,39 @@ private: class LLMenuHolderGL : public LLPanel { public: - struct Params : public LLInitParam::Block<Params, LLPanel::Params> - {}; - LLMenuHolderGL(const Params& p); - virtual ~LLMenuHolderGL() {} + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + {}; + LLMenuHolderGL(const Params& p); + virtual ~LLMenuHolderGL() {} - virtual BOOL hideMenus(); - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - void setCanHide(BOOL can_hide) { mCanHide = can_hide; } + virtual BOOL hideMenus(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + void setCanHide(BOOL can_hide) { mCanHide = can_hide; } - // LLView functionality - virtual void draw(); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + // LLView functionality + virtual void draw(); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - // Close context menus on right mouse up not handled by menus. - /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + // Close context menus on right mouse up not handled by menus. + /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual const LLRect getMenuRect() const { return getLocalRect(); } - LLView*const getVisibleMenu() const; - virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual const LLRect getMenuRect() const { return getLocalRect(); } + LLView*const getVisibleMenu() const; + virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} - static void setActivatedItem(LLMenuItemGL* item); + static void setActivatedItem(LLMenuItemGL* item); - // Need to detect if mouse-up after context menu spawn has moved. - // If not, need to keep the menu up. - static LLCoordGL sContextMenuSpawnPos; + // Need to detect if mouse-up after context menu spawn has moved. + // If not, need to keep the menu up. + static LLCoordGL sContextMenuSpawnPos; private: - static LLHandle<LLView> sItemLastSelectedHandle; - static LLFrameTimer sItemActivationTimer; + static LLHandle<LLView> sItemLastSelectedHandle; + static LLFrameTimer sItemActivationTimer; - BOOL mCanHide; + BOOL mCanHide; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -875,26 +877,26 @@ private: class LLTearOffMenu : public LLFloater { public: - static LLTearOffMenu* create(LLMenuGL* menup); - virtual ~LLTearOffMenu(); + static LLTearOffMenu* create(LLMenuGL* menup); + virtual ~LLTearOffMenu(); - virtual void draw(void); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual void translate(S32 x, S32 y); + virtual void draw(void); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual void translate(S32 x, S32 y); - void updateSize(); + void updateSize(); private: - LLTearOffMenu(LLMenuGL* menup); - - void closeTearOff(); - - LLView* mOldParent; - LLMenuGL* mMenu; - S32 mTargetHeight; + LLTearOffMenu(LLMenuGL* menup); + + void closeTearOff(); + + LLView* mOldParent; + LLMenuGL* mMenu; + S32 mTargetHeight; bool mQuitRequested; }; @@ -907,16 +909,16 @@ private: class LLMenuItemTearOffGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - {}; - - LLMenuItemTearOffGL( const Params& ); + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + {}; - virtual void onCommit(void); - virtual void draw(void); - virtual U32 getNominalHeight() const; + LLMenuItemTearOffGL( const Params& ); + + virtual void onCommit(void); + virtual void draw(void); + virtual U32 getNominalHeight() const; - LLFloater* getParentFloater(); + LLFloater* getParentFloater(); }; @@ -924,13 +926,13 @@ public: class LLEditMenuHandlerMgr { public: - LLEditMenuHandlerMgr& getInstance() { - static LLEditMenuHandlerMgr instance; - return instance; - } - virtual ~LLEditMenuHandlerMgr() {} + LLEditMenuHandlerMgr& getInstance() { + static LLEditMenuHandlerMgr instance; + return instance; + } + virtual ~LLEditMenuHandlerMgr() {} private: - LLEditMenuHandlerMgr() {}; + LLEditMenuHandlerMgr() {}; }; @@ -939,40 +941,40 @@ private: class view_listener_t : public boost::signals2::trackable { public: - virtual bool handleEvent(const LLSD& userdata) = 0; - view_listener_t() { sListeners.insert(this); } - virtual ~view_listener_t() { sListeners.erase(this); } - - static void addEnable(view_listener_t* listener, const std::string& name) - { - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addCommit(view_listener_t* listener, const std::string& name) - { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addMenu(view_listener_t* listener, const std::string& name) - { - // For now, add to both click and enable registries - addEnable(listener, name); - addCommit(listener, name); - } - - static void cleanup() - { - listener_vector_t listeners(sListeners.begin(), sListeners.end()); - sListeners.clear(); - - std::for_each(listeners.begin(), listeners.end(), DeletePointer()); - listeners.clear(); - } + virtual bool handleEvent(const LLSD& userdata) = 0; + view_listener_t() { sListeners.insert(this); } + virtual ~view_listener_t() { sListeners.erase(this); } + + static void addEnable(view_listener_t* listener, const std::string& name) + { + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addCommit(view_listener_t* listener, const std::string& name) + { + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addMenu(view_listener_t* listener, const std::string& name) + { + // For now, add to both click and enable registries + addEnable(listener, name); + addCommit(listener, name); + } + + static void cleanup() + { + listener_vector_t listeners(sListeners.begin(), sListeners.end()); + sListeners.clear(); + + std::for_each(listeners.begin(), listeners.end(), DeletePointer()); + listeners.clear(); + } private: - typedef std::set<view_listener_t*> listener_map_t; - typedef std::vector<view_listener_t*> listener_vector_t; - static listener_map_t sListeners; + typedef std::set<view_listener_t*> listener_map_t; + typedef std::vector<view_listener_t*> listener_vector_t; + static listener_map_t sListeners; }; #endif // LL_LLMENUGL_H diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 4fd650f2da..d6fc7d5377 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltexteditor.cpp * * $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$ */ @@ -32,7 +32,7 @@ #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR #include "llfontgl.h" -#include "llgl.h" // LLGLSUIDefault() +#include "llgl.h" // LLGLSUIDefault() #include "lllocalcliprect.h" #include "llrender.h" #include "llui.h" @@ -64,105 +64,105 @@ #include <queue> #include "llcombobox.h" -// +// // Globals // static LLDefaultChildRegistry::Register<LLTextEditor> r("simple_text_editor"); // Compiler optimization, generate extern template template class LLTextEditor* LLView::getChild<class LLTextEditor>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; // // Constants // -const S32 SPACES_PER_TAB = 4; -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on +const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd { public: - TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(ws) - { - } - virtual ~TextCmdInsert() {} - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString ); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(ws) + { + } + virtual ~TextCmdInsert() {} + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString ); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; + LLWString mWString; }; /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd { public: - TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) - { - } - virtual void blockExtensions() - { - mBlockExtensions = TRUE; - } - virtual BOOL canExtend(S32 pos) const - { - // cannot extend text with custom segments - if (!mSegments.empty()) return FALSE; - - return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) - { - LLWString ws; - ws += wc; - - *delta = insert(editor, pos, ws); - if( *delta > 0 ) - { - mWString += wc; - } - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) + { + } + virtual void blockExtensions() + { + mBlockExtensions = TRUE; + } + virtual BOOL canExtend(S32 pos) const + { + // cannot extend text with custom segments + if (!mSegments.empty()) return FALSE; + + return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) + { + LLWString ws; + ws += wc; + + *delta = insert(editor, pos, ws); + if( *delta > 0 ) + { + mWString += wc; + } + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; - BOOL mBlockExtensions; + LLWString mWString; + BOOL mBlockExtensions; }; @@ -171,30 +171,30 @@ private: class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd { public: - TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) - : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} - - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mOldChar = editor->getWText()[getPosition()]; - overwrite(editor, getPosition(), mChar); - *delta = 0; - return TRUE; - } - virtual S32 undo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mOldChar); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mChar); - return getPosition()+1; - } + TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) + : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} + + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mOldChar = editor->getWText()[getPosition()]; + overwrite(editor, getPosition(), mChar); + *delta = 0; + return TRUE; + } + virtual S32 undo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mOldChar); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mChar); + return getPosition()+1; + } private: - llwchar mChar; - llwchar mOldChar; + llwchar mChar; + llwchar mOldChar; }; /////////////////////////////////////////////////////////////////// @@ -202,114 +202,114 @@ private: class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd { public: - TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : - TextCmd(pos, group_with_next), mLen(len) - { - std::swap(mSegments, segments); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mWString = editor->getWText().substr(getPosition(), mLen); - *delta = remove(editor, getPosition(), mLen ); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString); - return getPosition() + mWString.length(); - } - virtual S32 redo( LLTextBase* editor ) - { - remove(editor, getPosition(), mLen ); - return getPosition(); - } + TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : + TextCmd(pos, group_with_next), mLen(len) + { + std::swap(mSegments, segments); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mWString = editor->getWText().substr(getPosition(), mLen); + *delta = remove(editor, getPosition(), mLen ); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString); + return getPosition() + mWString.length(); + } + virtual S32 redo( LLTextBase* editor ) + { + remove(editor, getPosition(), mLen ); + return getPosition(); + } private: - LLWString mWString; - S32 mLen; + LLWString mWString; + S32 mLen; }; /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() -: default_text("default_text"), - prevalidate_callback("prevalidate_callback"), - embedded_items("embedded_items", false), - ignore_tab("ignore_tab", true), - auto_indent("auto_indent", true), - default_color("default_color"), +: default_text("default_text"), + prevalidate_callback("prevalidate_callback"), + embedded_items("embedded_items", false), + ignore_tab("ignore_tab", true), + auto_indent("auto_indent", true), + default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), - show_context_menu("show_context_menu"), - show_emoji_helper("show_emoji_helper"), - enable_tooltip_paste("enable_tooltip_paste") + show_context_menu("show_context_menu"), + show_emoji_helper("show_emoji_helper"), + enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidate_callback, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : - LLTextBase(p), - mAutoreplaceCallback(), - mBaseDocIsPristine(TRUE), - mPristineCmd( NULL ), - mLastCmd( NULL ), - mDefaultColor( p.default_color() ), - mAutoIndent(p.auto_indent), - mCommitOnFocusLost( p.commit_on_focus_lost), - mAllowEmbeddedItems( p.embedded_items ), - mMouseDownX(0), - mMouseDownY(0), - mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), - mShowContextMenu(p.show_context_menu), - mShowEmojiHelper(p.show_emoji_helper), - mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), - mKeepSelectionOnReturn(false) -{ - mSourceID.generate(); - - //FIXME: use image? - LLViewBorder::Params params; - params.name = "text ed border"; - params.rect = getLocalRect(); - params.bevel_style = LLViewBorder::BEVEL_IN; - params.border_thickness = 1; - params.visible = p.border_visible; - mBorder = LLUICtrlFactory::create<LLViewBorder> (params); - addChild( mBorder ); - setText(p.default_text()); - - mParseOnTheFly = TRUE; + LLTextBase(p), + mAutoreplaceCallback(), + mBaseDocIsPristine(TRUE), + mPristineCmd( NULL ), + mLastCmd( NULL ), + mDefaultColor( p.default_color() ), + mAutoIndent(p.auto_indent), + mCommitOnFocusLost( p.commit_on_focus_lost), + mAllowEmbeddedItems( p.embedded_items ), + mMouseDownX(0), + mMouseDownY(0), + mTabsToNextField(p.ignore_tab), + mPrevalidateFunc(p.prevalidate_callback()), + mShowContextMenu(p.show_context_menu), + mShowEmojiHelper(p.show_emoji_helper), + mEnableTooltipPaste(p.enable_tooltip_paste), + mPassDelete(FALSE), + mKeepSelectionOnReturn(false) +{ + mSourceID.generate(); + + //FIXME: use image? + LLViewBorder::Params params; + params.name = "text ed border"; + params.rect = getLocalRect(); + params.bevel_style = LLViewBorder::BEVEL_IN; + params.border_thickness = 1; + params.visible = p.border_visible; + mBorder = LLUICtrlFactory::create<LLViewBorder> (params); + addChild( mBorder ); + setText(p.default_text()); + + mParseOnTheFly = TRUE; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) { - LLTextBase::initFromParams(p); + LLTextBase::initFromParams(p); - // HACK: text editors always need to be enabled so that we can scroll - LLView::setEnabled(true); + // HACK: text editors always need to be enabled so that we can scroll + LLView::setEnabled(true); - if (p.commit_on_focus_lost.isProvided()) - { - mCommitOnFocusLost = p.commit_on_focus_lost; - } - - updateAllowingLanguageInput(); + if (p.commit_on_focus_lost.isProvided()) + { + mCommitOnFocusLost = p.commit_on_focus_lost; + } + + updateAllowingLanguageInput(); } LLTextEditor::~LLTextEditor() { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid - // Scrollbar is deleted by LLView - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); - // Mark the menu as dead or its retained in memory till shutdown. - LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); - if(menu) - { - menu->die(); - mContextMenuHandle.markDead(); - } + // Scrollbar is deleted by LLView + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); + // Mark the menu as dead or its retained in memory till shutdown. + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if(menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } } //////////////////////////////////////////////////////////// @@ -318,649 +318,649 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { - // validate incoming text if necessary - if (mPrevalidateFunc) - { - LLWString test_text = utf8str_to_wstring(utf8str); - if (!mPrevalidateFunc(test_text)) - { - // not valid text, nothing to do - return; - } - } - - blockUndo(); - deselect(); + // validate incoming text if necessary + if (mPrevalidateFunc) + { + LLWString test_text = utf8str_to_wstring(utf8str); + if (!mPrevalidateFunc(test_text)) + { + // not valid text, nothing to do + return; + } + } - mParseOnTheFly = FALSE; - LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + blockUndo(); + deselect(); + + mParseOnTheFly = FALSE; + LLTextBase::setText(utf8str, input_params); + mParseOnTheFly = TRUE; - resetDirty(); + resetDirty(); } void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap) { - if (search_text_in.empty()) - { - return; - } - - LLWString text = getWText(); - LLWString search_text = utf8str_to_wstring(search_text_in); - if (case_insensitive) - { - LLWStringUtil::toLower(text); - LLWStringUtil::toLower(search_text); - } - - if (mIsSelecting) - { - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - - if (selected_text == search_text) - { - // We already have this word selected, we are searching for the next. - setCursorPos(mCursorPos + search_text.size()); - } - } - - S32 loc = text.find(search_text,mCursorPos); - - // If Maybe we wrapped, search again - if (wrap && (-1 == loc)) - { - loc = text.find(search_text); - } - - // If still -1, then search_text just isn't found. + if (search_text_in.empty()) + { + return; + } + + LLWString text = getWText(); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (case_insensitive) + { + LLWStringUtil::toLower(text); + LLWStringUtil::toLower(search_text); + } + + if (mIsSelecting) + { + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + + if (selected_text == search_text) + { + // We already have this word selected, we are searching for the next. + setCursorPos(mCursorPos + search_text.size()); + } + } + + S32 loc = text.find(search_text,mCursorPos); + + // If Maybe we wrapped, search again + if (wrap && (-1 == loc)) + { + loc = text.find(search_text); + } + + // If still -1, then search_text just isn't found. if (-1 == loc) - { - mIsSelecting = FALSE; - mSelectionEnd = 0; - mSelectionStart = 0; - return; - } - - setCursorPos(loc); + { + mIsSelecting = FALSE; + mSelectionEnd = 0; + mSelectionStart = 0; + return; + } - mIsSelecting = TRUE; - mSelectionEnd = mCursorPos; - mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); + setCursorPos(loc); + + mIsSelecting = TRUE; + mSelectionEnd = mCursorPos; + mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text, - BOOL case_insensitive, BOOL wrap) + BOOL case_insensitive, BOOL wrap) { - BOOL replaced = FALSE; + BOOL replaced = FALSE; - if (search_text_in.empty()) - { - return replaced; - } + if (search_text_in.empty()) + { + return replaced; + } - LLWString search_text = utf8str_to_wstring(search_text_in); - if (mIsSelecting) - { - LLWString text = getWText(); - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (mIsSelecting) + { + LLWString text = getWText(); + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - if (case_insensitive) - { - LLWStringUtil::toLower(selected_text); - LLWStringUtil::toLower(search_text); - } + if (case_insensitive) + { + LLWStringUtil::toLower(selected_text); + LLWStringUtil::toLower(search_text); + } - if (selected_text == search_text) - { - insertText(replace_text); - replaced = TRUE; - } - } + if (selected_text == search_text) + { + insertText(replace_text); + replaced = TRUE; + } + } - selectNext(search_text_in, case_insensitive, wrap); - return replaced; + selectNext(search_text_in, case_insensitive, wrap); + return replaced; } void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive) { - startOfDoc(); - selectNext(search_text, case_insensitive, FALSE); + startOfDoc(); + selectNext(search_text, case_insensitive, FALSE); - BOOL replaced = TRUE; - while ( replaced ) - { - replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); - } + BOOL replaced = TRUE; + while ( replaced ) + { + replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); + } } S32 LLTextEditor::prevWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) - { - cursorPos--; - } - while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) - { - cursorPos--; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) + { + cursorPos--; + } + while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) + { + cursorPos--; + } + return cursorPos; } S32 LLTextEditor::nextWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) - { - cursorPos++; - } - while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) - { - cursorPos++; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) + { + cursorPos++; + } + while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) + { + cursorPos++; + } + return cursorPos; } -const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const +const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const { - static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment; + static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment; - index_segment->setStart(mCursorPos); - index_segment->setEnd(mCursorPos); + index_segment->setStart(mCursorPos); + index_segment->setEnd(mCursorPos); - // find segment index at character to left of cursor (or rightmost edge of selection) - segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); + // find segment index at character to left of cursor (or rightmost edge of selection) + segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); - if (it != mSegments.end()) - { - return *it; - } - else - { - return LLTextSegmentPtr(); - } + if (it != mSegments.end()) + { + return *it; + } + else + { + return LLTextSegmentPtr(); + } } void LLTextEditor::getSelectedSegments(LLTextEditor::segment_vec_t& segments) const { - S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; - S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; - return getSegmentsInRange(segments, left, right, true); + return getSegmentsInRange(segments, left, right, true); } void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, S32 start, S32 end, bool include_partial) const { - segment_set_t::const_iterator first_it = getSegIterContaining(start); - segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); - if (end_it != mSegments.end()) ++end_it; + segment_set_t::const_iterator first_it = getSegIterContaining(start); + segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); + if (end_it != mSegments.end()) ++end_it; - for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) - { - LLTextSegmentPtr segment = *it; - if (include_partial - || (segment->getStart() >= start - && segment->getEnd() <= end)) - { - segments_out.push_back(segment); - } - } + for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) + { + LLTextSegmentPtr segment = *it; + if (include_partial + || (segment->getStart() >= start + && segment->getEnd() <= end)) + { + segments_out.push_back(segment); + } + } } void LLTextEditor::setShowEmojiHelper(bool show) { - if (!mShowEmojiHelper) - { - LLEmojiHelper::instance().hideHelper(this); - } + if (!mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } - mShowEmojiHelper = show; + mShowEmojiHelper = show; } BOOL LLTextEditor::selectionContainsLineBreaks() { - if (hasSelection()) - { - S32 left = llmin(mSelectionStart, mSelectionEnd); - S32 right = left + llabs(mSelectionStart - mSelectionEnd); + if (hasSelection()) + { + S32 left = llmin(mSelectionStart, mSelectionEnd); + S32 right = left + llabs(mSelectionStart - mSelectionEnd); - LLWString wtext = getWText(); - for( S32 i = left; i < right; i++ ) - { - if (wtext[i] == '\n') - { - return TRUE; - } - } - } - return FALSE; + LLWString wtext = getWText(); + for( S32 i = left; i < right; i++ ) + { + if (wtext[i] == '\n') + { + return TRUE; + } + } + } + return FALSE; } S32 LLTextEditor::indentLine( S32 pos, S32 spaces ) { - // Assumes that pos is at the start of the line - // spaces may be positive (indent) or negative (unindent). - // Returns the actual number of characters added or removed. - - llassert(pos >= 0); - llassert(pos <= getLength() ); - - S32 delta_spaces = 0; - - if (spaces >= 0) - { - // Indent - for(S32 i=0; i < spaces; i++) - { - delta_spaces += addChar(pos, ' '); - } - } - else - { - // Unindent - for(S32 i=0; i < -spaces; i++) - { - LLWString wtext = getWText(); - if (wtext[pos] == ' ') - { - delta_spaces += remove( pos, 1, FALSE ); - } - } - } - - return delta_spaces; + // Assumes that pos is at the start of the line + // spaces may be positive (indent) or negative (unindent). + // Returns the actual number of characters added or removed. + + llassert(pos >= 0); + llassert(pos <= getLength() ); + + S32 delta_spaces = 0; + + if (spaces >= 0) + { + // Indent + for(S32 i=0; i < spaces; i++) + { + delta_spaces += addChar(pos, ' '); + } + } + else + { + // Unindent + for(S32 i=0; i < -spaces; i++) + { + LLWString wtext = getWText(); + if (wtext[pos] == ' ') + { + delta_spaces += remove( pos, 1, FALSE ); + } + } + } + + return delta_spaces; } void LLTextEditor::indentSelectedLines( S32 spaces ) { - if( hasSelection() ) - { - LLWString text = getWText(); - S32 left = llmin( mSelectionStart, mSelectionEnd ); - S32 right = left + llabs( mSelectionStart - mSelectionEnd ); - BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); - S32 cur = left; - - // Expand left to start of line - while( (cur > 0) && (text[cur] != '\n') ) - { - cur--; - } - left = cur; - if( cur > 0 ) - { - left++; - } - - // Expand right to end of line - if( text[right - 1] == '\n' ) - { - right--; - } - else - { - while( (text[right] != '\n') && (right <= getLength() ) ) - { - right++; - } - } - - // Disabling parsing on the fly to avoid updating text segments - // until all indentation commands are executed. - mParseOnTheFly = FALSE; - - // Find each start-of-line and indent it - do - { - if( text[cur] == '\n' ) - { - cur++; - } - - S32 delta_spaces = indentLine( cur, spaces ); - if( delta_spaces > 0 ) - { - cur += delta_spaces; - } - right += delta_spaces; - - text = getWText(); - - // Find the next new line - while( (cur < right) && (text[cur] != '\n') ) - { - cur++; - } - } - while( cur < right ); - - mParseOnTheFly = TRUE; - - if( (right < getLength()) && (text[right] == '\n') ) - { - right++; - } - - // Set the selection and cursor - if( cursor_on_right ) - { - mSelectionStart = left; - mSelectionEnd = right; - } - else - { - mSelectionStart = right; - mSelectionEnd = left; - } - setCursorPos(mSelectionEnd); - } + if( hasSelection() ) + { + LLWString text = getWText(); + S32 left = llmin( mSelectionStart, mSelectionEnd ); + S32 right = left + llabs( mSelectionStart - mSelectionEnd ); + BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); + S32 cur = left; + + // Expand left to start of line + while( (cur > 0) && (text[cur] != '\n') ) + { + cur--; + } + left = cur; + if( cur > 0 ) + { + left++; + } + + // Expand right to end of line + if( text[right - 1] == '\n' ) + { + right--; + } + else + { + while( (text[right] != '\n') && (right <= getLength() ) ) + { + right++; + } + } + + // Disabling parsing on the fly to avoid updating text segments + // until all indentation commands are executed. + mParseOnTheFly = FALSE; + + // Find each start-of-line and indent it + do + { + if( text[cur] == '\n' ) + { + cur++; + } + + S32 delta_spaces = indentLine( cur, spaces ); + if( delta_spaces > 0 ) + { + cur += delta_spaces; + } + right += delta_spaces; + + text = getWText(); + + // Find the next new line + while( (cur < right) && (text[cur] != '\n') ) + { + cur++; + } + } + while( cur < right ); + + mParseOnTheFly = TRUE; + + if( (right < getLength()) && (text[right] == '\n') ) + { + right++; + } + + // Set the selection and cursor + if( cursor_on_right ) + { + mSelectionStart = left; + mSelectionEnd = right; + } + else + { + mSelectionStart = right; + mSelectionEnd = left; + } + setCursorPos(mSelectionEnd); + } } //virtual BOOL LLTextEditor::canSelectAll() const { - return TRUE; + return TRUE; } // virtual void LLTextEditor::selectAll() { - mSelectionStart = getLength(); - mSelectionEnd = 0; - setCursorPos(mSelectionEnd); - updatePrimary(); + mSelectionStart = getLength(); + mSelectionEnd = 0; + setCursorPos(mSelectionEnd); + updatePrimary(); } void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos) { - setCursorPos(prev_cursor_pos); - startSelection(); - setCursorPos(next_cursor_pos); - endSelection(); + setCursorPos(prev_cursor_pos); + startSelection(); + setCursorPos(next_cursor_pos); + endSelection(); } void LLTextEditor::insertEmoji(llwchar emoji) { - LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; - auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); - auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); - insert(mCursorPos, LLWString(1, emoji), false, segment); - setCursorPos(mCursorPos + 1); + LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmoji(); + auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); + insert(mCursorPos, LLWString(1, emoji), false, segment); + setCursorPos(mCursorPos + 1); } void LLTextEditor::handleEmojiCommit(llwchar emoji) { - S32 shortCodePos; - if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) - { - remove(shortCodePos, mCursorPos - shortCodePos, true); - setCursorPos(shortCodePos); + S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) + { + remove(shortCodePos, mCursorPos - shortCodePos, true); + setCursorPos(shortCodePos); - insertEmoji(emoji); - } + insertEmoji(emoji); + } } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // set focus first, in case click callbacks want to change it - // RN: do we really need to have a tab stop? - if (hasTabStop()) - { - setFocus( TRUE ); - } - - // Let scrollbar have first dibs - handled = LLTextBase::handleMouseDown(x, y, mask); - - if( !handled ) - { - if (!(mask & MASK_SHIFT)) - { - deselect(); - } - - BOOL start_select = TRUE; - if( start_select ) - { - // If we're not scrolling (handled by child), then we're selecting - if (mask & MASK_SHIFT) - { - S32 old_cursor_pos = mCursorPos; - setCursorAtLocalPos( x, y, true ); - - if (hasSelection()) - { - mSelectionEnd = mCursorPos; - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = mCursorPos; - } - // assume we're starting a drag select - mIsSelecting = TRUE; - } - else - { - setCursorAtLocalPos( x, y, true ); - startSelection(); - } - } - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if (handled && !gFocusMgr.getMouseCapture()) - { - gFocusMgr.setMouseCapture( this ); - } - return handled; + BOOL handled = FALSE; + + // set focus first, in case click callbacks want to change it + // RN: do we really need to have a tab stop? + if (hasTabStop()) + { + setFocus( TRUE ); + } + + // Let scrollbar have first dibs + handled = LLTextBase::handleMouseDown(x, y, mask); + + if( !handled ) + { + if (!(mask & MASK_SHIFT)) + { + deselect(); + } + + BOOL start_select = TRUE; + if( start_select ) + { + // If we're not scrolling (handled by child), then we're selecting + if (mask & MASK_SHIFT) + { + S32 old_cursor_pos = mCursorPos; + setCursorAtLocalPos( x, y, true ); + + if (hasSelection()) + { + mSelectionEnd = mCursorPos; + } + else + { + mSelectionStart = old_cursor_pos; + mSelectionEnd = mCursorPos; + } + // assume we're starting a drag select + mIsSelecting = TRUE; + } + else + { + setCursorAtLocalPos( x, y, true ); + startSelection(); + } + } + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if (handled && !gFocusMgr.getMouseCapture()) + { + gFocusMgr.setMouseCapture( this ); + } + return handled; } BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - bool show_menu = false; + bool show_menu = false; - // Prefer editor menu if it has selection. See EXT-6806. - if (hasSelection()) - { - S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); - if (click_pos > mSelectionStart && click_pos < mSelectionEnd) - { - show_menu = true; - } - } + // Prefer editor menu if it has selection. See EXT-6806. + if (hasSelection()) + { + S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); + if (click_pos > mSelectionStart && click_pos < mSelectionEnd) + { + show_menu = true; + } + } - // Let segments handle the click, if nothing does, show editor menu - if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) - { - show_menu = true; - } + // Let segments handle the click, if nothing does, show editor menu + if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) + { + show_menu = true; + } - if (show_menu && getShowContextMenu()) - { - showContextMenu(x, y); - } + if (show_menu && getShowContextMenu()) + { + showContextMenu(x, y); + } - return TRUE; + return TRUE; } BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - if (!LLTextBase::handleMouseDown(x, y, mask)) - { - if( canPastePrimary() ) - { - setCursorAtLocalPos( x, y, true ); - // does not rely on focus being set - pastePrimary(); - } - } - return TRUE; + if (!LLTextBase::handleMouseDown(x, y, mask)) + { + if( canPastePrimary() ) + { + setCursorAtLocalPos( x, y, true ); + // does not rely on focus being set + pastePrimary(); + } + } + return TRUE; } BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if(hasMouseCapture() ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - mSelectionEnd = mCursorPos; - } - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - if( !handled ) - { - // Pass to children - handled = LLTextBase::handleHover(x, y, mask); - } - - if( handled ) - { - // Delay cursor flashing - resetCursorBlink(); - } - - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + if(hasMouseCapture() ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + mSelectionEnd = mCursorPos; + } + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + if( !handled ) + { + // Pass to children + handled = LLTextBase::handleHover(x, y, mask); + } + + if( handled ) + { + // Delay cursor flashing + resetCursorBlink(); + } + + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // if I'm not currently selecting text - if (!(mIsSelecting && hasMouseCapture())) - { - // let text segments handle mouse event - handled = LLTextBase::handleMouseUp(x, y, mask); - } - - if( !handled ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - endSelection(); - } - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + // if I'm not currently selecting text + if (!(mIsSelecting && hasMouseCapture())) + { + // let text segments handle mouse event + handled = LLTextBase::handleMouseUp(x, y, mask); + } + + if( !handled ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + endSelection(); + } + + // take selection to 'primary' clipboard + updatePrimary(); + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - // let scrollbar and text segments have first dibs - handled = LLTextBase::handleDoubleClick(x, y, mask); + // let scrollbar and text segments have first dibs + handled = LLTextBase::handleDoubleClick(x, y, mask); - if( !handled ) - { - setCursorAtLocalPos( x, y, false ); - deselect(); + if( !handled ) + { + setCursorAtLocalPos( x, y, false ); + deselect(); - LLWString text = getWText(); + LLWString text = getWText(); + + if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + // Select word the cursor is over + while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) + { + if (!setCursorPos(mCursorPos - 1)) break; + } + startSelection(); - if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) - { - if (!setCursorPos(mCursorPos - 1)) break; - } - startSelection(); - - while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - if (!setCursorPos(mCursorPos + 1)) break; - } - - mSelectionEnd = mCursorPos; - } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - setCursorPos(mCursorPos + 1); - mSelectionEnd = mCursorPos; - } + while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + if (!setCursorPos(mCursorPos + 1)) break; + } + + mSelectionEnd = mCursorPos; + } + else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) + { + // Select the character the cursor is over + startSelection(); + setCursorPos(mCursorPos + 1); + mSelectionEnd = mCursorPos; + } - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection here. + mIsSelecting = FALSE; - // delay cursor flashing - resetCursorBlink(); + // delay cursor flashing + resetCursorBlink(); - // take selection to 'primary' clipboard - updatePrimary(); + // take selection to 'primary' clipboard + updatePrimary(); - handled = TRUE; - } + handled = TRUE; + } - return handled; + return handled; } @@ -969,228 +969,228 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) S32 LLTextEditor::execute( TextCmd* cmd ) { - if (!mReadOnly && mShowEmojiHelper) - { - // Any change to our contents should always hide the helper - LLEmojiHelper::instance().hideHelper(this); - } - - S32 delta = 0; - if( cmd->execute(this, &delta) ) - { - // Delete top of undo stack - undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - std::for_each(mUndoStack.begin(), enditer, DeletePointer()); - mUndoStack.erase(mUndoStack.begin(), enditer); - // Push the new command is now on the top (front) of the undo stack. - mUndoStack.push_front(cmd); - mLastCmd = cmd; - - bool need_to_rollback = mPrevalidateFunc - && !mPrevalidateFunc(getViewModel()->getDisplay()); - if (need_to_rollback) - { - // get rid of this last command and clean up undo stack - undo(); - - // remove any evidence of this command from redo history - mUndoStack.pop_front(); - delete cmd; - - // failure, nothing changed - delta = 0; - } - } - else - { - // Operation failed, so don't put it on the undo stack. - delete cmd; - } - - return delta; + if (!mReadOnly && mShowEmojiHelper) + { + // Any change to our contents should always hide the helper + LLEmojiHelper::instance().hideHelper(this); + } + + S32 delta = 0; + if( cmd->execute(this, &delta) ) + { + // Delete top of undo stack + undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + std::for_each(mUndoStack.begin(), enditer, DeletePointer()); + mUndoStack.erase(mUndoStack.begin(), enditer); + // Push the new command is now on the top (front) of the undo stack. + mUndoStack.push_front(cmd); + mLastCmd = cmd; + + bool need_to_rollback = mPrevalidateFunc + && !mPrevalidateFunc(getViewModel()->getDisplay()); + if (need_to_rollback) + { + // get rid of this last command and clean up undo stack + undo(); + + // remove any evidence of this command from redo history + mUndoStack.pop_front(); + delete cmd; + + // failure, nothing changed + delta = 0; + } + } + else + { + // Operation failed, so don't put it on the undo stack. + delete cmd; + } + + return delta; } S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment) { - return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); + return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); } S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op) { - S32 end_pos = getEditableIndex(pos + length, true); - BOOL removedChar = FALSE; + S32 end_pos = getEditableIndex(pos + length, true); + BOOL removedChar = FALSE; - segment_vec_t segments_to_remove; - // store text segments - getSegmentsInRange(segments_to_remove, pos, pos + length, false); + segment_vec_t segments_to_remove; + // store text segments + getSegmentsInRange(segments_to_remove, pos, pos + length, false); + + if (pos <= end_pos) + { + removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); + } - if (pos <= end_pos) - { - removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); - } - - return removedChar; + return removedChar; } S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) { - if ((S32)getLength() == pos) - { - return addChar(pos, wc); - } - else - { - return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); - } + if ((S32)getLength() == pos) + { + return addChar(pos, wc); + } + else + { + return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); + } } // Remove a single character from the text. Tries to remove // a pseudo-tab (up to for spaces in a row) void LLTextEditor::removeCharOrTab() { - if (!getEnabled()) - { - return; - } - - if (mCursorPos > 0) - { - S32 chars_to_remove = 1; - - LLWString text = getWText(); - if (text[mCursorPos - 1] == ' ') - { - // Try to remove a "tab" - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - if (offset > 0) - { - chars_to_remove = offset % SPACES_PER_TAB; - if (chars_to_remove == 0) - { - chars_to_remove = SPACES_PER_TAB; - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - if (text[mCursorPos - i - 1] != ' ') - { - // Fewer than a full tab's worth of spaces, so - // just delete a single character. - chars_to_remove = 1; - break; - } - } - } - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - setCursorPos(mCursorPos - 1); - remove(mCursorPos, 1, false); - } - - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (!getEnabled()) + { + return; + } + + if (mCursorPos > 0) + { + S32 chars_to_remove = 1; + + LLWString text = getWText(); + if (text[mCursorPos - 1] == ' ') + { + // Try to remove a "tab" + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + if (offset > 0) + { + chars_to_remove = offset % SPACES_PER_TAB; + if (chars_to_remove == 0) + { + chars_to_remove = SPACES_PER_TAB; + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + if (text[mCursorPos - i - 1] != ' ') + { + // Fewer than a full tab's worth of spaces, so + // just delete a single character. + chars_to_remove = 1; + break; + } + } + } + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + setCursorPos(mCursorPos - 1); + remove(mCursorPos, 1, false); + } + + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Remove a single character from the text S32 LLTextEditor::removeChar(S32 pos) { - return remove(pos, 1, false); + return remove(pos, 1, false); } void LLTextEditor::removeChar() { - if (!getEnabled()) - { - return; - } + if (!getEnabled()) + { + return; + } - if (mCursorPos > 0) - { - setCursorPos(mCursorPos - 1); - removeChar(mCursorPos); - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (mCursorPos > 0) + { + setCursorPos(mCursorPos - 1); + removeChar(mCursorPos); + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) - { - make_ui_sound("UISndBadKeystroke"); - return 0; - } - - if (mLastCmd && mLastCmd->canExtend(pos)) - { - S32 delta = 0; - if (mPrevalidateFunc) - { - // get a copy of current text contents - LLWString test_string(getViewModel()->getDisplay()); - - // modify text contents as if this addChar succeeded - llassert(pos <= (S32)test_string.size()); - test_string.insert(pos, 1, wc); - if (!mPrevalidateFunc( test_string)) - { - return 0; - } - } - mLastCmd->extendAndExecute(this, pos, wc, &delta); - - return delta; - } - else - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) + { + make_ui_sound("UISndBadKeystroke"); + return 0; + } + + if (mLastCmd && mLastCmd->canExtend(pos)) + { + S32 delta = 0; + if (mPrevalidateFunc) + { + // get a copy of current text contents + LLWString test_string(getViewModel()->getDisplay()); + + // modify text contents as if this addChar succeeded + llassert(pos <= (S32)test_string.size()); + test_string.insert(pos, 1, wc); + if (!mPrevalidateFunc( test_string)) + { + return 0; + } + } + mLastCmd->extendAndExecute(this, pos, wc, &delta); + + return delta; + } + else + { + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); + } } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } - - setCursorPos(mCursorPos + addChar( mCursorPos, wc )); - tryToShowEmojiHelper(); - - if (!mReadOnly && mAutoreplaceCallback != NULL) - { - // autoreplace the text, if necessary - S32 replacement_start; - S32 replacement_length; - LLWString replacement_string; - S32 new_cursor_pos = mCursorPos; - mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); - - if (replacement_length > 0 || !replacement_string.empty()) - { - remove(replacement_start, replacement_length, true); - insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); - setCursorPos(new_cursor_pos); - } - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + setCursorPos(mCursorPos + addChar( mCursorPos, wc )); + tryToShowEmojiHelper(); + + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // autoreplace the text, if necessary + S32 replacement_start; + S32 replacement_length; + LLWString replacement_string; + S32 new_cursor_pos = mCursorPos; + mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); + + if (replacement_length > 0 || !replacement_string.empty()) + { + remove(replacement_start, replacement_length, true); + insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); + setCursorPos(new_cursor_pos); + } + } } void LLTextEditor::showEmojiHelper() @@ -1226,791 +1226,792 @@ void LLTextEditor::tryToShowEmojiHelper() void LLTextEditor::addLineBreakChar(BOOL group_together) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } - - LLStyleConstSP sp(new LLStyle(LLStyle::Params())); - LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } - S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); + LLStyleConstSP sp(new LLStyle(LLStyle::Params())); + LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); - setCursorPos(mCursorPos + pos); + S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); + + setCursorPos(mCursorPos + pos); } BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - if( mask & MASK_SHIFT ) - { - handled = TRUE; - - switch( key ) - { - case KEY_LEFT: - if( 0 < mCursorPos ) - { - startSelection(); - setCursorPos(mCursorPos - 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(prevWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - startSelection(); - setCursorPos(mCursorPos + 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(nextWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_UP: - startSelection(); - changeLine( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_UP: - startSelection(); - changePage( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_HOME: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(0); - } - else - { - startOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - case KEY_DOWN: - startSelection(); - changeLine( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_DOWN: - startSelection(); - changePage( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_END: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(getLength()); - } - else - { - endOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - default: - handled = FALSE; - break; - } - } - - if( handled ) - { - // take selection to 'primary' clipboard - updatePrimary(); - } - - return handled; + BOOL handled = FALSE; + + if( mask & MASK_SHIFT ) + { + handled = TRUE; + + switch( key ) + { + case KEY_LEFT: + if( 0 < mCursorPos ) + { + startSelection(); + setCursorPos(mCursorPos - 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(prevWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + startSelection(); + setCursorPos(mCursorPos + 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(nextWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_UP: + startSelection(); + changeLine( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_UP: + startSelection(); + changePage( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_HOME: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(0); + } + else + { + startOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + case KEY_DOWN: + startSelection(); + changeLine( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_DOWN: + startSelection(); + changePage( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_END: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(getLength()); + } + else + { + endOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + default: + handled = FALSE; + break; + } + } + + if( handled ) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + + return handled; } BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - // Ignore capslock key - if( MASK_NONE == mask ) - { - handled = TRUE; - switch( key ) - { - case KEY_UP: - changeLine( -1 ); - break; - - case KEY_PAGE_UP: - changePage( -1 ); - break; - - case KEY_HOME: - startOfLine(); - break; - - case KEY_DOWN: - changeLine( 1 ); - deselect(); - break; - - case KEY_PAGE_DOWN: - changePage( 1 ); - break; - - case KEY_END: - endOfLine(); - break; - - case KEY_LEFT: - if( hasSelection() ) - { - setCursorPos(llmin( mSelectionStart, mSelectionEnd )); - } - else - { - if( 0 < mCursorPos ) - { - setCursorPos(mCursorPos - 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - case KEY_RIGHT: - if( hasSelection() ) - { - setCursorPos(llmax( mSelectionStart, mSelectionEnd )); - } - else - { - if( mCursorPos < getLength() ) - { - setCursorPos(mCursorPos + 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled) - { - deselect(); - } - - return handled; + BOOL handled = FALSE; + + // Ignore capslock key + if( MASK_NONE == mask ) + { + handled = TRUE; + switch( key ) + { + case KEY_UP: + changeLine( -1 ); + break; + + case KEY_PAGE_UP: + changePage( -1 ); + break; + + case KEY_HOME: + startOfLine(); + break; + + case KEY_DOWN: + changeLine( 1 ); + deselect(); + break; + + case KEY_PAGE_DOWN: + changePage( 1 ); + break; + + case KEY_END: + endOfLine(); + break; + + case KEY_LEFT: + if( hasSelection() ) + { + setCursorPos(llmin( mSelectionStart, mSelectionEnd )); + } + else + { + if( 0 < mCursorPos ) + { + setCursorPos(mCursorPos - 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + case KEY_RIGHT: + if( hasSelection() ) + { + setCursorPos(llmax( mSelectionStart, mSelectionEnd )); + } + else + { + if( mCursorPos < getLength() ) + { + setCursorPos(mCursorPos + 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled) + { + deselect(); + } + + return handled; } void LLTextEditor::deleteSelection(BOOL group_with_next_op ) { - if( getEnabled() && hasSelection() ) - { - S32 pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); + if( getEnabled() && hasSelection() ) + { + S32 pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + + remove( pos, length, group_with_next_op ); - remove( pos, length, group_with_next_op ); - - deselect(); - setCursorPos(pos); - } + deselect(); + setCursorPos(pos); + } } // virtual BOOL LLTextEditor::canCut() const { - return !mReadOnly && hasSelection(); + return !mReadOnly && hasSelection(); } // cut selection to clipboard void LLTextEditor::cut() { - if( !canCut() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); - deleteSelection( FALSE ); + if( !canCut() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); + deleteSelection( FALSE ); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canCopy() const { - return hasSelection(); + return hasSelection(); } // copy selection to clipboard void LLTextEditor::copy() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(); + return !mReadOnly && LLClipboard::instance().isTextAvailable(); } // paste from clipboard void LLTextEditor::paste() { - bool is_primary = false; - pasteHelper(is_primary); + bool is_primary = false; + pasteHelper(is_primary); } // paste from primary void LLTextEditor::pastePrimary() { - bool is_primary = true; - pasteHelper(is_primary); + bool is_primary = true; + pasteHelper(is_primary); } // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; - bool can_paste_it; - if (is_primary) - { - can_paste_it = canPastePrimary(); - } - else - { - can_paste_it = canPaste(); - } + mParseOnTheFly = FALSE; + bool can_paste_it; + if (is_primary) + { + can_paste_it = canPastePrimary(); + } + else + { + can_paste_it = canPaste(); + } - if (!can_paste_it) - { - return; - } + if (!can_paste_it) + { + return; + } - LLWString paste; - LLClipboard::instance().pasteFromClipboard(paste, is_primary); + LLWString paste; + LLClipboard::instance().pasteFromClipboard(paste, is_primary); - if (paste.empty()) - { - return; - } + if (paste.empty()) + { + return; + } - // Delete any selected characters (the paste replaces them) - if( (!is_primary) && hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the paste replaces them) + if( (!is_primary) && hasSelection() ) + { + deleteSelection(TRUE); + } - // Clean up string (replace tabs and remove characters that our fonts don't support). - LLWString clean_string(paste); - cleanStringForPaste(clean_string); + // Clean up string (replace tabs and remove characters that our fonts don't support). + LLWString clean_string(paste); + cleanStringForPaste(clean_string); - // Insert the new text into the existing text. + // Insert the new text into the existing text. - //paste text with linebreaks. - pasteTextWithLinebreaks(clean_string); + //paste text with linebreaks. + pasteTextWithLinebreaks(clean_string); - deselect(); + deselect(); - onKeyStroke(); - mParseOnTheFly = TRUE; + onKeyStroke(); + mParseOnTheFly = TRUE; } // Clean up string (replace tabs and remove characters that our fonts don't support). void LLTextEditor::cleanStringForPaste(LLWString & clean_string) { - std::string clean_string_utf = wstring_to_utf8str(clean_string); - std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); - clean_string = utf8str_to_wstring(clean_string_utf); - - LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); - if( mAllowEmbeddedItems ) - { - const llwchar LF = 10; - S32 len = clean_string.length(); - for( S32 i = 0; i < len; i++ ) - { - llwchar wc = clean_string[i]; - if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) - { - clean_string[i] = LL_UNKNOWN_CHAR; - } - else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) - { - clean_string[i] = pasteEmbeddedItem(wc); - } - } - } -} - - -void LLTextEditor::pasteTextWithLinebreaks(LLWString & clean_string) -{ - std::basic_string<llwchar>::size_type start = 0; - std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); - - while((pos != -1) && (pos != clean_string.length() -1)) - { - if(pos!=start) - { - std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); - } - addLineBreakChar(TRUE); // Add a line break and group with the next addition. - - start = pos+1; - pos = clean_string.find('\n',start); - } - - if (pos != start) - { - std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); - } - else - { - addLineBreakChar(FALSE); // Add a line break and end the grouping. - } + std::string clean_string_utf = wstring_to_utf8str(clean_string); + std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); + clean_string = utf8str_to_wstring(clean_string_utf); + + LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); + if( mAllowEmbeddedItems ) + { + const llwchar LF = 10; + S32 len = clean_string.length(); + for( S32 i = 0; i < len; i++ ) + { + llwchar wc = clean_string[i]; + if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) + { + clean_string[i] = LL_UNKNOWN_CHAR; + } + else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) + { + clean_string[i] = pasteEmbeddedItem(wc); + } + } + } +} + + +template <> +void LLTextEditor::pasteTextWithLinebreaks<LLWString>(const LLWString & clean_string) +{ + std::basic_string<llwchar>::size_type start = 0; + std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); + + while((pos != -1) && (pos != clean_string.length() -1)) + { + if(pos!=start) + { + std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); + } + addLineBreakChar(TRUE); // Add a line break and group with the next addition. + + start = pos+1; + pos = clean_string.find('\n',start); + } + + if (pos != start) + { + std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); + } + else + { + addLineBreakChar(FALSE); // Add a line break and end the grouping. + } } // copy selection to primary void LLTextEditor::copyPrimary() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(true); + return !mReadOnly && LLClipboard::instance().isTextAvailable(true); } void LLTextEditor::updatePrimary() { - if (canCopy()) - { - copyPrimary(); - } -} - -BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) -{ - BOOL handled = FALSE; - - if( mask & MASK_CONTROL ) - { - handled = TRUE; - - switch( key ) - { - case KEY_HOME: - if( mask & MASK_SHIFT ) - { - startSelection(); - setCursorPos(0); - mSelectionEnd = mCursorPos; - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - startOfDoc(); - } - break; - - case KEY_END: - { - if( mask & MASK_SHIFT ) - { - startSelection(); - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - } - endOfDoc(); - if( mask & MASK_SHIFT ) - { - mSelectionEnd = mCursorPos; - } - break; - } - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(nextWordPos(mCursorPos + 1)); - } - break; - - - case KEY_LEFT: - if( mCursorPos > 0 ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(prevWordPos(mCursorPos - 1)); - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled && !gFocusMgr.getMouseCapture()) - { - updatePrimary(); - } - - return handled; -} - - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) - { - BOOL handled = TRUE; - - if (mReadOnly) return FALSE; - - switch( key ) - { - case KEY_INSERT: - if (mask == MASK_NONE) - { - gKeyboard->toggleInsertMode(); - } - break; - - case KEY_BACKSPACE: - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( 0 < mCursorPos ) - { - removeCharOrTab(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - - case KEY_RETURN: - if (mask == MASK_NONE) - { - if( hasSelection() && !mKeepSelectionOnReturn ) - { - deleteSelection(FALSE); - } - if (mAutoIndent) - { - autoIndent(); - } - } - else - { - handled = FALSE; - break; - } - break; - - case KEY_TAB: - if (mask & MASK_CONTROL) - { - handled = FALSE; - break; - } - if( hasSelection() && selectionContainsLineBreaks() ) - { - indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); - } - else - { - if( hasSelection() ) - { - deleteSelection(FALSE); - } - - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - - S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - for( S32 i=0; i < spaces_needed; i++ ) - { - addChar( ' ' ); - } - } - break; - - default: - handled = FALSE; - break; - } - - if (handled) - { - onKeyStroke(); - } - return handled; + if (canCopy()) + { + copyPrimary(); + } +} + +BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) +{ + BOOL handled = FALSE; + + if( mask & MASK_CONTROL ) + { + handled = TRUE; + + switch( key ) + { + case KEY_HOME: + if( mask & MASK_SHIFT ) + { + startSelection(); + setCursorPos(0); + mSelectionEnd = mCursorPos; + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + startOfDoc(); + } + break; + + case KEY_END: + { + if( mask & MASK_SHIFT ) + { + startSelection(); + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + } + endOfDoc(); + if( mask & MASK_SHIFT ) + { + mSelectionEnd = mCursorPos; + } + break; + } + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(nextWordPos(mCursorPos + 1)); + } + break; + + + case KEY_LEFT: + if( mCursorPos > 0 ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(prevWordPos(mCursorPos - 1)); + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled && !gFocusMgr.getMouseCapture()) + { + updatePrimary(); + } + + return handled; +} + + +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) + { + BOOL handled = TRUE; + + if (mReadOnly) return FALSE; + + switch( key ) + { + case KEY_INSERT: + if (mask == MASK_NONE) + { + gKeyboard->toggleInsertMode(); + } + break; + + case KEY_BACKSPACE: + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( 0 < mCursorPos ) + { + removeCharOrTab(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( hasSelection() && !mKeepSelectionOnReturn ) + { + deleteSelection(FALSE); + } + if (mAutoIndent) + { + autoIndent(); + } + } + else + { + handled = FALSE; + break; + } + break; + + case KEY_TAB: + if (mask & MASK_CONTROL) + { + handled = FALSE; + break; + } + if( hasSelection() && selectionContainsLineBreaks() ) + { + indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); + } + else + { + if( hasSelection() ) + { + deleteSelection(FALSE); + } + + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + + S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + for( S32 i=0; i < spaces_needed; i++ ) + { + addChar( ' ' ); + } + } + break; + + default: + handled = FALSE; + break; + } + + if (handled) + { + onKeyStroke(); + } + return handled; } void LLTextEditor::unindentLineBeforeCloseBrace() { - if( mCursorPos >= 1 ) - { - LLWString text = getWText(); - if( ' ' == text[ mCursorPos - 1 ] ) - { - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); - - // Jump over spaces in the current line - while ((' ' == text[line_start]) && (line_start < mCursorPos)) - { - line_start++; - } - - // Make sure there is nothing but ' ' before the Brace we are unindenting - if (line_start == mCursorPos) - { - removeCharOrTab(); - } - } - } + if( mCursorPos >= 1 ) + { + LLWString text = getWText(); + if( ' ' == text[ mCursorPos - 1 ] ) + { + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + + // Jump over spaces in the current line + while ((' ' == text[line_start]) && (line_start < mCursorPos)) + { + line_start++; + } + + // Make sure there is nothing but ' ' before the Brace we are unindenting + if (line_start == mCursorPos) + { + removeCharOrTab(); + } + } + } } BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - - // Special case for TAB. If want to move to next field, report - // not handled and let the parent take care of field movement. - if (KEY_TAB == key && mTabsToNextField) - { - return FALSE; - } - - if (mReadOnly && mScroller) - { - handled = (mScroller && mScroller->handleKeyHere( key, mask )) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask); - } - else - { - if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) - { - return TRUE; - } - - if (mEnableTooltipPaste && - LLToolTipMgr::instance().toolTipVisible() && + BOOL handled = FALSE; + + // Special case for TAB. If want to move to next field, report + // not handled and let the parent take care of field movement. + if (KEY_TAB == key && mTabsToNextField) + { + return FALSE; + } + + if (mReadOnly && mScroller) + { + handled = (mScroller && mScroller->handleKeyHere( key, mask )) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask); + } + else + { + if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + { + return TRUE; + } + + if (mEnableTooltipPaste && + LLToolTipMgr::instance().toolTipVisible() && LLToolTipMgr::instance().isTooltipPastable() && - KEY_TAB == key) - { // Paste the first line of a tooltip into the editor - std::string message; - LLToolTipMgr::instance().getToolTipMessage(message); - LLWString tool_tip_text(utf8str_to_wstring(message)); - - if (tool_tip_text.size() > 0) - { - // Delete any selected characters (the tooltip text replaces them) - if(hasSelection()) - { - deleteSelection(TRUE); - } - - std::basic_string<llwchar>::size_type pos = tool_tip_text.find('\n',0); - if (pos != -1) - { // Extract the first line of the tooltip - tool_tip_text = std::basic_string<llwchar>(tool_tip_text, 0, pos); - } - - // Add the text - cleanStringForPaste(tool_tip_text); - pasteTextWithLinebreaks(tool_tip_text); - handled = TRUE; - } - } - else - { // Normal key handling - handled = handleNavigationKey( key, mask ) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask) - || handleSpecialKey(key, mask); - } - } - - if( handled ) - { - resetCursorBlink(); - needsScroll(); - - if (mShowEmojiHelper) - { - // Dismiss the helper whenever we handled a key that it didn't - LLEmojiHelper::instance().hideHelper(this); - } - } - - return handled; + KEY_TAB == key) + { // Paste the first line of a tooltip into the editor + std::string message; + LLToolTipMgr::instance().getToolTipMessage(message); + LLWString tool_tip_text(utf8str_to_wstring(message)); + + if (tool_tip_text.size() > 0) + { + // Delete any selected characters (the tooltip text replaces them) + if(hasSelection()) + { + deleteSelection(TRUE); + } + + std::basic_string<llwchar>::size_type pos = tool_tip_text.find('\n',0); + if (pos != -1) + { // Extract the first line of the tooltip + tool_tip_text = std::basic_string<llwchar>(tool_tip_text, 0, pos); + } + + // Add the text + cleanStringForPaste(tool_tip_text); + pasteTextWithLinebreaks(tool_tip_text); + handled = TRUE; + } + } + else + { // Normal key handling + handled = handleNavigationKey( key, mask ) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask) + || handleSpecialKey(key, mask); + } + } + + if( handled ) + { + resetCursorBlink(); + needsScroll(); + + if (mShowEmojiHelper) + { + // Dismiss the helper whenever we handled a key that it didn't + LLEmojiHelper::instance().hideHelper(this); + } + } + + return handled; } BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } - BOOL handled = FALSE; + BOOL handled = FALSE; - // Handle most keys only if the text editor is writeable. - if( !mReadOnly ) - { + // Handle most keys only if the text editor is writeable. + if( !mReadOnly ) + { if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE)) { return TRUE; } if( mAutoIndent && '}' == uni_char ) - { - unindentLineBeforeCloseBrace(); - } + { + unindentLineBeforeCloseBrace(); + } - // TODO: KLW Add auto show of tool tip on ( - addChar( uni_char ); + // TODO: KLW Add auto show of tool tip on ( + addChar( uni_char ); - // Keys that add characters temporarily hide the cursor - getWindow()->hideCursorUntilMouseMove(); + // Keys that add characters temporarily hide the cursor + getWindow()->hideCursorUntilMouseMove(); - handled = TRUE; - } + handled = TRUE; + } - if( handled ) - { - resetCursorBlink(); + if( handled ) + { + resetCursorBlink(); - // Most keystrokes will make the selection box go away, but not all will. - deselect(); + // Most keystrokes will make the selection box go away, but not all will. + deselect(); - onKeyStroke(); - } + onKeyStroke(); + } - return handled; + return handled; } // virtual BOOL LLTextEditor::canDoDelete() const { - return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); + return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); } void LLTextEditor::doDelete() { - if( !canDoDelete() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( mCursorPos < getLength() ) - { - S32 i; - S32 chars_to_remove = 1; - LLWString text = getWText(); - if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) - { - // Try to remove a full tab's worth of spaces - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - if( chars_to_remove == 0 ) - { - chars_to_remove = SPACES_PER_TAB; - } - - for( i = 0; i < chars_to_remove; i++ ) - { - if( text[mCursorPos + i] != ' ' ) - { - chars_to_remove = 1; - break; - } - } - } - - for( i = 0; i < chars_to_remove; i++ ) - { - setCursorPos(mCursorPos + 1); - removeChar(); - } - - } - - onKeyStroke(); + if( !canDoDelete() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( mCursorPos < getLength() ) + { + S32 i; + S32 chars_to_remove = 1; + LLWString text = getWText(); + if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) + { + // Try to remove a full tab's worth of spaces + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + if( chars_to_remove == 0 ) + { + chars_to_remove = SPACES_PER_TAB; + } + + for( i = 0; i < chars_to_remove; i++ ) + { + if( text[mCursorPos + i] != ' ' ) + { + chars_to_remove = 1; + break; + } + } + } + + for( i = 0; i < chars_to_remove; i++ ) + { + setCursorPos(mCursorPos + 1); + removeChar(); + } + + } + + onKeyStroke(); } //---------------------------------------------------------------------------- @@ -2018,624 +2019,624 @@ void LLTextEditor::doDelete() void LLTextEditor::blockUndo() { - mBaseDocIsPristine = FALSE; - mLastCmd = NULL; - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); + mBaseDocIsPristine = FALSE; + mLastCmd = NULL; + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); } // virtual BOOL LLTextEditor::canUndo() const { - return !mReadOnly && mLastCmd != NULL; + return !mReadOnly && mLastCmd != NULL; } void LLTextEditor::undo() { - if( !canUndo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - pos = mLastCmd->undo(this); - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.end()) - ++iter; - if (iter != mUndoStack.end()) - mLastCmd = *iter; - else - mLastCmd = NULL; + if( !canUndo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + pos = mLastCmd->undo(this); + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.end()) + ++iter; + if (iter != mUndoStack.end()) + mLastCmd = *iter; + else + mLastCmd = NULL; - } while( mLastCmd && mLastCmd->groupWithNext() ); + } while( mLastCmd && mLastCmd->groupWithNext() ); - setCursorPos(pos); + setCursorPos(pos); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canRedo() const { - return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); + return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); } void LLTextEditor::redo() { - if( !canRedo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - if( !mLastCmd ) - { - mLastCmd = mUndoStack.back(); - } - else - { - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.begin()) - mLastCmd = *(--iter); - else - mLastCmd = NULL; - } - - if( mLastCmd ) - { - pos = mLastCmd->redo(this); - } - } while( - mLastCmd && - mLastCmd->groupWithNext() && - (mLastCmd != mUndoStack.front()) ); - - setCursorPos(pos); - - onKeyStroke(); + if( !canRedo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + if( !mLastCmd ) + { + mLastCmd = mUndoStack.back(); + } + else + { + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.begin()) + mLastCmd = *(--iter); + else + mLastCmd = NULL; + } + + if( mLastCmd ) + { + pos = mLastCmd->redo(this); + } + } while( + mLastCmd && + mLastCmd->groupWithNext() && + (mLastCmd != mUndoStack.front()) ); + + setCursorPos(pos); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() { - LLTextBase::onFocusReceived(); - updateAllowingLanguageInput(); + LLTextBase::onFocusReceived(); + updateAllowingLanguageInput(); } void LLTextEditor::focusLostHelper() { - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - if (mCommitOnFocusLost) - { - onCommit(); - } + if (mCommitOnFocusLost) + { + onCommit(); + } - // Make sure cursor is shown again - getWindow()->showCursorFromMouseMove(); + // Make sure cursor is shown again + getWindow()->showCursorFromMouseMove(); } void LLTextEditor::onFocusLost() { - focusLostHelper(); - LLTextBase::onFocusLost(); + focusLostHelper(); + LLTextBase::onFocusLost(); } void LLTextEditor::onCommit() { - setControlValue(getValue()); - LLTextBase::onCommit(); + setControlValue(getValue()); + LLTextBase::onCommit(); } void LLTextEditor::setEnabled(BOOL enabled) { - // just treat enabled as read-only flag - bool read_only = !enabled; - if (read_only != mReadOnly) - { - //mReadOnly = read_only; - LLTextBase::setReadOnly(read_only); - updateSegments(); - updateAllowingLanguageInput(); - } + // just treat enabled as read-only flag + bool read_only = !enabled; + if (read_only != mReadOnly) + { + //mReadOnly = read_only; + LLTextBase::setReadOnly(read_only); + updateSegments(); + updateAllowingLanguageInput(); + } } void LLTextEditor::showContextMenu(S32 x, S32 y) { - LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); - if (!menu) - { - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml", - LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if (!menu) + { + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); if(!menu) { LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL; return; } - mContextMenuHandle = menu->getHandle(); - } - - // Route menu to this class - // previously this was done in ::handleRightMoseDown: - //if(hasTabStop()) - // setFocus(TRUE) - why? weird... - // and then inside setFocus - // .... - // gEditMenuHandler = this; - // .... - // but this didn't work in all cases and just weird... - //why not here? - // (all this was done for EXT-4443) - - gEditMenuHandler = this; - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - setCursorAtLocalPos(x, y, false); - if (hasSelection()) - { - if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) - { - deselect(); - } - else - { - setCursorPos(llmax(mSelectionStart, mSelectionEnd)); - } - } - - bool use_spellcheck = getSpellCheck(), is_misspelled = false; - if (use_spellcheck) - { - mSuggestionList.clear(); - - // If the cursor is on a misspelled word, retrieve suggestions for it - std::string misspelled_word = getMisspelledWord(mCursorPos); - if ((is_misspelled = !misspelled_word.empty()) == true) - { - LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); - } - } - - menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); - menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); - menu->show(screen_x, screen_y, this); + mContextMenuHandle = menu->getHandle(); + } + + // Route menu to this class + // previously this was done in ::handleRightMoseDown: + //if(hasTabStop()) + // setFocus(TRUE) - why? weird... + // and then inside setFocus + // .... + // gEditMenuHandler = this; + // .... + // but this didn't work in all cases and just weird... + //why not here? + // (all this was done for EXT-4443) + + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } void LLTextEditor::drawPreeditMarker() { - static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); - static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); - static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); - static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); - static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); - static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); - static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); - static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); + static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); + static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); + static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); + static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); + static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); + static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); + static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); + static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); - if (!hasPreeditString()) - { - return; - } + if (!hasPreeditString()) + { + return; + } const LLWString textString(getWText()); - const llwchar *text = textString.c_str(); - const S32 text_len = getLength(); - const S32 num_lines = getLineCount(); - - S32 cur_line = getFirstVisibleLine(); - if (cur_line >= num_lines) - { - return; - } - - const S32 line_height = mFont->getLineHeight(); - - S32 line_start = getLineStart(cur_line); - S32 line_y = mVisibleTextRect.mTop - line_height; - while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) - { - S32 next_start = -1; - S32 line_end = text_len; - - if ((cur_line + 1) < num_lines) - { - next_start = getLineStart(cur_line + 1); - line_end = next_start; - } - if ( text[line_end-1] == '\n' ) - { - --line_end; - } - - // Does this line contain preedits? - if (line_start >= mPreeditPositions.back()) - { - // We have passed the preedits. - break; - } - if (line_end > mPreeditPositions.front()) - { - for (U32 i = 0; i < mPreeditStandouts.size(); i++) - { - S32 left = mPreeditPositions[i]; - S32 right = mPreeditPositions[i + 1]; - if (right <= line_start || left >= line_end) - { - continue; - } - - line_info& line = mLineInfoList[cur_line]; - LLRect text_rect(line.mRect); - text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - - S32 preedit_left = text_rect.mLeft; - if (left > line_start) - { - preedit_left += mFont->getWidth(text, line_start, left - line_start); - } - S32 preedit_right = text_rect.mLeft; - if (right < line_end) - { - preedit_right += mFont->getWidth(text, line_start, right - line_start); - } - else - { - preedit_right += mFont->getWidth(text, line_start, line_end - line_start); - } - - if (mPreeditStandouts[i]) - { - gl_rect_2d(preedit_left + preedit_standout_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_standout_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, - (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); - } - else - { - gl_rect_2d(preedit_left + preedit_marker_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_marker_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, - (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); - } - } - } - - // move down one line - line_y -= line_height; - line_start = next_start; - cur_line++; - } + const llwchar *text = textString.c_str(); + const S32 text_len = getLength(); + const S32 num_lines = getLineCount(); + + S32 cur_line = getFirstVisibleLine(); + if (cur_line >= num_lines) + { + return; + } + + const S32 line_height = mFont->getLineHeight(); + + S32 line_start = getLineStart(cur_line); + S32 line_y = mVisibleTextRect.mTop - line_height; + while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // Does this line contain preedits? + if (line_start >= mPreeditPositions.back()) + { + // We have passed the preedits. + break; + } + if (line_end > mPreeditPositions.front()) + { + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + S32 left = mPreeditPositions[i]; + S32 right = mPreeditPositions[i + 1]; + if (right <= line_start || left >= line_end) + { + continue; + } + + line_info& line = mLineInfoList[cur_line]; + LLRect text_rect(line.mRect); + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + + S32 preedit_left = text_rect.mLeft; + if (left > line_start) + { + preedit_left += mFont->getWidth(text, line_start, left - line_start); + } + S32 preedit_right = text_rect.mLeft; + if (right < line_end) + { + preedit_right += mFont->getWidth(text, line_start, right - line_start); + } + else + { + preedit_right += mFont->getWidth(text, line_start, line_end - line_start); + } + + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_left + preedit_standout_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_standout_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, + (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); + } + else + { + gl_rect_2d(preedit_left + preedit_marker_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_marker_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, + (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); + } + } + } + + // move down one line + line_y -= line_height; + line_start = next_start; + cur_line++; + } } void LLTextEditor::draw() { - { - // pad clipping rectangle so that cursor can draw at full width - // when at left edge of mVisibleTextRect - LLRect clip_rect(mVisibleTextRect); - clip_rect.stretch(1); - LLLocalClipRect clip(clip_rect); - } + { + // pad clipping rectangle so that cursor can draw at full width + // when at left edge of mVisibleTextRect + LLRect clip_rect(mVisibleTextRect); + clip_rect.stretch(1); + LLLocalClipRect clip(clip_rect); + } - LLTextBase::draw(); + LLTextBase::draw(); drawPreeditMarker(); - //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret - // when in readonly mode - mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); + //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret + // when in readonly mode + mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); } // Start or stop the editor from accepting text-editing keystrokes // see also LLLineEditor void LLTextEditor::setFocus( BOOL new_state ) { - BOOL old_state = hasFocus(); + BOOL old_state = hasFocus(); - // Don't change anything if the focus state didn't change - if (new_state == old_state) return; + // Don't change anything if the focus state didn't change + if (new_state == old_state) return; - // Notify early if we are losing focus. - if (!new_state) - { - getWindow()->allowLanguageTextInput(this, FALSE); - } + // Notify early if we are losing focus. + if (!new_state) + { + getWindow()->allowLanguageTextInput(this, FALSE); + } - LLTextBase::setFocus( new_state ); + LLTextBase::setFocus( new_state ); - if( new_state ) - { - // Route menu to this class - gEditMenuHandler = this; + if( new_state ) + { + // Route menu to this class + gEditMenuHandler = this; - // Don't start the cursor flashing right away - resetCursorBlink(); - } - else - { - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Don't start the cursor flashing right away + resetCursorBlink(); + } + else + { + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - endSelection(); - } + endSelection(); + } } // public void LLTextEditor::setCursorAndScrollToEnd() { - deselect(); - endOfDoc(); + deselect(); + endOfDoc(); } -void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) -{ - *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); - *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); +void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) +{ + *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); + *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); } void LLTextEditor::autoIndent() { - // Count the number of spaces in the current line - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); - S32 space_count = 0; - S32 i; + // Count the number of spaces in the current line + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + S32 space_count = 0; + S32 i; - LLWString text = getWText(); - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - while(( ' ' == text[line_start] ) && (space_count < offset)) - { - space_count++; - line_start++; - } + LLWString text = getWText(); + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + while(( ' ' == text[line_start] ) && (space_count < offset)) + { + space_count++; + line_start++; + } - // If we're starting a braced section, indent one level. - if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) - { - space_count += SPACES_PER_TAB; - } + // If we're starting a braced section, indent one level. + if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) + { + space_count += SPACES_PER_TAB; + } - // Insert that number of spaces on the new line + // Insert that number of spaces on the new line - //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); - addLineBreakChar(); + //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); + addLineBreakChar(); - for( i = 0; i < space_count; i++ ) - { - addChar( ' ' ); - } + for( i = 0; i < space_count; i++ ) + { + addChar( ' ' ); + } } // Inserts new text at the cursor position void LLTextEditor::insertText(const std::string &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } - - setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - setEnabled( enabled ); + setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); + + setEnabled( enabled ); } void LLTextEditor::insertText(LLWString &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); + setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo) { - // Save old state - S32 selection_start = mSelectionStart; - S32 selection_end = mSelectionEnd; - BOOL was_selecting = mIsSelecting; - S32 cursor_pos = mCursorPos; - S32 old_length = getLength(); - BOOL cursor_was_at_end = (mCursorPos == old_length); + // Save old state + S32 selection_start = mSelectionStart; + S32 selection_end = mSelectionEnd; + BOOL was_selecting = mIsSelecting; + S32 cursor_pos = mCursorPos; + S32 old_length = getLength(); + BOOL cursor_was_at_end = (mCursorPos == old_length); - deselect(); + deselect(); - setCursorPos(old_length); + setCursorPos(old_length); - LLWString widget_wide_text = utf8str_to_wstring(text); + LLWString widget_wide_text = utf8str_to_wstring(text); - LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); - insert(getLength(), widget_wide_text, FALSE, segment); + LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); + insert(getLength(), widget_wide_text, FALSE, segment); - // Set the cursor and scroll position - if( selection_start != selection_end ) - { - mSelectionStart = selection_start; - mSelectionEnd = selection_end; + // Set the cursor and scroll position + if( selection_start != selection_end ) + { + mSelectionStart = selection_start; + mSelectionEnd = selection_end; - mIsSelecting = was_selecting; - setCursorPos(cursor_pos); - } - else if( cursor_was_at_end ) - { - setCursorPos(getLength()); - } - else - { - setCursorPos(cursor_pos); - } + mIsSelecting = was_selecting; + setCursorPos(cursor_pos); + } + else if( cursor_was_at_end ) + { + setCursorPos(getLength()); + } + else + { + setCursorPos(cursor_pos); + } - if (!allow_undo) - { - blockUndo(); - } + if (!allow_undo) + { + blockUndo(); + } } void LLTextEditor::removeTextFromEnd(S32 num_chars) { - if (num_chars <= 0) return; + if (num_chars <= 0) return; - remove(getLength() - num_chars, num_chars, FALSE); + remove(getLength() - num_chars, num_chars, FALSE); - S32 len = getLength(); - setCursorPos (llclamp(mCursorPos, 0, len)); - mSelectionStart = llclamp(mSelectionStart, 0, len); - mSelectionEnd = llclamp(mSelectionEnd, 0, len); + S32 len = getLength(); + setCursorPos (llclamp(mCursorPos, 0, len)); + mSelectionStart = llclamp(mSelectionStart, 0, len); + mSelectionEnd = llclamp(mSelectionEnd, 0, len); - needsScroll(); + needsScroll(); } //---------------------------------------------------------------------------- void LLTextEditor::onSpellCheckPerformed() { - if (isPristine()) - { - mBaseDocIsPristine = FALSE; - } + if (isPristine()) + { + mBaseDocIsPristine = FALSE; + } } void LLTextEditor::makePristine() { - mPristineCmd = mLastCmd; - mBaseDocIsPristine = !mLastCmd; + mPristineCmd = mLastCmd; + mBaseDocIsPristine = !mLastCmd; - // Create a clean partition in the undo stack. We don't want a single command to extend from - // the "pre-pristine" state to the "post-pristine" state. - if( mLastCmd ) - { - mLastCmd->blockExtensions(); - } + // Create a clean partition in the undo stack. We don't want a single command to extend from + // the "pre-pristine" state to the "post-pristine" state. + if( mLastCmd ) + { + mLastCmd->blockExtensions(); + } } BOOL LLTextEditor::isPristine() const { - if( mPristineCmd ) - { - return (mPristineCmd == mLastCmd); - } - else - { - // No undo stack, so check if the version before and commands were done was the original version - return !mLastCmd && mBaseDocIsPristine; - } + if( mPristineCmd ) + { + return (mPristineCmd == mLastCmd); + } + else + { + // No undo stack, so check if the version before and commands were done was the original version + return !mLastCmd && mBaseDocIsPristine; + } } BOOL LLTextEditor::tryToRevertToPristineState() { - if( !isPristine() ) - { - deselect(); - S32 i = 0; - while( !isPristine() && canUndo() ) - { - undo(); - i--; - } - - while( !isPristine() && canRedo() ) - { - redo(); - i++; - } - - if( !isPristine() ) - { - // failed, so go back to where we started - while( i > 0 ) - { - undo(); - i--; - } - } - } - - return isPristine(); // TRUE => success + if( !isPristine() ) + { + deselect(); + S32 i = 0; + while( !isPristine() && canUndo() ) + { + undo(); + i--; + } + + while( !isPristine() && canRedo() ) + { + redo(); + i++; + } + + if( !isPristine() ) + { + // failed, so go back to where we started + while( i > 0 ) + { + undo(); + i--; + } + } + } + + return isPristine(); // TRUE => success } void LLTextEditor::updateLinkSegments() { - LLWString wtext = getWText(); - - // update any segments that contain a link - for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegment *segment = *it; - if (segment && segment->getStyle() && segment->getStyle()->isLink()) - { - LLStyleConstSP style = segment->getStyle(); - LLStyleSP new_style(new LLStyle(*style)); - LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); - - segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); - LLTextSegment *next_segment = *next_it; - if (next_segment) - { - LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); - std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); - LLUrlMatch match; - - if ( LLUrlRegistry::instance().findUrl(link_check, match)) - { - if(match.getQuery() == wstring_to_utf8str(next_url_label)) - { - continue; - } - } - } - - // if the link's label (what the user can edit) is a valid Url, - // then update the link's HREF to be the same as the label text. - // This lets users edit Urls in-place. - if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) - { - std::string new_url = wstring_to_utf8str(url_label); - LLStringUtil::trim(new_url); - new_style->setLinkHREF(new_url); - LLStyleConstSP sp(new_style); - segment->setStyle(sp); - } - } - } + LLWString wtext = getWText(); + + // update any segments that contain a link + for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *segment = *it; + if (segment && segment->getStyle() && segment->getStyle()->isLink()) + { + LLStyleConstSP style = segment->getStyle(); + LLStyleSP new_style(new LLStyle(*style)); + LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); + + segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); + LLTextSegment *next_segment = *next_it; + if (next_segment) + { + LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); + std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); + LLUrlMatch match; + + if ( LLUrlRegistry::instance().findUrl(link_check, match)) + { + if(match.getQuery() == wstring_to_utf8str(next_url_label)) + { + continue; + } + } + } + + // if the link's label (what the user can edit) is a valid Url, + // then update the link's HREF to be the same as the label text. + // This lets users edit Urls in-place. + if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) + { + std::string new_url = wstring_to_utf8str(url_label); + LLStringUtil::trim(new_url); + new_style->setLinkHREF(new_url); + LLStyleConstSP sp(new_style); + segment->setStyle(sp); + } + } + } } void LLTextEditor::onMouseCaptureLost() { - endSelection(); + endSelection(); } /////////////////////////////////////////////////////////////////// @@ -2643,135 +2644,135 @@ void LLTextEditor::onMouseCaptureLost() BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) { - std::istringstream instream(buffer); - - // Version 1 format: - // Linden text version 1\n - // {\n - // <EmbeddedItemList chunk> - // Text length <bytes without \0>\n - // <text without \0> (text may contain ext_char_values) - // }\n - - char tbuf[MAX_STRING]; /* Flawfinder: ignore */ - - S32 version = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) - { - LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; - return FALSE; - } - - if( 1 != version ) - { - LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; - return FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( 0 != sscanf(tbuf, "{") ) - { - LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; - return FALSE; - } - - S32 text_len = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) - { - LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; - return FALSE; - } - - if( text_len > mMaxTextByteLength ) - { - LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; - return FALSE; - } - - BOOL success = TRUE; - - char* text = new char[ text_len + 1]; - if (text == NULL) - { + std::istringstream instream(buffer); + + // Version 1 format: + // Linden text version 1\n + // {\n + // <EmbeddedItemList chunk> + // Text length <bytes without \0>\n + // <text without \0> (text may contain ext_char_values) + // }\n + + char tbuf[MAX_STRING]; /* Flawfinder: ignore */ + + S32 version = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) + { + LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; + return FALSE; + } + + if( 1 != version ) + { + LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; + return FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( 0 != sscanf(tbuf, "{") ) + { + LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; + return FALSE; + } + + S32 text_len = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) + { + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; + return FALSE; + } + + if( text_len > mMaxTextByteLength ) + { + LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; + return FALSE; + } + + BOOL success = TRUE; + + char* text = new char[ text_len + 1]; + if (text == NULL) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Memory allocation failure." << LL_ENDL; - return FALSE; - } - instream.get(text, text_len + 1, '\0'); - text[text_len] = '\0'; - if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ - { - LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ - success = FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( success && (0 != sscanf(tbuf, "}")) ) - { - LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; - success = FALSE; - } - - if( success ) - { - // Actually set the text - setText( LLStringExplicit(text) ); - } - - delete[] text; - - startOfDoc(); - deselect(); - - return success; + LL_ERRS() << "Memory allocation failure." << LL_ENDL; + return FALSE; + } + instream.get(text, text_len + 1, '\0'); + text[text_len] = '\0'; + if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ + { + LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ + success = FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( success && (0 != sscanf(tbuf, "}")) ) + { + LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; + success = FALSE; + } + + if( success ) + { + // Actually set the text + setText( LLStringExplicit(text) ); + } + + delete[] text; + + startOfDoc(); + deselect(); + + return success; } BOOL LLTextEditor::exportBuffer(std::string &buffer ) { - std::ostringstream outstream(buffer); - - outstream << "Linden text version 1\n"; - outstream << "{\n"; + std::ostringstream outstream(buffer); + + outstream << "Linden text version 1\n"; + outstream << "{\n"; - outstream << llformat("Text length %d\n", getLength() ); - outstream << getText(); - outstream << "}\n"; + outstream << llformat("Text length %d\n", getLength() ); + outstream << getText(); + outstream << "}\n"; - return TRUE; + return TRUE; } void LLTextEditor::updateAllowingLanguageInput() { - LLWindow* window = getWindow(); - if (!window) - { - // test app, no window available - return; - } - if (hasFocus() && !mReadOnly) - { - window->allowLanguageTextInput(this, TRUE); - } - else - { - window->allowLanguageTextInput(this, FALSE); - } + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } + if (hasFocus() && !mReadOnly) + { + window->allowLanguageTextInput(this, TRUE); + } + else + { + window->allowLanguageTextInput(this, FALSE); + } } // Preedit is managed off the undo/redo command stack. BOOL LLTextEditor::hasPreeditString() const { - return (mPreeditPositions.size() > 1); + return (mPreeditPositions.size() > 1); } void LLTextEditor::resetPreedit() { if (hasSelection()) { - if (hasPreeditString()) + if (hasPreeditString()) { LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); @@ -2781,277 +2782,277 @@ void LLTextEditor::resetPreedit() deleteSelection(TRUE); } } - if (hasPreeditString()) - { - if (hasSelection()) - { - LL_WARNS() << "Preedit and selection!" << LL_ENDL; - deselect(); - } + if (hasPreeditString()) + { + if (hasSelection()) + { + LL_WARNS() << "Preedit and selection!" << LL_ENDL; + deselect(); + } - setCursorPos(mPreeditPositions.front()); - removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); - insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); + setCursorPos(mPreeditPositions.front()); + removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); + insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); - mPreeditWString.clear(); - mPreeditOverwrittenWString.clear(); - mPreeditPositions.clear(); + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); - // A call to updatePreedit should soon follow under a - // normal course of operation, so we don't need to - // maintain internal variables such as line start - // positions now. - } + // A call to updatePreedit should soon follow under a + // normal course of operation, so we don't need to + // maintain internal variables such as line start + // positions now. + } } void LLTextEditor::updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) { - // Just in case. - if (mReadOnly) - { - return; - } + // Just in case. + if (mReadOnly) + { + return; + } - getWindow()->hideCursorUntilMouseMove(); + getWindow()->hideCursorUntilMouseMove(); - S32 insert_preedit_at = mCursorPos; - - mPreeditWString = preedit_string; - mPreeditPositions.resize(preedit_segment_lengths.size() + 1); - S32 position = insert_preedit_at; - for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) - { - mPreeditPositions[i] = position; - position += preedit_segment_lengths[i]; - } - mPreeditPositions.back() = position; + S32 insert_preedit_at = mCursorPos; - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); - removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); - } - else - { - mPreeditOverwrittenWString.clear(); - } + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; - segment_vec_t segments; - //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. - insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); + removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } + + segment_vec_t segments; + //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. + insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); - mPreeditStandouts = preedit_standouts; + mPreeditStandouts = preedit_standouts; - setCursorPos(insert_preedit_at + caret_position); + setCursorPos(insert_preedit_at + caret_position); - // Update of the preedit should be caused by some key strokes. - resetCursorBlink(); + // Update of the preedit should be caused by some key strokes. + resetCursorBlink(); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const { - if (control) - { - LLRect control_rect_screen; - localRectToScreen(mVisibleTextRect, &control_rect_screen); - LLUI::getInstance()->screenRectToGL(control_rect_screen, control); - } - - S32 preedit_left_position, preedit_right_position; - if (hasPreeditString()) - { - preedit_left_position = mPreeditPositions.front(); - preedit_right_position = mPreeditPositions.back(); - } - else - { - preedit_left_position = preedit_right_position = mCursorPos; - } - - const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); - if (query < preedit_left_position || query > preedit_right_position) - { - return FALSE; - } - - const S32 first_visible_line = getFirstVisibleLine(); - if (query < getLineStart(first_visible_line)) - { - return FALSE; - } - - S32 current_line = first_visible_line; - S32 current_line_start, current_line_end; - for (;;) - { - current_line_start = getLineStart(current_line); - current_line_end = getLineStart(current_line + 1); - if (query >= current_line_start && query < current_line_end) - { - break; - } - if (current_line_start == current_line_end) - { - // We have reached on the last line. The query position must be here. - break; - } - current_line++; - } + if (control) + { + LLRect control_rect_screen; + localRectToScreen(mVisibleTextRect, &control_rect_screen); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_position, preedit_right_position; + if (hasPreeditString()) + { + preedit_left_position = mPreeditPositions.front(); + preedit_right_position = mPreeditPositions.back(); + } + else + { + preedit_left_position = preedit_right_position = mCursorPos; + } + + const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); + if (query < preedit_left_position || query > preedit_right_position) + { + return FALSE; + } + + const S32 first_visible_line = getFirstVisibleLine(); + if (query < getLineStart(first_visible_line)) + { + return FALSE; + } + + S32 current_line = first_visible_line; + S32 current_line_start, current_line_end; + for (;;) + { + current_line_start = getLineStart(current_line); + current_line_end = getLineStart(current_line + 1); + if (query >= current_line_start && query < current_line_end) + { + break; + } + if (current_line_start == current_line_end) + { + // We have reached on the last line. The query position must be here. + break; + } + current_line++; + } const LLWString textString(getWText()); - const llwchar * const text = textString.c_str(); - const S32 line_height = mFont->getLineHeight(); - - if (coord) - { - const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); - const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; - S32 query_screen_x, query_screen_y; - localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); - LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); - } - - if (bounds) - { - S32 preedit_left = mVisibleTextRect.mLeft; - if (preedit_left_position > current_line_start) - { - preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); - } - - S32 preedit_right = mVisibleTextRect.mLeft; - if (preedit_right_position < current_line_end) - { - preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); - } - else - { - preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); - } - - const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; - const S32 preedit_bottom = preedit_top - line_height; - - const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); - LLRect preedit_rect_screen; - localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); - } - - return TRUE; + const llwchar * const text = textString.c_str(); + const S32 line_height = mFont->getLineHeight(); + + if (coord) + { + const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; + S32 query_screen_x, query_screen_y; + localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left = mVisibleTextRect.mLeft; + if (preedit_left_position > current_line_start) + { + preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); + } + + S32 preedit_right = mVisibleTextRect.mLeft; + if (preedit_right_position < current_line_end) + { + preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); + } + else + { + preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); + } + + const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_bottom = preedit_top - line_height; + + const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; } void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const { - if (hasSelection()) - { - *position = llmin(mSelectionStart, mSelectionEnd); - *length = llabs(mSelectionStart - mSelectionEnd); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const { - if (hasPreeditString()) - { - *position = mPreeditPositions.front(); - *length = mPreeditPositions.back() - mPreeditPositions.front(); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::markAsPreedit(S32 position, S32 length) { - deselect(); - setCursorPos(position); - if (hasPreeditString()) - { - LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; - } - mPreeditWString = LLWString( getWText(), position, length ); - if (length > 0) - { - mPreeditPositions.resize(2); - mPreeditPositions[0] = position; - mPreeditPositions[1] = position + length; - mPreeditStandouts.resize(1); - mPreeditStandouts[0] = FALSE; - } - else - { - mPreeditPositions.clear(); - mPreeditStandouts.clear(); - } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = mPreeditWString; - } - else - { - mPreeditOverwrittenWString.clear(); - } + deselect(); + setCursorPos(position); + if (hasPreeditString()) + { + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; + } + mPreeditWString = LLWString( getWText(), position, length ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } } S32 LLTextEditor::getPreeditFontSize() const { - return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } BOOL LLTextEditor::isDirty() const { - if(mReadOnly) - { - return FALSE; - } + if(mReadOnly) + { + return FALSE; + } - if( mPristineCmd ) - { - return ( mPristineCmd == mLastCmd ); - } - else - { - return ( NULL != mLastCmd ); - } + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } } void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) { - mKeystrokeSignal.connect(callback); + mKeystrokeSignal.connect(callback); } void LLTextEditor::onKeyStroke() { - mKeystrokeSignal(this); + mKeystrokeSignal(this); - mSpellCheckStart = mSpellCheckEnd = -1; - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual void LLTextEditor::clear() { - getViewModel()->setDisplay(LLWStringUtil::null); - clearSegments(); + getViewModel()->setDisplay(LLWStringUtil::null); + clearSegments(); } bool LLTextEditor::canLoadOrSaveToFile() { - return !mReadOnly; + return !mReadOnly; } S32 LLTextEditor::spacesPerTab() { - return SPACES_PER_TAB; + return SPACES_PER_TAB; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index e965848ce1..658bfb9295 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -34,6 +34,7 @@ #include "llstyle.h" #include "lleditmenuhandler.h" #include "llviewborder.h" // for params +#include "llstring.h" #include "lltextbase.h" #include "lltextvalidate.h" @@ -47,305 +48,316 @@ class LLUICtrlFactory; class LLScrollContainer; class LLTextEditor : - public LLTextBase, - protected LLPreeditor + public LLTextBase, + protected LLPreeditor { public: - struct Params : public LLInitParam::Block<Params, LLTextBase::Params> - { - Optional<std::string> default_text; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; - - Optional<bool> embedded_items, - ignore_tab, - commit_on_focus_lost, - show_context_menu, - show_emoji_helper, - enable_tooltip_paste, - auto_indent; - - //colors - Optional<LLUIColor> default_color; - - Params(); - }; - - void initFromParams(const Params&); + struct Params : public LLInitParam::Block<Params, LLTextBase::Params> + { + Optional<std::string> default_text; + Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; + + Optional<bool> embedded_items, + ignore_tab, + commit_on_focus_lost, + show_context_menu, + show_emoji_helper, + enable_tooltip_paste, + auto_indent; + + //colors + Optional<LLUIColor> default_color; + + Params(); + }; + + void initFromParams(const Params&); protected: - LLTextEditor(const Params&); - friend class LLUICtrlFactory; + LLTextEditor(const Params&); + friend class LLUICtrlFactory; public: - // - // Constants - // - static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; - static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; - static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; + // + // Constants + // + static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; + static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; + static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; - virtual ~LLTextEditor(); + virtual ~LLTextEditor(); - typedef boost::signals2::signal<void (LLTextEditor* caller)> keystroke_signal_t; + typedef boost::signals2::signal<void (LLTextEditor* caller)> keystroke_signal_t; - void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); - void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} - static S32 spacesPerTab(); + static S32 spacesPerTab(); - void insertEmoji(llwchar emoji); - void handleEmojiCommit(llwchar emoji); + void insertEmoji(llwchar emoji); + void handleEmojiCommit(llwchar emoji); - // mousehandler overrides - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); - virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + // mousehandler overrides + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); + virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask ); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleKeyHere(KEY key, MASK mask ); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void onMouseCaptureLost(); + virtual void onMouseCaptureLost(); - // view overrides - virtual void draw(); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual void onCommit(); - virtual void setEnabled(BOOL enabled); + // view overrides + virtual void draw(); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual void onCommit(); + virtual void setEnabled(BOOL enabled); - // uictrl overrides - virtual void clear(); - virtual void setFocus( BOOL b ); - virtual BOOL isDirty() const; + // uictrl overrides + virtual void clear(); + virtual void setFocus( BOOL b ); + virtual BOOL isDirty() const; - // LLEditMenuHandler interface - virtual void undo(); - virtual BOOL canUndo() const; - virtual void redo(); - virtual BOOL canRedo() const; + // LLEditMenuHandler interface + virtual void undo(); + virtual BOOL canUndo() const; + virtual void redo(); + virtual BOOL canRedo() const; - virtual void cut(); - virtual BOOL canCut() const; - virtual void copy(); - virtual BOOL canCopy() const; - virtual void paste(); - virtual BOOL canPaste() const; + virtual void cut(); + virtual BOOL canCut() const; + virtual void copy(); + virtual BOOL canCopy() const; + virtual void paste(); + virtual BOOL canPaste() const; - virtual void updatePrimary(); - virtual void copyPrimary(); - virtual void pastePrimary(); - virtual BOOL canPastePrimary() const; + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; - virtual void doDelete(); - virtual BOOL canDoDelete() const; - virtual void selectAll(); - virtual BOOL canSelectAll() const; + virtual void doDelete(); + virtual BOOL canDoDelete() const; + virtual void selectAll(); + virtual BOOL canSelectAll() const; - void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); - virtual bool canLoadOrSaveToFile(); + virtual bool canLoadOrSaveToFile(); - void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); - BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); - void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); + void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); + BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); + void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); - // Undo/redo stack - void blockUndo(); + // Undo/redo stack + void blockUndo(); - // Text editing - virtual void makePristine(); - BOOL isPristine() const; - BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } + // Text editing + virtual void makePristine(); + BOOL isPristine() const; + BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } - // Autoreplace (formerly part of LLLineEditor) - typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t; - autoreplace_callback_t mAutoreplaceCallback; - void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } + // Autoreplace (formerly part of LLLineEditor) + typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } - /*virtual*/ void onSpellCheckPerformed(); + /*virtual*/ void onSpellCheckPerformed(); - // - // Text manipulation - // + // + // Text manipulation + // - // inserts text at cursor - void insertText(const std::string &text); - void insertText(LLWString &text); + // inserts text at cursor + void insertText(const std::string &text); + void insertText(LLWString &text); - void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); - // Non-undoable - void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); + void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); + // Non-undoable + void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); - // Removes text from the end of document - // Does not change highlight or cursor position. - void removeTextFromEnd(S32 num_chars); + // Removes text from the end of document + // Does not change highlight or cursor position. + void removeTextFromEnd(S32 num_chars); - BOOL tryToRevertToPristineState(); + BOOL tryToRevertToPristineState(); - void setCursorAndScrollToEnd(); + void setCursorAndScrollToEnd(); - void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); + void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); - // Hacky methods to make it into a word-wrapping, potentially scrolling, - // read-only text box. - void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } + // Hacky methods to make it into a word-wrapping, potentially scrolling, + // read-only text box. + void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } - // Hack to handle Notecards - virtual BOOL importBuffer(const char* buffer, S32 length ); - virtual BOOL exportBuffer(std::string& buffer ); + // Hack to handle Notecards + virtual BOOL importBuffer(const char* buffer, S32 length ); + virtual BOOL exportBuffer(std::string& buffer ); - const LLUUID& getSourceID() const { return mSourceID; } + const LLUUID& getSourceID() const { return mSourceID; } - const LLTextSegmentPtr getPreviousSegment() const; - const LLTextSegmentPtr getLastSegment() const; - void getSelectedSegments(segment_vec_t& segments) const; + const LLTextSegmentPtr getPreviousSegment() const; + const LLTextSegmentPtr getLastSegment() const; + void getSelectedSegments(segment_vec_t& segments) const; - void setShowContextMenu(bool show) { mShowContextMenu = show; } - bool getShowContextMenu() const { return mShowContextMenu; } + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getShowContextMenu() const { return mShowContextMenu; } - void showEmojiHelper(); - void setShowEmojiHelper(bool show); - bool getShowEmojiHelper() const { return mShowEmojiHelper; } + void showEmojiHelper(); + void setShowEmojiHelper(bool show); + bool getShowEmojiHelper() const { return mShowEmojiHelper; } - void setPassDelete(BOOL b) { mPassDelete = b; } + void setPassDelete(BOOL b) { mPassDelete = b; } protected: - void showContextMenu(S32 x, S32 y); - void drawPreeditMarker(); - - void assignEmbedded(const std::string &s); - - void removeCharOrTab(); - - void indentSelectedLines( S32 spaces ); - S32 indentLine( S32 pos, S32 spaces ); - void unindentLineBeforeCloseBrace(); - - virtual BOOL handleSpecialKey(const KEY key, const MASK mask); - BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSelectionKey(const KEY key, const MASK mask); - BOOL handleControlKey(const KEY key, const MASK mask); - - BOOL selectionContainsLineBreaks(); - void deleteSelection(BOOL transient_operation); - - S32 prevWordPos(S32 cursorPos) const; - S32 nextWordPos(S32 cursorPos) const; - - void autoIndent(); - - void findEmbeddedItemSegments(S32 start, S32 end); - void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; - - virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } - - - // Here's the method that takes and applies text commands. - S32 execute(TextCmd* cmd); - - // Undoable operations - void addChar(llwchar c); // at mCursorPos - S32 addChar(S32 pos, llwchar wc); - void addLineBreakChar(BOOL group_together = FALSE); - S32 overwriteChar(S32 pos, llwchar wc); - void removeChar(); - S32 removeChar(S32 pos); - S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); - S32 remove(S32 pos, S32 length, bool group_with_next_op); - - void tryToShowEmojiHelper(); - void focusLostHelper(); - void updateAllowingLanguageInput(); - BOOL hasPreeditString() const; - - // Overrides LLPreeditor - virtual void resetPreedit(); - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); - virtual void markAsPreedit(S32 position, S32 length); - virtual void getPreeditRange(S32 *position, S32 *length) const; - virtual void getSelectionRange(S32 *position, S32 *length) const; - virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; - virtual S32 getPreeditFontSize() const; - virtual LLWString getPreeditString() const { return getWText(); } - // - // Protected data - // - // Probably deserves serious thought to hiding as many of these - // as possible behind protected accessor methods. - // - - // Use these to determine if a click on an embedded item is a drag or not. - S32 mMouseDownX; - S32 mMouseDownY; - - LLWString mPreeditWString; - LLWString mPreeditOverwrittenWString; - std::vector<S32> mPreeditPositions; - std::vector<BOOL> mPreeditStandouts; + void showContextMenu(S32 x, S32 y); + void drawPreeditMarker(); + + void assignEmbedded(const std::string &s); + + void removeCharOrTab(); + + void indentSelectedLines( S32 spaces ); + S32 indentLine( S32 pos, S32 spaces ); + void unindentLineBeforeCloseBrace(); + + virtual BOOL handleSpecialKey(const KEY key, const MASK mask); + BOOL handleNavigationKey(const KEY key, const MASK mask); + BOOL handleSelectionKey(const KEY key, const MASK mask); + BOOL handleControlKey(const KEY key, const MASK mask); + + BOOL selectionContainsLineBreaks(); + void deleteSelection(BOOL transient_operation); + + S32 prevWordPos(S32 cursorPos) const; + S32 nextWordPos(S32 cursorPos) const; + + void autoIndent(); + + void findEmbeddedItemSegments(S32 start, S32 end); + void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; + + virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } + + + // Here's the method that takes and applies text commands. + S32 execute(TextCmd* cmd); + + // Undoable operations + void addChar(llwchar c); // at mCursorPos + S32 addChar(S32 pos, llwchar wc); +public: + void addLineBreakChar(BOOL group_together = FALSE); +protected: + S32 overwriteChar(S32 pos, llwchar wc); + void removeChar(); + S32 removeChar(S32 pos); + S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); + S32 remove(S32 pos, S32 length, bool group_with_next_op); + + void tryToShowEmojiHelper(); + void focusLostHelper(); + void updateAllowingLanguageInput(); + BOOL hasPreeditString() const; + + // Overrides LLPreeditor + virtual void resetPreedit(); + virtual void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); + virtual void markAsPreedit(S32 position, S32 length); + virtual void getPreeditRange(S32 *position, S32 *length) const; + virtual void getSelectionRange(S32 *position, S32 *length) const; + virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; + virtual S32 getPreeditFontSize() const; + virtual LLWString getPreeditString() const { return getWText(); } + // + // Protected data + // + // Probably deserves serious thought to hiding as many of these + // as possible behind protected accessor methods. + // + + // Use these to determine if a click on an embedded item is a drag or not. + S32 mMouseDownX; + S32 mMouseDownY; + + LLWString mPreeditWString; + LLWString mPreeditOverwrittenWString; + std::vector<S32> mPreeditPositions; + std::vector<BOOL> mPreeditStandouts; protected: - LLUIColor mDefaultColor; + LLUIColor mDefaultColor; - bool mAutoIndent; - bool mParseOnTheFly; + bool mAutoIndent; + bool mParseOnTheFly; - void updateLinkSegments(); - void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } - class LLViewBorder* mBorder; + void updateLinkSegments(); + void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } + class LLViewBorder* mBorder; private: - // - // Methods - // - void pasteHelper(bool is_primary); - void cleanStringForPaste(LLWString & clean_string); - void pasteTextWithLinebreaks(LLWString & clean_string); + // + // Methods + // + void pasteHelper(bool is_primary); + void cleanStringForPaste(LLWString & clean_string); + +public: + template <typename STRINGTYPE> + void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) + { + pasteTextWithLinebreaks<LLWString>(ll_convert(clean_string)); + } + template <> + void pasteTextWithLinebreaks<LLWString>(const LLWString & clean_string); - void onKeyStroke(); +private: + void onKeyStroke(); - // Concrete TextCmd sub-classes used by the LLTextEditor base class - class TextCmdInsert; - class TextCmdAddChar; - class TextCmdOverwriteChar; - class TextCmdRemove; + // Concrete TextCmd sub-classes used by the LLTextEditor base class + class TextCmdInsert; + class TextCmdAddChar; + class TextCmdOverwriteChar; + class TextCmdRemove; - BOOL mBaseDocIsPristine; - TextCmd* mPristineCmd; + BOOL mBaseDocIsPristine; + TextCmd* mPristineCmd; - TextCmd* mLastCmd; + TextCmd* mLastCmd; - typedef std::deque<TextCmd*> undo_stack_t; - undo_stack_t mUndoStack; + typedef std::deque<TextCmd*> undo_stack_t; + undo_stack_t mUndoStack; - BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces - BOOL mCommitOnFocusLost; - BOOL mTakesFocus; + BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces + BOOL mCommitOnFocusLost; + BOOL mTakesFocus; - BOOL mAllowEmbeddedItems; - bool mShowContextMenu; - bool mShowEmojiHelper; - bool mEnableTooltipPaste; - bool mPassDelete; - bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + BOOL mAllowEmbeddedItems; + bool mShowContextMenu; + bool mShowEmojiHelper; + bool mEnableTooltipPaste; + bool mPassDelete; + bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter - LLUUID mSourceID; + LLUUID mSourceID; - LLCoordGL mLastIMEPosition; // Last position of the IME editor + LLCoordGL mLastIMEPosition; // Last position of the IME editor - keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + keystroke_signal_t mKeystrokeSignal; + LLTextValidate::validate_func_t mPrevalidateFunc; - LLHandle<LLContextMenu> mContextMenuHandle; + LLHandle<LLContextMenu> mContextMenuHandle; }; // end class LLTextEditor // Build time optimization, generate once in .cpp file #ifndef LLTEXTEDITOR_CPP extern template class LLTextEditor* LLView::getChild<class LLTextEditor>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_TEXTEDITOR_H diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 8ccda101c1..9e9e424455 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -1,25 +1,25 @@ -/** +/** * @file llwindow.h * @brief Basic graphical window class * * $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$ */ @@ -44,40 +44,40 @@ class LLWindow : public LLInstanceTracker<LLWindow> { public: - struct LLWindowResolution - { - S32 mWidth; - S32 mHeight; - }; - enum ESwapMethod - { - SWAP_METHOD_UNDEFINED, - SWAP_METHOD_EXCHANGE, - SWAP_METHOD_COPY - }; - enum EFlags - { - // currently unused - }; + struct LLWindowResolution + { + S32 mWidth; + S32 mHeight; + }; + enum ESwapMethod + { + SWAP_METHOD_UNDEFINED, + SWAP_METHOD_EXCHANGE, + SWAP_METHOD_COPY + }; + enum EFlags + { + // currently unused + }; public: - virtual void show() = 0; - virtual void hide() = 0; - virtual void close() = 0; - virtual BOOL getVisible() = 0; - virtual BOOL getMinimized() = 0; - virtual BOOL getMaximized() = 0; - virtual BOOL maximize() = 0; - virtual void minimize() = 0; - virtual void restore() = 0; - BOOL getFullscreen() { return mFullscreen; }; - virtual BOOL getPosition(LLCoordScreen *position) = 0; - virtual BOOL getSize(LLCoordScreen *size) = 0; - virtual BOOL getSize(LLCoordWindow *size) = 0; - virtual BOOL setPosition(LLCoordScreen position) = 0; - BOOL setSize(LLCoordScreen size); - BOOL setSize(LLCoordWindow size); - virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0; + virtual void show() = 0; + virtual void hide() = 0; + virtual void close() = 0; + virtual BOOL getVisible() = 0; + virtual BOOL getMinimized() = 0; + virtual BOOL getMaximized() = 0; + virtual BOOL maximize() = 0; + virtual void minimize() = 0; + virtual void restore() = 0; + BOOL getFullscreen() { return mFullscreen; }; + virtual BOOL getPosition(LLCoordScreen *position) = 0; + virtual BOOL getSize(LLCoordScreen *size) = 0; + virtual BOOL getSize(LLCoordWindow *size) = 0; + virtual BOOL setPosition(LLCoordScreen position) = 0; + BOOL setSize(LLCoordScreen size); + BOOL setSize(LLCoordWindow size); + virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); + virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0; //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread // returns a pointer to be handed back to destroySharedConext/makeContextCurrent @@ -91,111 +91,113 @@ public: virtual void toggleVSync(bool enable_vsync) = 0; virtual BOOL setCursorPosition(LLCoordWindow position) = 0; - virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; + virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; #if LL_WINDOWS virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0; #endif - virtual void showCursor() = 0; - virtual void hideCursor() = 0; - virtual BOOL isCursorHidden() = 0; - virtual void showCursorFromMouseMove() = 0; - virtual void hideCursorUntilMouseMove() = 0; + virtual void showCursor() = 0; + virtual void hideCursor() = 0; + virtual BOOL isCursorHidden() = 0; + virtual void showCursorFromMouseMove() = 0; + virtual void hideCursorUntilMouseMove() = 0; // Provide a way to set the Viewer window title after the // windows has been created. The initial use case for this - // is described in SL-16102 (update window title with agent + // is described in SL-16102 (update window title with agent // name, location etc. for non-interactive viewer) but it // may also be useful in other cases. virtual void setTitle(const std::string title); - // These two functions create a way to make a busy cursor instead - // of an arrow when someone's busy doing something. Draw an - // arrow/hour if busycount > 0. - virtual void incBusyCount(); - virtual void decBusyCount(); - virtual void resetBusyCount(); - virtual S32 getBusyCount() const; + // These two functions create a way to make a busy cursor instead + // of an arrow when someone's busy doing something. Draw an + // arrow/hour if busycount > 0. + virtual void incBusyCount(); + virtual void decBusyCount(); + virtual void resetBusyCount(); + virtual S32 getBusyCount() const; - // Sets cursor, may set to arrow+hourglass - virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; }; + // Sets cursor, may set to arrow+hourglass + virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; }; virtual ECursorType getCursor() const; virtual ECursorType getNextCursor() const { return mNextCursor; }; - virtual void updateCursor() = 0; - - virtual void captureMouse() = 0; - virtual void releaseMouse() = 0; - virtual void setMouseClipping( BOOL b ) = 0; - - virtual BOOL isClipboardTextAvailable() = 0; - virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; - virtual BOOL copyTextToClipboard(const LLWString &src) = 0; - - virtual BOOL isPrimaryTextAvailable(); - virtual BOOL pasteTextFromPrimary(LLWString &dst); - virtual BOOL copyTextToPrimary(const LLWString &src); - - virtual void flashIcon(F32 seconds) = 0; - virtual F32 getGamma() = 0; - virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma - virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples - virtual U32 getFSAASamples() = 0; - virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) - virtual ESwapMethod getSwapMethod() { return mSwapMethod; } - virtual void processMiscNativeEvents(); - virtual void gatherInput() = 0; - virtual void delayInputProcessing() = 0; - virtual void swapBuffers() = 0; - virtual void bringToFront() = 0; - virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract - virtual void setOldResize(bool oldresize) { }; - // handy coordinate space conversion routines - // NB: screen to window and vice verse won't work on width/height coordinate pairs, - // as the conversion must take into account left AND right border widths, etc. - virtual BOOL convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; - virtual BOOL convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; - virtual BOOL convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; - virtual BOOL convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; - virtual BOOL convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; - virtual BOOL convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; - - // query supported resolutions - virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; - virtual F32 getNativeAspectRatio() = 0; - virtual F32 getPixelAspectRatio() = 0; - virtual void setNativeAspectRatio(F32 aspect) = 0; - - // query VRAM usage - virtual U32 getAvailableVRAMMegabytes() = 0; - - virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) - virtual void afterDialog() {}; // undo whatever was done in beforeDialog() - - // opens system default color picker, modally - // Returns TRUE if valid color selected - virtual BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); + virtual void updateCursor() = 0; + + virtual void captureMouse() = 0; + virtual void releaseMouse() = 0; + virtual void setMouseClipping( BOOL b ) = 0; + + virtual BOOL isClipboardTextAvailable() = 0; + virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; + virtual BOOL copyTextToClipboard(const LLWString &src) = 0; + + virtual BOOL isPrimaryTextAvailable(); + virtual BOOL pasteTextFromPrimary(LLWString &dst); + virtual BOOL copyTextToPrimary(const LLWString &src); + + virtual void flashIcon(F32 seconds) = 0; + virtual F32 getGamma() = 0; + virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma + virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples + virtual U32 getFSAASamples() = 0; + virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) + virtual ESwapMethod getSwapMethod() { return mSwapMethod; } + virtual void processMiscNativeEvents(); + virtual void gatherInput() = 0; + virtual void delayInputProcessing() = 0; + virtual void swapBuffers() = 0; + virtual void bringToFront() = 0; + virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract + virtual void setOldResize(bool oldresize) { }; + // handy coordinate space conversion routines + // NB: screen to window and vice verse won't work on width/height coordinate pairs, + // as the conversion must take into account left AND right border widths, etc. + virtual BOOL convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; + virtual BOOL convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; + virtual BOOL convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; + virtual BOOL convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; + virtual BOOL convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; + virtual BOOL convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; + + // query supported resolutions + virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; + virtual F32 getNativeAspectRatio() = 0; + virtual F32 getPixelAspectRatio() = 0; + virtual void setNativeAspectRatio(F32 aspect) = 0; + + // query VRAM usage + virtual U32 getAvailableVRAMMegabytes() = 0; + + virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) + virtual void afterDialog() {}; // undo whatever was done in beforeDialog() + + // opens system default color picker, modally + // Returns TRUE if valid color selected + virtual BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getPlatformWindow() = 0; + virtual void *getPlatformWindow() = 0; // return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getMediaWindow(); - - // control platform's Language Text Input mechanisms. - virtual void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) {} - virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; - virtual void updateLanguageTextInputArea() {} - virtual void interruptLanguageTextInput() {} - virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; + virtual void *getMediaWindow(); + + // control platform's Language Text Input mechanisms. + virtual void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) {} + virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; + virtual void updateLanguageTextInputArea() {} + virtual void interruptLanguageTextInput() {} + virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; - static std::vector<std::string> getDynamicFallbackFontList(); + virtual void openFolder(const std::string &path) {}; - // Provide native key event data - virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } + static std::vector<std::string> getDynamicFallbackFontList(); + + // Provide native key event data + virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } - // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) - virtual F32 getSystemUISize() { return 1.0; } + // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) + virtual F32 getSystemUISize() { return 1.0; } - static std::vector<std::string> getDisplaysResolutionList(); + static std::vector<std::string> getDisplaysResolutionList(); // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; @@ -203,49 +205,49 @@ public: virtual S32 getRefreshRate() { return mRefreshRate; } protected: - LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); - virtual ~LLWindow(); - // Defaults to true - virtual BOOL isValid(); - // Defaults to true - virtual BOOL canDelete(); + LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); + virtual ~LLWindow(); + // Defaults to true + virtual BOOL isValid(); + // Defaults to true + virtual BOOL canDelete(); - virtual BOOL setSizeImpl(LLCoordScreen size) = 0; - virtual BOOL setSizeImpl(LLCoordWindow size) = 0; + virtual BOOL setSizeImpl(LLCoordScreen size) = 0; + virtual BOOL setSizeImpl(LLCoordWindow size) = 0; protected: - LLWindowCallbacks* mCallbacks; - - BOOL mPostQuit; // should this window post a quit message when destroyed? - BOOL mFullscreen; - S32 mFullscreenWidth; - S32 mFullscreenHeight; - S32 mFullscreenBits; - S32 mFullscreenRefresh; - LLWindowResolution* mSupportedResolutions; - S32 mNumSupportedResolutions; - ECursorType mCurrentCursor; - ECursorType mNextCursor; - BOOL mCursorHidden; - S32 mBusyCount; // how deep is the "cursor busy" stack? - BOOL mIsMouseClipping; // Is this window currently clipping the mouse - ESwapMethod mSwapMethod; - BOOL mHideCursorPermanent; - U32 mFlags; - U16 mHighSurrogate; - S32 mMinWindowWidth; - S32 mMinWindowHeight; + LLWindowCallbacks* mCallbacks; + + BOOL mPostQuit; // should this window post a quit message when destroyed? + BOOL mFullscreen; + S32 mFullscreenWidth; + S32 mFullscreenHeight; + S32 mFullscreenBits; + S32 mFullscreenRefresh; + LLWindowResolution* mSupportedResolutions; + S32 mNumSupportedResolutions; + ECursorType mCurrentCursor; + ECursorType mNextCursor; + BOOL mCursorHidden; + S32 mBusyCount; // how deep is the "cursor busy" stack? + BOOL mIsMouseClipping; // Is this window currently clipping the mouse + ESwapMethod mSwapMethod; + BOOL mHideCursorPermanent; + U32 mFlags; + U16 mHighSurrogate; + S32 mMinWindowWidth; + S32 mMinWindowHeight; S32 mRefreshRate; - // Handle a UTF-16 encoding unit received from keyboard. - // Converting the series of UTF-16 encoding units to UTF-32 data, - // this method passes the resulting UTF-32 data to mCallback's - // handleUnicodeChar. The mask should be that to be passed to the - // callback. This method uses mHighSurrogate as a dedicated work - // variable. - void handleUnicodeUTF16(U16 utf16, MASK mask); + // Handle a UTF-16 encoding unit received from keyboard. + // Converting the series of UTF-16 encoding units to UTF-32 data, + // this method passes the resulting UTF-32 data to mCallback's + // handleUnicodeChar. The mask should be that to be passed to the + // callback. This method uses mHighSurrogate as a dedicated work + // variable. + void handleUnicodeUTF16(U16 utf16, MASK mask); - friend class LLWindowManager; + friend class LLWindowManager; }; @@ -258,24 +260,24 @@ protected: class LLSplashScreen { public: - LLSplashScreen() { }; - virtual ~LLSplashScreen() { }; + LLSplashScreen() { }; + virtual ~LLSplashScreen() { }; - // Call to display the window. - static LLSplashScreen * create(); - static void show(); - static void hide(); - static void update(const std::string& string); + // Call to display the window. + static LLSplashScreen * create(); + static void show(); + static void hide(); + static void update(const std::string& string); - static bool isVisible(); + static bool isVisible(); protected: - // These are overridden by the platform implementation - virtual void showImpl() = 0; - virtual void updateImpl(const std::string& string) = 0; - virtual void hideImpl() = 0; + // These are overridden by the platform implementation + virtual void showImpl() = 0; + virtual void updateImpl(const std::string& string) = 0; + virtual void hideImpl() = 0; - static BOOL sVisible; + static BOOL sVisible; }; @@ -297,21 +299,21 @@ const S32 OSBTN_CANCEL = 3; class LLWindowManager { public: - static LLWindow *createWindow( - LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - U32 flags = 0, - BOOL fullscreen = FALSE, - BOOL clearBg = FALSE, - BOOL enable_vsync = FALSE, - BOOL use_gl = TRUE, - BOOL ignore_pixel_depth = FALSE, - U32 fsaa_samples = 0, + static LLWindow *createWindow( + LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, + U32 flags = 0, + BOOL fullscreen = FALSE, + BOOL clearBg = FALSE, + BOOL enable_vsync = FALSE, + BOOL use_gl = TRUE, + BOOL ignore_pixel_depth = FALSE, + U32 fsaa_samples = 0, U32 max_cores = 0, U32 max_vram = 0, F32 max_gl_version = 4.6f); - static BOOL destroyWindow(LLWindow* window); - static BOOL isWindowValid(LLWindow *window); + static BOOL destroyWindow(LLWindow* window); + static BOOL isWindowValid(LLWindow *window); }; // diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 31dc83493e..ade303c6d4 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -1,4 +1,4 @@ -/** +/** * @file llwindowmacosx-objc.h * @brief Prototypes for functions shared between llwindowmacosx.cpp * and llwindowmacosx-objc.mm. @@ -6,21 +6,21 @@ * $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$ */ @@ -40,8 +40,8 @@ typedef std::vector<int> segment_lengths; typedef std::vector<int> segment_standouts; struct attributedStringInfo { - segment_lengths seg_lengths; - segment_standouts seg_standouts; + segment_lengths seg_lengths; + segment_standouts seg_standouts; }; // This will actually hold an NSCursor*, but that type is only available in objective C. @@ -57,7 +57,7 @@ struct NativeKeyEventData { KEYDOWN, KEYCHAR }; - + EventType mKeyEvent = KEYUNKNOWN; uint32_t mEventType = 0; uint32_t mEventModifiers = 0; @@ -177,6 +177,8 @@ void setMarkedText(unsigned short *text, unsigned int *selectedRange, unsigned i void getPreeditLocation(float *location, unsigned int length); void allowDirectMarkedTextInput(bool allow, GLViewRef glView); +void openFolderWithFinder(const char *folder_path); + NSWindowRef getMainAppWindow(); GLViewRef getGLView(); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 690fe058db..56d1798dcf 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -462,6 +462,13 @@ long showAlert(std::string text, std::string title, int type) return ret; } +void openFolderWithFinder(const char *folder_path) +{ + @autoreleasepool { + NSString *folderPathString = [NSString stringWithUTF8String:folder_path]; + [[NSWorkspace sharedWorkspace] openFile:folderPathString withApplication:@"Finder"]; + } +} /* GLViewRef getGLView() { diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 34ec85bcf6..b774597eb6 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -46,8 +46,8 @@ extern BOOL gDebugWindowProc; BOOL gHiDPISupport = TRUE; -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; const S32 DEFAULT_REFRESH_RATE = 60; @@ -65,34 +65,34 @@ BOOL LLWindowMacOSX::sUseMultGL = FALSE; BOOL check_for_card(const char* RENDERER, const char* bad_card) { - if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) - { - std::string buffer = llformat( - "Your video card appears to be a %s, which Second Life does not support.\n" - "\n" - "Second Life requires a video card with 32 Mb of memory or more, as well as\n" - "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" - "and ATI Radeon 8500 or better.\n" - "\n" - "If you own a supported card and continue to receive this message, try \n" - "updating to the latest video card drivers. Otherwise look in the\n" - "secondlife.com support section or e-mail technical support\n" - "\n" - "You can try to run Second Life, but it will probably crash or run\n" - "very slowly. Try anyway?", - bad_card); - S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); - if (OSBTN_YES == button) - { - return FALSE; - } - else - { - return TRUE; - } - } - - return FALSE; + if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) + { + std::string buffer = llformat( + "Your video card appears to be a %s, which Second Life does not support.\n" + "\n" + "Second Life requires a video card with 32 Mb of memory or more, as well as\n" + "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" + "and ATI Radeon 8500 or better.\n" + "\n" + "If you own a supported card and continue to receive this message, try \n" + "updating to the latest video card drivers. Otherwise look in the\n" + "secondlife.com support section or e-mail technical support\n" + "\n" + "You can try to run Second Life, but it will probably crash or run\n" + "very slowly. Try anyway?", + bad_card); + S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); + if (OSBTN_YES == button) + { + return FALSE; + } + else + { + return TRUE; + } + } + + return FALSE; } // Switch to determine whether we capture all displays, or just the main one. @@ -110,93 +110,93 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key); static LLWindowMacOSX *gWindowImplementation = NULL; LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, - U32 fsaa_samples) - : LLWindow(NULL, fullscreen, flags) -{ - // *HACK: During window construction we get lots of OS events for window - // reshape, activate, etc. that the viewer isn't ready to handle. - // Route them to a dummy callback structure until the end of constructor. - LLWindowCallbacks null_callbacks; - mCallbacks = &null_callbacks; - - // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). - setupCocoa(); - - // Initialize the keyboard - gKeyboard = new LLKeyboardMacOSX(); - gKeyboard->setCallbacks(callbacks); - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mContext = NULL; - mPixelFormat = NULL; - mDisplay = CGMainDisplayID(); - mSimulatedRightClick = FALSE; - mLastModifiers = 0; - mHandsOffEvents = FALSE; - mCursorDecoupled = FALSE; - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - mNeedsResize = FALSE; - mOverrideAspectRatio = 0.f; - mMaximized = FALSE; - mMinimized = FALSE; - mLanguageTextInputAllowed = FALSE; - mPreeditor = NULL; - mFSAASamples = fsaa_samples; - mForceRebuild = FALSE; - - // Get the original aspect ratio of the main device. - mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); - - // Stash the window title - mWindowTitle = title; - //mWindowTitle[0] = title.length(); - - mDragOverrideCursor = -1; - - // Set up global event handlers (the fullscreen case needs this) - //InstallStandardEventHandler(GetApplicationEventTarget()); - - // Stash an object pointer for OSMessageBox() - gWindowImplementation = this; - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) - { - if(mWindow != NULL) - { - makeWindowOrderFront(mWindow); - } - - if (!gGLManager.initGL()) - { - setupFailure( - "Second Life is unable to run because your video card drivers\n" - "are out of date or unsupported. Please make sure you have\n" - "the latest video card drivers installed.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + BOOL fullscreen, BOOL clearBg, + BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, + U32 fsaa_samples) + : LLWindow(NULL, fullscreen, flags) +{ + // *HACK: During window construction we get lots of OS events for window + // reshape, activate, etc. that the viewer isn't ready to handle. + // Route them to a dummy callback structure until the end of constructor. + LLWindowCallbacks null_callbacks; + mCallbacks = &null_callbacks; + + // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). + setupCocoa(); + + // Initialize the keyboard + gKeyboard = new LLKeyboardMacOSX(); + gKeyboard->setCallbacks(callbacks); + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mContext = NULL; + mPixelFormat = NULL; + mDisplay = CGMainDisplayID(); + mSimulatedRightClick = FALSE; + mLastModifiers = 0; + mHandsOffEvents = FALSE; + mCursorDecoupled = FALSE; + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = FALSE; + mNeedsResize = FALSE; + mOverrideAspectRatio = 0.f; + mMaximized = FALSE; + mMinimized = FALSE; + mLanguageTextInputAllowed = FALSE; + mPreeditor = NULL; + mFSAASamples = fsaa_samples; + mForceRebuild = FALSE; + + // Get the original aspect ratio of the main device. + mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); + + // Stash the window title + mWindowTitle = title; + //mWindowTitle[0] = title.length(); + + mDragOverrideCursor = -1; + + // Set up global event handlers (the fullscreen case needs this) + //InstallStandardEventHandler(GetApplicationEventTarget()); + + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) + { + if(mWindow != NULL) + { + makeWindowOrderFront(mWindow); + } + + if (!gGLManager.initGL()) + { + setupFailure( + "Second Life is unable to run because your video card drivers\n" + "are out of date or unsupported. Please make sure you have\n" + "the latest video card drivers installed.\n" + "If you continue to receive this message, contact customer service.", + "Error", + OSMB_OK); + return; + } //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - - allowLanguageTextInput(NULL, FALSE); - } - - mCallbacks = callbacks; - stop_glerror(); - + initCursors(); + setCursor( UI_CURSOR_ARROW ); + + allowLanguageTextInput(NULL, FALSE); + } + mCallbacks = callbacks; + stop_glerror(); + + } // These functions are used as wrappers for our internal event handling callbacks. @@ -205,7 +205,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) { mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyUp(key, mask); + bool retVal = gKeyboard->handleKeyUp(key, mask); mRawKeyEvent = NULL; return retVal; } @@ -222,22 +222,22 @@ bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wch } mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyDown(key, mask); + bool retVal = gKeyboard->handleKeyDown(key, mask); mRawKeyEvent = NULL; return retVal; } void callResetKeys() { - gKeyboard->resetKeys(); + gKeyboard->resetKeys(); } bool callUnicodeCallback(wchar_t character, unsigned int mask) { NativeKeyEventData eventData; - + memset(&eventData, 0, sizeof(NativeKeyEventData)); - + eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; eventData.mEventType = 0; eventData.mEventModifiers = mask; @@ -245,9 +245,9 @@ bool callUnicodeCallback(wchar_t character, unsigned int mask) eventData.mEventChars = character; eventData.mEventUnmodChars = character; eventData.mEventRepeat = false; - + mRawKeyEvent = &eventData; - + bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); mRawKeyEvent = NULL; return result; @@ -255,18 +255,18 @@ bool callUnicodeCallback(wchar_t character, unsigned int mask) void callFocus() { - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); - } + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); + } } void callFocusLost() { - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } } void callRightMouseDown(float *pos, MASK mask) @@ -275,11 +275,11 @@ void callRightMouseDown(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callRightMouseUp(float *pos, MASK mask) @@ -288,11 +288,11 @@ void callRightMouseUp(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callLeftMouseDown(float *pos, MASK mask) @@ -301,11 +301,11 @@ void callLeftMouseDown(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callLeftMouseUp(float *pos, MASK mask) @@ -314,12 +314,12 @@ void callLeftMouseUp(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); - + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + } void callDoubleClick(float *pos, MASK mask) @@ -328,37 +328,37 @@ void callDoubleClick(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callResize(unsigned int width, unsigned int height) { - if (gWindowImplementation != NULL) - { - gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); - } + if (gWindowImplementation != NULL) + { + gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); + } } void callMouseMoved(float *pos, MASK mask) { - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); - //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); } void callMouseDragged(float *pos, MASK mask) { - LLCoordGL outCoords; + LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); float deltas[2]; @@ -370,78 +370,78 @@ void callMouseDragged(float *pos, MASK mask) void callScrollMoved(float deltaX, float deltaY) { - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); - } + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } } void callMouseExit() { - gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); + gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); } void callWindowFocus() { if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); - } - else - { - LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; - } + { + gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); + } + else + { + LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; + } } void callWindowUnfocus() { - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } } void callWindowHide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); - } +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); + } } void callWindowUnhide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); - } +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); + } } void callWindowDidChangeScreen() { - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); - } + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); + } } void callDeltaUpdate(float *delta, MASK mask) { - gWindowImplementation->updateMouseDeltas(delta); + gWindowImplementation->updateMouseDeltas(delta); } void callOtherMouseDown(float *pos, MASK mask, int button) { - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; if (button == 2) { @@ -455,12 +455,12 @@ void callOtherMouseDown(float *pos, MASK mask, int button) void callOtherMouseUp(float *pos, MASK mask, int button) { - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; if (button == 2) { @@ -474,169 +474,169 @@ void callOtherMouseUp(float *pos, MASK mask, int button) void callModifier(MASK mask) { - gKeyboard->handleModifier(mask); + gKeyboard->handleModifier(mask); } void callHandleDragEntered(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); } void callHandleDragExited(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); } void callHandleDragUpdated(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); } void callHandleDragDropped(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); } void callQuitHandler() { - if (gWindowImplementation) - { - if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) - { - gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); - } - } + if (gWindowImplementation) + { + if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) + { + gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); + } + } } void getPreeditSelectionRange(int *position, int *length) { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getSelectionRange(position, length); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getSelectionRange(position, length); + } } void getPreeditMarkedRange(int *position, int *length) { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getPreeditRange(position, length); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getPreeditRange(position, length); + } } void setPreeditMarkedRange(int position, int length) { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->markAsPreedit(position, length); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->markAsPreedit(position, length); + } } bool handleUnicodeCharacter(wchar_t c) { bool success = false; - if (gWindowImplementation->getPreeditor()) - { + if (gWindowImplementation->getPreeditor()) + { success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); - } - + } + return success; } void resetPreedit() { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->resetPreedit(); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->resetPreedit(); + } } // For reasons of convenience, handle IME updates here. // This largely mirrors the old implementation, only sans the carbon parameters. void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments) { - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - preeditor->resetPreedit(); - // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. - if (replacementRange[0] < replacementRange[1]) - { - const LLWString& text = preeditor->getPreeditString(); - const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); - const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); - preeditor->markAsPreedit(location, length); - } - - LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); - - S32 caret_position = fix_str.length(); - - preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); - } + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + preeditor->resetPreedit(); + // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. + if (replacementRange[0] < replacementRange[1]) + { + const LLWString& text = preeditor->getPreeditString(); + const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); + const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); + preeditor->markAsPreedit(location, length); + } + + LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); + + S32 caret_position = fix_str.length(); + + preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); + } } void getPreeditLocation(float *location, unsigned int length) { - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - LLCoordGL coord; - LLCoordScreen screen; - LLRect rect; - - preeditor->getPreeditLocation(length, &coord, &rect, NULL); - - float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; - - convertRectToScreen(gWindowImplementation->getWindow(), c); - - location[0] = c[0]; - location[1] = c[1]; - } + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + LLCoordGL coord; + LLCoordScreen screen; + LLRect rect; + + preeditor->getPreeditLocation(length, &coord, &rect, NULL); + + float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; + + convertRectToScreen(gWindowImplementation->getWindow(), c); + + location[0] = c[0]; + location[1] = c[1]; + } } void LLWindowMacOSX::updateMouseDeltas(float* deltas) { - if (mCursorDecoupled) - { - mCursorLastEventDeltaX = ll_round(deltas[0]); - mCursorLastEventDeltaY = ll_round(-deltas[1]); - - if (mCursorIgnoreNextDelta) - { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - } - } else { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - } + if (mCursorDecoupled) + { + mCursorLastEventDeltaX = ll_round(deltas[0]); + mCursorLastEventDeltaY = ll_round(-deltas[1]); + + if (mCursorIgnoreNextDelta) + { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = FALSE; + } + } else { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + } } void LLWindowMacOSX::getMouseDeltas(float* delta) { - delta[0] = mCursorLastEventDeltaX; - delta[1] = mCursorLastEventDeltaY; + delta[0] = mCursorLastEventDeltaX; + delta[1] = mCursorLastEventDeltaY; } BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync) { - mFullscreen = fullscreen; - - if (mWindow == NULL) - { - mWindow = getMainAppWindow(); - } - - if(mContext == NULL) - { - // Our OpenGL view is already defined within SecondLife.xib. - // Get the view instead. - mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); - mContext = getCGLContextObj(mGLView); - gGLManager.mVRAM = getVramSize(mGLView); + mFullscreen = fullscreen; + + if (mWindow == NULL) + { + mWindow = getMainAppWindow(); + } + + if(mContext == NULL) + { + // Our OpenGL view is already defined within SecondLife.xib. + // Get the view instead. + mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); + mContext = getCGLContextObj(mGLView); + gGLManager.mVRAM = getVramSize(mGLView); if(!mPixelFormat) { @@ -659,30 +659,30 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits GLint numPixelFormats; CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); - + if(mPixelFormat == NULL) { CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); } } - } - - // This sets up our view to recieve text from our non-inline text input window. - setupInputWindow(mWindow, mGLView); - - // Hook up the context to a drawable - - if(mContext != NULL) - { - - - U32 err = CGLSetCurrentContext(mContext); - if (err != kCGLNoError) - { - setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return FALSE; - } - } + } + + // This sets up our view to recieve text from our non-inline text input window. + setupInputWindow(mWindow, mGLView); + + // Hook up the context to a drawable + + if(mContext != NULL) + { + + + U32 err = CGLSetCurrentContext(mContext); + if (err != kCGLNoError) + { + setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); + return FALSE; + } + } mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); if(mRefreshRate == 0) @@ -691,29 +691,29 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits mRefreshRate = DEFAULT_REFRESH_RATE; } - // Disable vertical sync for swap + // Disable vertical sync for swap toggleVSync(enable_vsync); - //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); + //enable multi-threaded OpenGL + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - makeFirstResponder(mWindow, mGLView); - - return TRUE; + } + } + makeFirstResponder(mWindow, mGLView); + + return TRUE; } @@ -721,66 +721,66 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // This makes this method obsolete. BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp) { - return FALSE; + return FALSE; } void LLWindowMacOSX::destroyContext() { - if (!mContext) - { - // We don't have a context - return; - } - // Unhook the GL context from any drawable it may have - if(mContext != NULL) - { - LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; - CGLSetCurrentContext(NULL); - } - - // Clean up remaining GL state before blowing away window - gGLManager.shutdownGL(); - - // Clean up the pixel format - if(mPixelFormat != NULL) - { - CGLDestroyPixelFormat(mPixelFormat); - mPixelFormat = NULL; - } - - // Clean up the GL context - if(mContext != NULL) - { - CGLDestroyContext(mContext); - } - - // Destroy our LLOpenGLView - if(mGLView != NULL) - { - removeGLView(mGLView); - mGLView = NULL; - } - - // Close the window - if(mWindow != NULL) - { + if (!mContext) + { + // We don't have a context + return; + } + // Unhook the GL context from any drawable it may have + if(mContext != NULL) + { + LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; + CGLSetCurrentContext(NULL); + } + + // Clean up remaining GL state before blowing away window + gGLManager.shutdownGL(); + + // Clean up the pixel format + if(mPixelFormat != NULL) + { + CGLDestroyPixelFormat(mPixelFormat); + mPixelFormat = NULL; + } + + // Clean up the GL context + if(mContext != NULL) + { + CGLDestroyContext(mContext); + } + + // Destroy our LLOpenGLView + if(mGLView != NULL) + { + removeGLView(mGLView); + mGLView = NULL; + } + + // Close the window + if(mWindow != NULL) + { NSWindowRef dead_window = mWindow; mWindow = NULL; - closeWindow(dead_window); - } + closeWindow(dead_window); + } } LLWindowMacOSX::~LLWindowMacOSX() { - destroyContext(); + destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + if(mSupportedResolutions != NULL) + { + delete []mSupportedResolutions; + } - gWindowImplementation = NULL; + gWindowImplementation = NULL; } @@ -791,20 +791,20 @@ void LLWindowMacOSX::show() void LLWindowMacOSX::hide() { - setMouseClipping(FALSE); + setMouseClipping(FALSE); } //virtual void LLWindowMacOSX::minimize() { - setMouseClipping(FALSE); - showCursor(); + setMouseClipping(FALSE); + showCursor(); } //virtual void LLWindowMacOSX::restore() { - show(); + show(); } @@ -812,193 +812,193 @@ void LLWindowMacOSX::restore() // Usually called from LLWindowManager::destroyWindow() void LLWindowMacOSX::close() { - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } + // Is window is already closed? + // if (!mWindow) + // { + // return; + // } - // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(FALSE); - showCursor(); + // Make sure cursor is visible and we haven't mangled the clipping state. + setMouseClipping(FALSE); + showCursor(); - destroyContext(); + destroyContext(); } BOOL LLWindowMacOSX::isValid() { - if(mFullscreen) - { - return(TRUE); - } + if(mFullscreen) + { + return(TRUE); + } - return (mWindow != NULL); + return (mWindow != NULL); } BOOL LLWindowMacOSX::getVisible() { - BOOL result = FALSE; + BOOL result = FALSE; - if(mFullscreen) - { - result = TRUE; - }if (mWindow) - { - result = TRUE; - } + if(mFullscreen) + { + result = TRUE; + }if (mWindow) + { + result = TRUE; + } - return(result); + return(result); } BOOL LLWindowMacOSX::getMinimized() { - return mMinimized; + return mMinimized; } BOOL LLWindowMacOSX::getMaximized() { - return mMaximized; + return mMaximized; } BOOL LLWindowMacOSX::maximize() { - if (mWindow && !mMaximized) - { - } + if (mWindow && !mMaximized) + { + } - return mMaximized; + return mMaximized; } BOOL LLWindowMacOSX::getFullscreen() { - return mFullscreen; + return mFullscreen; } void LLWindowMacOSX::gatherInput() { - updateCursor(); + updateCursor(); } BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) { - S32 err = -1; + S32 err = -1; - if(mFullscreen) - { - position->mX = 0; - position->mY = 0; - err = noErr; - } - else if(mWindow) - { - const CGPoint & pos = getContentViewBoundsPosition(mWindow); + if(mFullscreen) + { + position->mX = 0; + position->mY = 0; + err = noErr; + } + else if(mWindow) + { + const CGPoint & pos = getContentViewBoundsPosition(mWindow); - position->mX = pos.x; - position->mY = pos.y; + position->mX = pos.x; + position->mY = pos.y; - err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; - } + err = noErr; + } + else + { + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; + } - return (err == noErr); + return (err == noErr); } BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) { - S32 err = -1; + S32 err = -1; - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - size->mX = sz.width; - size->mY = sz.height; + size->mX = sz.width; + size->mY = sz.height; err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } - return (err == noErr); + return (err == noErr); } BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) { - S32 err = -1; - - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - - size->mX = sz.width; - size->mY = sz.height; + S32 err = -1; + + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + + size->mX = sz.width; + size->mY = sz.height; err = noErr; - - - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); + + + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); } BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) { - if(mWindow) - { - float pos[2] = {float(position.mX), float(position.mY)}; - setWindowPos(mWindow, pos); - } + if(mWindow) + { + float pos[2] = {float(position.mX), float(position.mY)}; + setWindowPos(mWindow, pos); + } - return TRUE; + return TRUE; } BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) { - if(mWindow) - { + if(mWindow) + { LLCoordWindow to; convertCoords(size, &to); - setWindowSize(mWindow, to.mX, to.mY); + setWindowSize(mWindow, to.mX, to.mY); return TRUE; - } + } - return FALSE; + return FALSE; } BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) { - if (mWindow) - { + if (mWindow) + { const int titlePadding = 22; setWindowSize(mWindow, size.mX, size.mY + titlePadding); return TRUE; - } - - return FALSE; + } + + return FALSE; } void LLWindowMacOSX::swapBuffers() { - CGLFlushDrawable(mContext); + CGLFlushDrawable(mContext); } void LLWindowMacOSX::restoreGLContext() @@ -1008,106 +1008,106 @@ void LLWindowMacOSX::restoreGLContext() F32 LLWindowMacOSX::getGamma() { - F32 result = 2.2; // Default to something sane - - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) == noErr) - { - // So many choices... - // Let's just return the green channel gamma for now. - result = greenGamma; - } - - return result; + F32 result = 2.2; // Default to something sane + + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) == noErr) + { + // So many choices... + // Let's just return the green channel gamma for now. + result = greenGamma; + } + + return result; } U32 LLWindowMacOSX::getFSAASamples() { - return mFSAASamples; + return mFSAASamples; } void LLWindowMacOSX::setFSAASamples(const U32 samples) { - mFSAASamples = samples; - mForceRebuild = TRUE; + mFSAASamples = samples; + mForceRebuild = TRUE; } BOOL LLWindowMacOSX::restoreGamma() { - CGDisplayRestoreColorSyncSettings(); - return true; + CGDisplayRestoreColorSyncSettings(); + return true; } BOOL LLWindowMacOSX::setGamma(const F32 gamma) { - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - // MBW -- XXX -- Should we allow this in windowed mode? - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) != noErr) - { - return false; - } - - if(CGSetDisplayTransferByFormula( - mDisplay, - redMin, - redMax, - gamma, - greenMin, - greenMax, - gamma, - blueMin, - blueMax, - gamma) != noErr) - { - return false; - } - - - return true; + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + // MBW -- XXX -- Should we allow this in windowed mode? + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) != noErr) + { + return false; + } + + if(CGSetDisplayTransferByFormula( + mDisplay, + redMin, + redMax, + gamma, + greenMin, + greenMax, + gamma, + blueMin, + blueMax, + gamma) != noErr) + { + return false; + } + + + return true; } BOOL LLWindowMacOSX::isCursorHidden() { - return mCursorHidden; + return mCursorHidden; } @@ -1115,142 +1115,142 @@ BOOL LLWindowMacOSX::isCursorHidden() // Constrains the mouse to the window. void LLWindowMacOSX::setMouseClipping( BOOL b ) { - // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. - mIsMouseClipping = b; + // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. + mIsMouseClipping = b; - if(b) - { - // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; - } - else - { - // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; - } + if(b) + { + // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; + } + else + { + // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; + } - adjustCursorDecouple(); + adjustCursorDecouple(); } BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) { - BOOL result = FALSE; - LLCoordScreen screen_pos; + BOOL result = FALSE; + LLCoordScreen screen_pos; - if (!convertCoords(position, &screen_pos)) - { - return FALSE; - } + if (!convertCoords(position, &screen_pos)) + { + return FALSE; + } - CGPoint newPosition; + CGPoint newPosition; - // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; - newPosition.x = screen_pos.mX; - newPosition.y = screen_pos.mY; + newPosition.x = screen_pos.mX; + newPosition.y = screen_pos.mY; - CGSetLocalEventsSuppressionInterval(0.0); - if(CGWarpMouseCursorPosition(newPosition) == noErr) - { - result = TRUE; - } + CGSetLocalEventsSuppressionInterval(0.0); + if(CGWarpMouseCursorPosition(newPosition) == noErr) + { + result = TRUE; + } - // Under certain circumstances, this will trigger us to decouple the cursor. - adjustCursorDecouple(true); + // Under certain circumstances, this will trigger us to decouple the cursor. + adjustCursorDecouple(true); - // trigger mouse move callback - LLCoordGL gl_pos; - convertCoords(position, &gl_pos); - float scale = getSystemUISize(); - gl_pos.mX *= scale; - gl_pos.mY *= scale; - mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); + // trigger mouse move callback + LLCoordGL gl_pos; + convertCoords(position, &gl_pos); + float scale = getSystemUISize(); + gl_pos.mX *= scale; + gl_pos.mY *= scale; + mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); - return result; + return result; } BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) { - float cursor_point[2]; - LLCoordScreen screen_pos; - - if(mWindow == NULL) - return FALSE; + float cursor_point[2]; + LLCoordScreen screen_pos; - getCursorPos(mWindow, cursor_point); + if(mWindow == NULL) + return FALSE; + + getCursorPos(mWindow, cursor_point); - if(mCursorDecoupled) - { - // CGMouseDelta x, y; + if(mCursorDecoupled) + { + // CGMouseDelta x, y; - // If the cursor's decoupled, we need to read the latest movement delta as well. - // CGGetLastMouseDelta( &x, &y ); - // cursor_point.h += x; - // cursor_point.v += y; + // If the cursor's decoupled, we need to read the latest movement delta as well. + // CGGetLastMouseDelta( &x, &y ); + // cursor_point.h += x; + // cursor_point.v += y; - // CGGetLastMouseDelta may behave strangely when the cursor's first captured. - // Stash in the event handler instead. - cursor_point[0] += mCursorLastEventDeltaX; - cursor_point[1] += mCursorLastEventDeltaY; - } + // CGGetLastMouseDelta may behave strangely when the cursor's first captured. + // Stash in the event handler instead. + cursor_point[0] += mCursorLastEventDeltaX; + cursor_point[1] += mCursorLastEventDeltaY; + } - float scale = getSystemUISize(); - position->mX = cursor_point[0] * scale; - position->mY = cursor_point[1] * scale; + float scale = getSystemUISize(); + position->mX = cursor_point[0] * scale; + position->mY = cursor_point[1] * scale; - return TRUE; + return TRUE; } void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) { - if(mIsMouseClipping && mCursorHidden) - { - if(warpingMouse) - { - // The cursor should be decoupled. Make sure it is. - if(!mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(false); - mCursorDecoupled = true; - mCursorIgnoreNextDelta = TRUE; - } - } - } - else - { - // The cursor should not be decoupled. Make sure it isn't. - if(mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(true); - mCursorDecoupled = false; - } - } + if(mIsMouseClipping && mCursorHidden) + { + if(warpingMouse) + { + // The cursor should be decoupled. Make sure it is. + if(!mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(false); + mCursorDecoupled = true; + mCursorIgnoreNextDelta = TRUE; + } + } + } + else + { + // The cursor should not be decoupled. Make sure it isn't. + if(mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(true); + mCursorDecoupled = false; + } + } } F32 LLWindowMacOSX::getNativeAspectRatio() { - if (mFullscreen) - { - return (F32)mFullscreenWidth / (F32)mFullscreenHeight; - } - else - { - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. + if (mFullscreen) + { + return (F32)mFullscreenWidth / (F32)mFullscreenHeight; + } + else + { + // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution + // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } - return mOriginalAspectRatio; - } + return mOriginalAspectRatio; + } } F32 LLWindowMacOSX::getPixelAspectRatio() { - //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode - return 1.f; + //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode + return 1.f; } U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { @@ -1281,165 +1281,165 @@ void LLWindowMacOSX::afterDialog() void LLWindowMacOSX::flashIcon(F32 seconds) { - // For consistency with OS X conventions, the number of seconds given is ignored and - // left up to the OS (which will actually bounce it for one second). - requestUserAttention(); + // For consistency with OS X conventions, the number of seconds given is ignored and + // left up to the OS (which will actually bounce it for one second). + requestUserAttention(); } BOOL LLWindowMacOSX::isClipboardTextAvailable() { - return pasteBoardAvailable(); + return pasteBoardAvailable(); } BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) { unsigned short* pboard_data = copyFromPBoard(); // must free returned data - llutf16string str(pboard_data); + llutf16string str(pboard_data); free(pboard_data); - dst = utf16str_to_wstring(str); - if (dst != L"") - { - return true; - } else { - return false; - } + dst = utf16str_to_wstring(str); + if (dst != L"") + { + return true; + } else { + return false; + } } BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) { - BOOL result = false; - llutf16string utf16str = wstring_to_utf16str(s); - - result = copyToPBoard(utf16str.data(), utf16str.length()); + BOOL result = false; + llutf16string utf16str = wstring_to_utf16str(s); + + result = copyToPBoard(utf16str.data(), utf16str.length()); - return result; + return result; } // protected BOOL LLWindowMacOSX::resetDisplayResolution() { - // This is only called from elsewhere in this class, and it's not used by the Mac implementation. - return true; + // This is only called from elsewhere in this class, and it's not used by the Mac implementation. + return true; } LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) { - if (!mSupportedResolutions) - { - CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); - - if(modes != NULL) - { - CFIndex index, cnt; - - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - mNumSupportedResolutions = 0; - - // Examine each mode - cnt = CFArrayGetCount( modes ); - - for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) - { - // Pull the mode dictionary out of the CFArray - CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); - long width = getDictLong(mode, kCGDisplayWidth); - long height = getDictLong(mode, kCGDisplayHeight); - long bits = getDictLong(mode, kCGDisplayBitsPerPixel); - - if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) - { - BOOL resolution_exists = FALSE; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == width && - mSupportedResolutions[i].mHeight == height) - { - resolution_exists = TRUE; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = width; - mSupportedResolutions[mNumSupportedResolutions].mHeight = height; - mNumSupportedResolutions++; - } - } - } + if (!mSupportedResolutions) + { + CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); + + if(modes != NULL) + { + CFIndex index, cnt; + + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + mNumSupportedResolutions = 0; + + // Examine each mode + cnt = CFArrayGetCount( modes ); + + for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) + { + // Pull the mode dictionary out of the CFArray + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); + long width = getDictLong(mode, kCGDisplayWidth); + long height = getDictLong(mode, kCGDisplayHeight); + long bits = getDictLong(mode, kCGDisplayBitsPerPixel); + + if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) + { + BOOL resolution_exists = FALSE; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == width && + mSupportedResolutions[i].mHeight == height) + { + resolution_exists = TRUE; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = width; + mSupportedResolutions[mNumSupportedResolutions].mHeight = height; + mNumSupportedResolutions++; + } + } + } CFRelease(modes); - } - } + } + } - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; } BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) { - to->mX = from.mX; - to->mY = from.mY; - return TRUE; + to->mX = from.mX; + to->mY = from.mY; + return TRUE; } BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) { - to->mX = from.mX; - to->mY = from.mY; - return TRUE; + to->mX = from.mX; + to->mY = from.mY; + return TRUE; } BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) { - if(mWindow) - { - float mouse_point[2]; - - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; + if(mWindow) + { + float mouse_point[2]; - convertScreenToWindow(mWindow, mouse_point); + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertScreenToWindow(mWindow, mouse_point); - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; - return TRUE; - } - return FALSE; + return TRUE; + } + return FALSE; } BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) { - if(mWindow) - { - float mouse_point[2]; + if(mWindow) + { + float mouse_point[2]; - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertWindowToScreen(mWindow, mouse_point); - convertWindowToScreen(mWindow, mouse_point); + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; - - return TRUE; - } - return FALSE; + return TRUE; + } + return FALSE; } BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } @@ -1447,66 +1447,66 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) { - destroyContext(); + destroyContext(); - OSMessageBox(text, caption, type); + OSMessageBox(text, caption, type); } - // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature - // it is handled at a very low-level + // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature + // it is handled at a very low-level const char* cursorIDToName(int id) { - switch (id) - { - case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; - case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; - case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; - case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; - case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; - case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; - case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; - case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; - case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; - case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; - case UI_CURSOR_NO: return "UI_CURSOR_NO"; - case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; - case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; - case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; - case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; - case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; - case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; - case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; - case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; - case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; - case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; - case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; - case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; - case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; - case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; - case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; - case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; - case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; - case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; - case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; - case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; - case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; - case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; - case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; - case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; - case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; - case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; - case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; - case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; - } - - LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; - - return "UI_CURSOR_ARROW"; + switch (id) + { + case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; + case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; + case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; + case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; + case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; + case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; + case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; + case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; + case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; + case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; + case UI_CURSOR_NO: return "UI_CURSOR_NO"; + case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; + case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; + case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; + case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; + case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; + case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; + case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; + case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; + case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; + case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; + case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; + case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; + case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; + case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; + case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; + case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; + case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; + case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; + case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; + case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; + case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; + case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; + case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; + case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; + case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; + case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; + case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; + case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; + case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; + } + + LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; + + return "UI_CURSOR_ARROW"; } static CursorRef gCursors[UI_CURSOR_COUNT]; @@ -1514,233 +1514,233 @@ static CursorRef gCursors[UI_CURSOR_COUNT]; static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) { - // cursors are in <Application Bundle>/Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif - std::string fullpath = gDirUtilp->add( - gDirUtilp->getAppRODataDir(), - "cursors_mac", - cursorIDToName(cursorid) + std::string(".tif")); + // cursors are in <Application Bundle>/Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif + std::string fullpath = gDirUtilp->add( + gDirUtilp->getAppRODataDir(), + "cursors_mac", + cursorIDToName(cursorid) + std::string(".tif")); - gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); + gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); } void LLWindowMacOSX::updateCursor() { - S32 result = 0; - - if (mDragOverrideCursor != -1) - { - // A drag is in progress...remember the requested cursor and we'll - // restore it when it is done - mCurrentCursor = mNextCursor; - return; - } - - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - + S32 result = 0; + + if (mDragOverrideCursor != -1) + { + // A drag is in progress...remember the requested cursor and we'll + // restore it when it is done + mCurrentCursor = mNextCursor; + return; + } + + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + if(mCurrentCursor == mNextCursor) { if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) { - hideNSCursor(); + hideNSCursor(); adjustCursorDecouple(); } return; } - // RN: replace multi-drag cursors with single versions - if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) - { - mNextCursor = UI_CURSOR_ARROWDRAG; - } - else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) - { - mNextCursor = UI_CURSOR_ARROWCOPY; - } - - switch(mNextCursor) - { - default: - case UI_CURSOR_ARROW: - setArrowCursor(); - if(mCursorHidden) - { - // Since InitCursor resets the hide level, correct for it here. - hideNSCursor(); - } - break; - - // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. - // Find out what they look like and replicate them. - - // These are essentially correct - case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; - case UI_CURSOR_IBEAM: setIBeamCursor(); break; - case UI_CURSOR_CROSS: setCrossCursor(); break; - case UI_CURSOR_HAND: setPointingHandCursor(); break; - // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; - case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; - - // Double-check these - case UI_CURSOR_NO: - case UI_CURSOR_SIZEWE: - case UI_CURSOR_SIZENS: - case UI_CURSOR_SIZENWSE: - case UI_CURSOR_SIZENESW: - case UI_CURSOR_WORKING: - case UI_CURSOR_TOOLGRAB: - case UI_CURSOR_TOOLLAND: - case UI_CURSOR_TOOLFOCUS: - case UI_CURSOR_TOOLCREATE: - case UI_CURSOR_ARROWDRAG: - case UI_CURSOR_NOLOCKED: - case UI_CURSOR_ARROWLOCKED: - case UI_CURSOR_GRABLOCKED: - case UI_CURSOR_PIPETTE: - case UI_CURSOR_TOOLTRANSLATE: - case UI_CURSOR_TOOLROTATE: - case UI_CURSOR_TOOLSCALE: - case UI_CURSOR_TOOLCAMERA: - case UI_CURSOR_TOOLPAN: - case UI_CURSOR_TOOLZOOMIN: - case UI_CURSOR_TOOLPICKOBJECT3: - case UI_CURSOR_TOOLPLAY: - case UI_CURSOR_TOOLPAUSE: - case UI_CURSOR_TOOLMEDIAOPEN: - case UI_CURSOR_TOOLSIT: - case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLOPEN: - case UI_CURSOR_TOOLPATHFINDING: - case UI_CURSOR_TOOLPATHFINDING_PATH_START: - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: - case UI_CURSOR_TOOLPATHFINDING_PATH_END: - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: - case UI_CURSOR_TOOLNO: - result = setImageCursor(gCursors[mNextCursor]); - break; - - } - - if(result != noErr) - { - setArrowCursor(); - } - - mCurrentCursor = mNextCursor; + // RN: replace multi-drag cursors with single versions + if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) + { + mNextCursor = UI_CURSOR_ARROWDRAG; + } + else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) + { + mNextCursor = UI_CURSOR_ARROWCOPY; + } + + switch(mNextCursor) + { + default: + case UI_CURSOR_ARROW: + setArrowCursor(); + if(mCursorHidden) + { + // Since InitCursor resets the hide level, correct for it here. + hideNSCursor(); + } + break; + + // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. + // Find out what they look like and replicate them. + + // These are essentially correct + case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; + case UI_CURSOR_IBEAM: setIBeamCursor(); break; + case UI_CURSOR_CROSS: setCrossCursor(); break; + case UI_CURSOR_HAND: setPointingHandCursor(); break; + // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; + case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; + + // Double-check these + case UI_CURSOR_NO: + case UI_CURSOR_SIZEWE: + case UI_CURSOR_SIZENS: + case UI_CURSOR_SIZENWSE: + case UI_CURSOR_SIZENESW: + case UI_CURSOR_WORKING: + case UI_CURSOR_TOOLGRAB: + case UI_CURSOR_TOOLLAND: + case UI_CURSOR_TOOLFOCUS: + case UI_CURSOR_TOOLCREATE: + case UI_CURSOR_ARROWDRAG: + case UI_CURSOR_NOLOCKED: + case UI_CURSOR_ARROWLOCKED: + case UI_CURSOR_GRABLOCKED: + case UI_CURSOR_PIPETTE: + case UI_CURSOR_TOOLTRANSLATE: + case UI_CURSOR_TOOLROTATE: + case UI_CURSOR_TOOLSCALE: + case UI_CURSOR_TOOLCAMERA: + case UI_CURSOR_TOOLPAN: + case UI_CURSOR_TOOLZOOMIN: + case UI_CURSOR_TOOLPICKOBJECT3: + case UI_CURSOR_TOOLPLAY: + case UI_CURSOR_TOOLPAUSE: + case UI_CURSOR_TOOLMEDIAOPEN: + case UI_CURSOR_TOOLSIT: + case UI_CURSOR_TOOLBUY: + case UI_CURSOR_TOOLOPEN: + case UI_CURSOR_TOOLPATHFINDING: + case UI_CURSOR_TOOLPATHFINDING_PATH_START: + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: + case UI_CURSOR_TOOLPATHFINDING_PATH_END: + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: + case UI_CURSOR_TOOLNO: + result = setImageCursor(gCursors[mNextCursor]); + break; + + } + + if(result != noErr) + { + setArrowCursor(); + } + + mCurrentCursor = mNextCursor; } ECursorType LLWindowMacOSX::getCursor() const { - return mCurrentCursor; + return mCurrentCursor; } void LLWindowMacOSX::initCursors() { - initPixmapCursor(UI_CURSOR_NO, 8, 8); - initPixmapCursor(UI_CURSOR_WORKING, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); - initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); - initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); - initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); - initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); - initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); - initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); - initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); - initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); - initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); + initPixmapCursor(UI_CURSOR_NO, 8, 8); + initPixmapCursor(UI_CURSOR_WORKING, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); + initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); + initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); + initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); + initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); + initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); + initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); + initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); + initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); + initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); - - initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); - initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); + initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); + + initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); + initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10); } void LLWindowMacOSX::captureMouse() { - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. } void LLWindowMacOSX::releaseMouse() { - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. } void LLWindowMacOSX::hideCursor() { - if(!mCursorHidden) - { - // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; - hideNSCursor(); - } - else - { - // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; - } + if(!mCursorHidden) + { + // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; + mCursorHidden = TRUE; + mHideCursorPermanent = TRUE; + hideNSCursor(); + } + else + { + // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; + } - adjustCursorDecouple(); + adjustCursorDecouple(); } void LLWindowMacOSX::showCursor() { - if(mCursorHidden || !isCGCursorVisible()) - { - // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; - showNSCursor(); - } - else - { - // LL_INFOS() << "showCursor: already visible" << LL_ENDL; - } + if(mCursorHidden || !isCGCursorVisible()) + { + // LL_INFOS() << "showCursor: showing" << LL_ENDL; + mCursorHidden = FALSE; + mHideCursorPermanent = FALSE; + showNSCursor(); + } + else + { + // LL_INFOS() << "showCursor: already visible" << LL_ENDL; + } - adjustCursorDecouple(); + adjustCursorDecouple(); } void LLWindowMacOSX::showCursorFromMouseMove() { - if (!mHideCursorPermanent) - { - showCursor(); - } + if (!mHideCursorPermanent) + { + showCursor(); + } } void LLWindowMacOSX::hideCursorUntilMouseMove() { - if (!mHideCursorPermanent) - { - hideCursor(); - mHideCursorPermanent = FALSE; - } + if (!mHideCursorPermanent) + { + hideCursor(); + mHideCursorPermanent = FALSE; + } } @@ -1750,7 +1750,7 @@ void LLWindowMacOSX::hideCursorUntilMouseMove() // LLSplashScreenMacOSX::LLSplashScreenMacOSX() { - mWindow = NULL; + mWindow = NULL; } LLSplashScreenMacOSX::~LLSplashScreenMacOSX() @@ -1759,201 +1759,201 @@ LLSplashScreenMacOSX::~LLSplashScreenMacOSX() void LLSplashScreenMacOSX::showImpl() { - // This code _could_ be used to display a spash screen... + // This code _could_ be used to display a spash screen... } void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) { - if(mWindow != NULL) - { - CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); - } + if(mWindow != NULL) + { + CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); + } } void LLSplashScreenMacOSX::hideImpl() { - if(mWindow != NULL) - { - mWindow = NULL; - } + if(mWindow != NULL) + { + mWindow = NULL; + } } S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) { - return showAlert(text, caption, type); + return showAlert(text, caption, type); } // Open a URL with the user's default web browser. // Must begin with protocol identifier. void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) { - // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. - - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - S32 result = 0; - CFURLRef urlRef = NULL; - - LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; - - CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); - if (stringRef) - { - // This will succeed if the string is a full URL, including the http:// - // Note that URLs specified this way need to be properly percent-escaped. - urlRef = CFURLCreateWithString(NULL, stringRef, NULL); - - // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs - - CFRelease(stringRef); - } - - if (urlRef) - { - result = LSOpenCFURLRef(urlRef, NULL); - - if (result != noErr) - { - LL_INFOS() << "Error " << result << " on open." << LL_ENDL; - } - - CFRelease(urlRef); - } - else - { - LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; - } + // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. + + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + S32 result = 0; + CFURLRef urlRef = NULL; + + LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; + + CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); + if (stringRef) + { + // This will succeed if the string is a full URL, including the http:// + // Note that URLs specified this way need to be properly percent-escaped. + urlRef = CFURLCreateWithString(NULL, stringRef, NULL); + + // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs + + CFRelease(stringRef); + } + + if (urlRef) + { + result = LSOpenCFURLRef(urlRef, NULL); + + if (result != noErr) + { + LL_INFOS() << "Error " << result << " on open." << LL_ENDL; + } + + CFRelease(urlRef); + } + else + { + LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; + } } LLSD LLWindowMacOSX::getNativeKeyData() { - LLSD result = LLSD::emptyMap(); + LLSD result = LLSD::emptyMap(); - if(mRawKeyEvent) - { + if(mRawKeyEvent) + { result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); - } + } - LL_DEBUGS() << "native key data is: " << result << LL_ENDL; + LL_DEBUGS() << "native key data is: " << result << LL_ENDL; - return result; + return result; } BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - BOOL retval = FALSE; - OSErr error = noErr; - NColorPickerInfo info; - - memset(&info, 0, sizeof(info)); - info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); - info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); - info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); - info.placeWhere = kCenterOnMainScreen; - - error = NPickColor(&info); - - if (error == noErr) - { - retval = info.newColorChosen; - if (info.newColorChosen) - { - *r = ((float) info.theColor.color.rgb.red) / 65535.0; - *g = ((float) info.theColor.color.rgb.green) / 65535.0; - *b = ((float) info.theColor.color.rgb.blue) / 65535.0; - } - } - - return (retval); + BOOL retval = FALSE; + OSErr error = noErr; + NColorPickerInfo info; + + memset(&info, 0, sizeof(info)); + info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); + info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); + info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); + info.placeWhere = kCenterOnMainScreen; + + error = NPickColor(&info); + + if (error == noErr) + { + retval = info.newColorChosen; + if (info.newColorChosen) + { + *r = ((float) info.theColor.color.rgb.red) / 65535.0; + *g = ((float) info.theColor.color.rgb.green) / 65535.0; + *b = ((float) info.theColor.color.rgb.blue) / 65535.0; + } + } + + return (retval); } void *LLWindowMacOSX::getPlatformWindow() { - // NOTE: this will be NULL in fullscreen mode. Plan accordingly. - return (void*)mWindow; + // NOTE: this will be NULL in fullscreen mode. Plan accordingly. + return (void*)mWindow; } // get a double value from a dictionary /* static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) { - double double_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it - return -1; // fail - return double_value; // otherwise return the long value + double double_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it + return -1; // fail + return double_value; // otherwise return the long value }*/ // get a long value from a dictionary static long getDictLong (CFDictionaryRef refDict, CFStringRef key) { - long int_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it - return -1; // fail - return int_value; // otherwise return the long value + long int_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it + return -1; // fail + return int_value; // otherwise return the long value } void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { - if (preeditor != mPreeditor && !b) - { - // This condition may occur by a call to - // setEnabled(BOOL) against LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - // We need to interrupt before updating mPreeditor, - // so that the fix string from input method goes to - // the old preeditor. - if (mLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - if (b == mLanguageTextInputAllowed) - { - return; - } - mLanguageTextInputAllowed = b; + if (preeditor != mPreeditor && !b) + { + // This condition may occur by a call to + // setEnabled(BOOL) against LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + // We need to interrupt before updating mPreeditor, + // so that the fix string from input method goes to + // the old preeditor. + if (mLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + if (b == mLanguageTextInputAllowed) + { + return; + } + mLanguageTextInputAllowed = b; allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit } -class sharedContext +class sharedContext { public: CGLContextObj mContext; @@ -1963,7 +1963,7 @@ void* LLWindowMacOSX::createSharedContext() { sharedContext* sc = new sharedContext(); CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); - + if (sUseMultGL) { CGLEnable(mContext, kCGLCEMPEngine); @@ -1977,23 +1977,23 @@ void LLWindowMacOSX::makeContextCurrent(void* context) CGLSetCurrentContext(((sharedContext*)context)->mContext); //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); - - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - + } + } + } void LLWindowMacOSX::destroySharedContext(void* context) @@ -2016,166 +2016,171 @@ void LLWindowMacOSX::toggleVSync(bool enable_vsync) { frames_per_swap = 1; } - + CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); } void LLWindowMacOSX::interruptLanguageTextInput() { - commitCurrentPreedit(mGLView); + commitCurrentPreedit(mGLView); } std::vector<std::string> LLWindowMacOSX::getDisplaysResolutionList() { - std::vector<std::string> resolution_list; - - CGDirectDisplayID display_ids[10]; - uint32_t found_displays = 0; - CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); - - if (kCGErrorSuccess != err) - { - LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; - return std::vector<std::string>(); - } - - for (uint32_t i = 0; i < found_displays; i++) - { - S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); - S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); - - resolution_list.push_back(res); - } - - return resolution_list; + std::vector<std::string> resolution_list; + + CGDirectDisplayID display_ids[10]; + uint32_t found_displays = 0; + CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); + + if (kCGErrorSuccess != err) + { + LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; + return std::vector<std::string>(); + } + + for (uint32_t i = 0; i < found_displays; i++) + { + S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); + S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + resolution_list.push_back(res); + } + + return resolution_list; } //static std::vector<std::string> LLWindowMacOSX::getDynamicFallbackFontList() { - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector<std::string>(); + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector<std::string>(); } // static MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) { - MASK mask = 0; - if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } - if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } - if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } - return mask; + MASK mask = 0; + if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } + if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } + if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } + return mask; } F32 LLWindowMacOSX::getSystemUISize() { - return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); + return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); +} + +void LLWindowMacOSX::openFolder(const std::string &path) +{ + openFolderWithFinder(path.c_str()); } #if LL_OS_DRAGDROP_ENABLED /* S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, - void * handlerRefCon, DragRef drag) + void * handlerRefCon, DragRef drag) { - S16 result = 0; - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + S16 result = 0; + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; + LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; - switch(message) - { - case kDragTrackingInWindow: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); - break; + switch(message) + { + case kDragTrackingInWindow: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); + break; - case kDragTrackingEnterHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); - break; + case kDragTrackingEnterHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); + break; - case kDragTrackingLeaveHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); - break; + case kDragTrackingLeaveHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); + break; - default: - break; - } + default: + break; + } - return result; + return result; } OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, - DragRef drag) + DragRef drag) { - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); } */ void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) { - MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); - - float mouse_point[2]; - // This will return the mouse point in window coords - getCursorPos(mWindow, mouse_point); - LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); - LLCoordGL gl_pos; - convertCoords(window_coords, &gl_pos); - - if(!url.empty()) - { - LLWindowCallbacks::DragNDropResult res = - mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); - - switch (res) { - case LLWindowCallbacks::DND_NONE: // No drop allowed - if (action == LLWindowCallbacks::DNDA_TRACK) - { - mDragOverrideCursor = 0; - } - else { - mDragOverrideCursor = -1; - } - break; - case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation - mDragOverrideCursor = UI_CURSOR_NO; - break; - case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation - mDragOverrideCursor = UI_CURSOR_ARROWCOPY; - break; - default: - mDragOverrideCursor = -1; - break; - } - // This overrides the cursor being set by setCursor. - // This is a bit of a hack workaround because lots of areas - // within the viewer just blindly set the cursor. - if (mDragOverrideCursor == -1) - { - // Restore the cursor - ECursorType temp_cursor = mCurrentCursor; - // get around the "setting the same cursor" code in setCursor() - mCurrentCursor = UI_CURSOR_COUNT; - setCursor(temp_cursor); - } - else { - // Override the cursor - switch (mDragOverrideCursor) { - case 0: - setArrowCursor(); - break; - case UI_CURSOR_NO: - setNotAllowedCursor(); - case UI_CURSOR_ARROWCOPY: - setCopyCursor(); - default: - break; - }; - } - } + MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); + + float mouse_point[2]; + // This will return the mouse point in window coords + getCursorPos(mWindow, mouse_point); + LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); + LLCoordGL gl_pos; + convertCoords(window_coords, &gl_pos); + + if(!url.empty()) + { + LLWindowCallbacks::DragNDropResult res = + mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); + + switch (res) { + case LLWindowCallbacks::DND_NONE: // No drop allowed + if (action == LLWindowCallbacks::DNDA_TRACK) + { + mDragOverrideCursor = 0; + } + else { + mDragOverrideCursor = -1; + } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = UI_CURSOR_NO; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = UI_CURSOR_ARROWCOPY; + break; + default: + mDragOverrideCursor = -1; + break; + } + // This overrides the cursor being set by setCursor. + // This is a bit of a hack workaround because lots of areas + // within the viewer just blindly set the cursor. + if (mDragOverrideCursor == -1) + { + // Restore the cursor + ECursorType temp_cursor = mCurrentCursor; + // get around the "setting the same cursor" code in setCursor() + mCurrentCursor = UI_CURSOR_COUNT; + setCursor(temp_cursor); + } + else { + // Override the cursor + switch (mDragOverrideCursor) { + case 0: + setArrowCursor(); + break; + case UI_CURSOR_NO: + setNotAllowedCursor(); + case UI_CURSOR_ARROWCOPY: + setCopyCursor(); + default: + break; + }; + } + } } #endif // LL_OS_DRAGDROP_ENABLED diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 196a284ac3..5f728fb72e 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -1,25 +1,25 @@ -/** +/** * @file llwindowmacosx.h * @brief Mac implementation of LLWindow class * * $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$ */ @@ -44,94 +44,96 @@ class LLWindowMacOSX : public LLWindow { public: - void show() override; - void hide() override; - void close() override; - BOOL getVisible() override; - BOOL getMinimized() override; - BOOL getMaximized() override; - BOOL maximize() override; - void minimize() override; - void restore() override; - BOOL getFullscreen(); - BOOL getPosition(LLCoordScreen *position) override; - BOOL getSize(LLCoordScreen *size) override; - BOOL getSize(LLCoordWindow *size) override; - BOOL setPosition(LLCoordScreen position) override; - BOOL setSizeImpl(LLCoordScreen size) override; - BOOL setSizeImpl(LLCoordWindow size) override; - BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override; - BOOL setCursorPosition(LLCoordWindow position) override; - BOOL getCursorPosition(LLCoordWindow *position) override; - void showCursor() override; - void hideCursor() override; - void showCursorFromMouseMove() override; - void hideCursorUntilMouseMove() override; - BOOL isCursorHidden() override; - void updateCursor() override; - ECursorType getCursor() const override; - void captureMouse() override; - void releaseMouse() override; - void setMouseClipping( BOOL b ) override; - BOOL isClipboardTextAvailable() override; - BOOL pasteTextFromClipboard(LLWString &dst) override; - BOOL copyTextToClipboard(const LLWString & src) override; - void flashIcon(F32 seconds) override; - F32 getGamma() override; - BOOL setGamma(const F32 gamma) override; // Set the gamma - U32 getFSAASamples() override; - void setFSAASamples(const U32 fsaa_samples) override; - BOOL restoreGamma() override; // Restore original gamma table (before updating gamma) - ESwapMethod getSwapMethod() override { return mSwapMethod; } - void gatherInput() override; - void delayInputProcessing() override {}; - void swapBuffers() override; - - // handy coordinate space conversion routines - BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; - BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; - BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; - BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; - BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; - BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; - - LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; - F32 getNativeAspectRatio() override; - F32 getPixelAspectRatio() override; - void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - - // query VRAM usage + void show() override; + void hide() override; + void close() override; + BOOL getVisible() override; + BOOL getMinimized() override; + BOOL getMaximized() override; + BOOL maximize() override; + void minimize() override; + void restore() override; + BOOL getFullscreen(); + BOOL getPosition(LLCoordScreen *position) override; + BOOL getSize(LLCoordScreen *size) override; + BOOL getSize(LLCoordWindow *size) override; + BOOL setPosition(LLCoordScreen position) override; + BOOL setSizeImpl(LLCoordScreen size) override; + BOOL setSizeImpl(LLCoordWindow size) override; + BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override; + BOOL setCursorPosition(LLCoordWindow position) override; + BOOL getCursorPosition(LLCoordWindow *position) override; + void showCursor() override; + void hideCursor() override; + void showCursorFromMouseMove() override; + void hideCursorUntilMouseMove() override; + BOOL isCursorHidden() override; + void updateCursor() override; + ECursorType getCursor() const override; + void captureMouse() override; + void releaseMouse() override; + void setMouseClipping( BOOL b ) override; + BOOL isClipboardTextAvailable() override; + BOOL pasteTextFromClipboard(LLWString &dst) override; + BOOL copyTextToClipboard(const LLWString & src) override; + void flashIcon(F32 seconds) override; + F32 getGamma() override; + BOOL setGamma(const F32 gamma) override; // Set the gamma + U32 getFSAASamples() override; + void setFSAASamples(const U32 fsaa_samples) override; + BOOL restoreGamma() override; // Restore original gamma table (before updating gamma) + ESwapMethod getSwapMethod() override { return mSwapMethod; } + void gatherInput() override; + void delayInputProcessing() override {}; + void swapBuffers() override; + + // handy coordinate space conversion routines + BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; + BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; + BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; + BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; + + LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; + F32 getNativeAspectRatio() override; + F32 getPixelAspectRatio() override; + void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } + + // query VRAM usage /*virtual*/ U32 getAvailableVRAMMegabytes() override; - void beforeDialog() override; - void afterDialog() override; - - BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; - - void *getPlatformWindow() override; - void bringToFront() override {}; - - void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override; - void interruptLanguageTextInput() override; - void spawnWebBrowser(const std::string& escaped_url, bool async) override; - F32 getSystemUISize() override; - - static std::vector<std::string> getDisplaysResolutionList(); - - static std::vector<std::string> getDynamicFallbackFontList(); - - // Provide native key event data - LLSD getNativeKeyData() override; - - void* getWindow() { return mWindow; } - LLWindowCallbacks* getCallbacks() { return mCallbacks; } - LLPreeditor* getPreeditor() { return mPreeditor; } - - void updateMouseDeltas(float* deltas); - void getMouseDeltas(float* delta); - - void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); - + void beforeDialog() override; + void afterDialog() override; + + BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; + + void *getPlatformWindow() override; + void bringToFront() override {}; + + void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override; + void interruptLanguageTextInput() override; + void spawnWebBrowser(const std::string& escaped_url, bool async) override; + F32 getSystemUISize() override; + + void openFolder(const std::string &path) override; + + static std::vector<std::string> getDisplaysResolutionList(); + + static std::vector<std::string> getDynamicFallbackFontList(); + + // Provide native key event data + LLSD getNativeKeyData() override; + + void* getWindow() { return mWindow; } + LLWindowCallbacks* getCallbacks() { return mCallbacks; } + LLPreeditor* getPreeditor() { return mPreeditor; } + + void updateMouseDeltas(float* deltas); + void getMouseDeltas(float* delta); + + void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); + bool allowsLanguageInput() { return mLanguageTextInputAllowed; } //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread @@ -146,29 +148,29 @@ public: void toggleVSync(bool enable_vsync) override; protected: - LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, - U32 fsaa_samples); - ~LLWindowMacOSX(); - - void initCursors(); - BOOL isValid() override; - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + LLWindowMacOSX(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, + BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, + U32 fsaa_samples); + ~LLWindowMacOSX(); + void initCursors(); + BOOL isValid() override; + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); + // Changes display resolution. Returns true if successful + BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - // Restore the display resolution to its value before we ran the app. - BOOL resetDisplayResolution(); + // Go back to last fullscreen display resolution. + BOOL setFullscreenResolution(); - BOOL shouldPostQuit() { return mPostQuit; } + // Restore the display resolution to its value before we ran the app. + BOOL resetDisplayResolution(); + BOOL shouldPostQuit() { return mPostQuit; } + //Satisfy MAINT-3135 and MAINT-3288 with a flag. /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } @@ -176,81 +178,81 @@ private: void restoreGLContext(); protected: - // - // Platform specific methods - // - - // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync); - void destroyContext(); - void setupFailure(const std::string& text, const std::string& caption, U32 type); - void adjustCursorDecouple(bool warpingMouse = false); - static MASK modifiersToMask(S16 modifiers); - + // + // Platform specific methods + // + + // create or re-create the GL context/window. Called from the constructor and switchContext(). + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync); + void destroyContext(); + void setupFailure(const std::string& text, const std::string& caption, U32 type); + void adjustCursorDecouple(bool warpingMouse = false); + static MASK modifiersToMask(S16 modifiers); + #if LL_OS_DRAGDROP_ENABLED - - //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - - + + //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + + #endif // LL_OS_DRAGDROP_ENABLED - - // - // Platform specific variables - // - - // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. - NSWindowRef mWindow; - GLViewRef mGLView; - CGLContextObj mContext; - CGLPixelFormatObj mPixelFormat; - CGDirectDisplayID mDisplay; - - LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - std::string mWindowTitle; - double mOriginalAspectRatio; - BOOL mSimulatedRightClick; - U32 mLastModifiers; - BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. - // Used to allow event processing when putting up dialogs in fullscreen mode. - BOOL mCursorDecoupled; - S32 mCursorLastEventDeltaX; - S32 mCursorLastEventDeltaY; - BOOL mCursorIgnoreNextDelta; - BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. - LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - BOOL mMaximized; - BOOL mMinimized; - U32 mFSAASamples; - BOOL mForceRebuild; - - S32 mDragOverrideCursor; - - // Input method management through Text Service Manager. - BOOL mLanguageTextInputAllowed; - LLPreeditor* mPreeditor; - + + // + // Platform specific variables + // + + // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. + NSWindowRef mWindow; + GLViewRef mGLView; + CGLContextObj mContext; + CGLPixelFormatObj mPixelFormat; + CGDirectDisplayID mDisplay; + + LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + std::string mWindowTitle; + double mOriginalAspectRatio; + BOOL mSimulatedRightClick; + U32 mLastModifiers; + BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. + // Used to allow event processing when putting up dialogs in fullscreen mode. + BOOL mCursorDecoupled; + S32 mCursorLastEventDeltaX; + S32 mCursorLastEventDeltaY; + BOOL mCursorIgnoreNextDelta; + BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + LLCoordScreen mNeedsResizeSize; + F32 mOverrideAspectRatio; + BOOL mMaximized; + BOOL mMinimized; + U32 mFSAASamples; + BOOL mForceRebuild; + + S32 mDragOverrideCursor; + + // Input method management through Text Service Manager. + BOOL mLanguageTextInputAllowed; + LLPreeditor* mPreeditor; + public: - static BOOL sUseMultGL; - - friend class LLWindowManager; + static BOOL sUseMultGL; + friend class LLWindowManager; + }; class LLSplashScreenMacOSX : public LLSplashScreen { public: - LLSplashScreenMacOSX(); - virtual ~LLSplashScreenMacOSX(); + LLSplashScreenMacOSX(); + virtual ~LLSplashScreenMacOSX(); - void showImpl(); - void updateImpl(const std::string& mesg); - void hideImpl(); + void showImpl(); + void updateImpl(const std::string& mesg); + void hideImpl(); private: - WindowRef mWindow; + WindowRef mWindow; }; S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 8670298f46..dd776e5a0f 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llwindowwin32.cpp * @brief Platform-dependent implementation of llwindow * * $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$ */ @@ -53,7 +53,7 @@ #include <commdlg.h> #include <WinUser.h> #include <mapi.h> -#include <process.h> // for _spawn +#include <process.h> // for _spawn #include <shellapi.h> #include <fstream> #include <Imm.h> @@ -75,10 +75,10 @@ #pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems #pragma comment(lib, "dinput8") -const S32 MAX_MESSAGE_PER_UPDATE = 20; -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; -const F32 ICON_FLASH_TIME = 0.5f; +const S32 MAX_MESSAGE_PER_UPDATE = 20; +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; +const F32 ICON_FLASH_TIME = 0.5f; #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 @@ -114,16 +114,16 @@ LLW32MsgCallback gAsyncMsgCallback = NULL; #ifndef DPI_ENUMS_DECLARED typedef enum PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; typedef enum MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; #endif @@ -131,14 +131,14 @@ typedef enum MONITOR_DPI_TYPE { typedef HRESULT(STDAPICALLTYPE *SetProcessDpiAwarenessType)(_In_ PROCESS_DPI_AWARENESS value); typedef HRESULT(STDAPICALLTYPE *GetProcessDpiAwarenessType)( - _In_ HANDLE hprocess, - _Out_ PROCESS_DPI_AWARENESS *value); + _In_ HANDLE hprocess, + _Out_ PROCESS_DPI_AWARENESS *value); typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( - _In_ HMONITOR hmonitor, - _In_ MONITOR_DPI_TYPE dpiType, - _Out_ UINT *dpiX, - _Out_ UINT *dpiY); + _In_ HMONITOR hmonitor, + _In_ MONITOR_DPI_TYPE dpiType, + _Out_ UINT *dpiX, + _Out_ UINT *dpiY); // // LLWindowWin32 @@ -146,19 +146,19 @@ typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( void show_window_creation_error(const std::string& title) { - LL_WARNS("Window") << title << LL_ENDL; + LL_WARNS("Window") << title << LL_ENDL; } HGLRC SafeCreateContext(HDC &hdc) { - __try - { - return wglCreateContext(hdc); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - return NULL; - } + __try + { + return wglCreateContext(hdc); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return NULL; + } } GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) @@ -180,11 +180,11 @@ GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) //static BOOL LLWindowWin32::sIsClassRegistered = FALSE; -BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; -BOOL LLWindowWin32::sWinIMEOpened = FALSE; -HKL LLWindowWin32::sWinInputLocale = 0; -DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; -DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; +BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; +BOOL LLWindowWin32::sWinIMEOpened = FALSE; +HKL LLWindowWin32::sWinInputLocale = 0; +DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; +DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); // The following class LLWinImm delegates Windows IMM APIs. @@ -196,110 +196,110 @@ LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); class LLWinImm { public: - static bool isAvailable() { return true; } + static bool isAvailable() { return true; } public: - // Wrappers for IMM API. - static BOOL isIME(HKL hkl); - static HIMC getContext(HWND hwnd); - static BOOL releaseContext(HWND hwnd, HIMC himc); - static BOOL getOpenStatus(HIMC himc); - static BOOL setOpenStatus(HIMC himc, BOOL status); - static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); - static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); - static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); - static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); - static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); - static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); - static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); + // Wrappers for IMM API. + static BOOL isIME(HKL hkl); + static HIMC getContext(HWND hwnd); + static BOOL releaseContext(HWND hwnd, HIMC himc); + static BOOL getOpenStatus(HIMC himc); + static BOOL setOpenStatus(HIMC himc, BOOL status); + static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); + static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); + static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); + static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); + static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); + static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); + static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); }; -// static -BOOL LLWinImm::isIME(HKL hkl) -{ - return ImmIsIME(hkl); +// static +BOOL LLWinImm::isIME(HKL hkl) +{ + return ImmIsIME(hkl); } -// static -HIMC LLWinImm::getContext(HWND hwnd) +// static +HIMC LLWinImm::getContext(HWND hwnd) { - return ImmGetContext(hwnd); + return ImmGetContext(hwnd); } -//static -BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) -{ - return ImmReleaseContext(hwnd, himc); +//static +BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) +{ + return ImmReleaseContext(hwnd, himc); } -// static -BOOL LLWinImm::getOpenStatus(HIMC himc) -{ - return ImmGetOpenStatus(himc); +// static +BOOL LLWinImm::getOpenStatus(HIMC himc) +{ + return ImmGetOpenStatus(himc); } -// static -BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) -{ - return ImmSetOpenStatus(himc, status); +// static +BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) +{ + return ImmSetOpenStatus(himc, status); } -// static -BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) -{ - return ImmGetConversionStatus(himc, conversion, sentence); +// static +BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) +{ + return ImmGetConversionStatus(himc, conversion, sentence); } -// static -BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) -{ - return ImmSetConversionStatus(himc, conversion, sentence); +// static +BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) +{ + return ImmSetConversionStatus(himc, conversion, sentence); } -// static -BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - return ImmGetCompositionWindow(himc, form); +// static +BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + return ImmGetCompositionWindow(himc, form); } -// static -BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - return ImmSetCompositionWindow(himc, form); +// static +BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + return ImmSetCompositionWindow(himc, form); } -// static -LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) -{ - return ImmGetCompositionString(himc, index, data, length); +// static +LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) +{ + return ImmGetCompositionString(himc, index, data, length); } -// static -BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) -{ - return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); +// static +BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) +{ + return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); } -// static -BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) -{ - return ImmSetCompositionFont(himc, pFont); +// static +BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) +{ + return ImmSetCompositionFont(himc, pFont); } -// static -BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) -{ - return ImmSetCandidateWindow(himc, form); +// static +BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) +{ + return ImmSetCandidateWindow(himc, form); } -// static -BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) -{ - return ImmNotifyIME(himc, action, index, value); +// static +BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) +{ + return ImmNotifyIME(himc, action, index, value); } @@ -308,31 +308,31 @@ class LLMonitorInfo { public: - std::vector<std::string> getResolutionsList() { return mResList; } + std::vector<std::string> getResolutionsList() { return mResList; } - LLMonitorInfo() - { - EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); - } + LLMonitorInfo() + { + EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); + } private: - static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) - { - int monitor_width = lprcMonitor->right - lprcMonitor->left; - int monitor_height = lprcMonitor->bottom - lprcMonitor->top; - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); + static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) + { + int monitor_width = lprcMonitor->right - lprcMonitor->left; + int monitor_height = lprcMonitor->bottom - lprcMonitor->top; + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); - LLMonitorInfo* pThis = reinterpret_cast<LLMonitorInfo*>(pData); - pThis->mResList.push_back(res); + LLMonitorInfo* pThis = reinterpret_cast<LLMonitorInfo*>(pData); + pThis->mResList.push_back(res); - return TRUE; - } + return TRUE; + } - std::vector<std::string> mResList; + std::vector<std::string> mResList; }; static LLMonitorInfo sMonitorInfo; @@ -363,7 +363,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // initialzie DXGI adapter (for querying available VRAM) void initDX(); - + // initialize D3D (if DXGI cannot be used) void initD3D(); @@ -437,28 +437,28 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, - U32 fsaa_samples, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + BOOL fullscreen, BOOL clearBg, + BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, + U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version) - : - LLWindow(callbacks, fullscreen, flags), - mMaxGLVersion(max_gl_version), + : + LLWindow(callbacks, fullscreen, flags), + mMaxGLVersion(max_gl_version), mMaxCores(max_cores) { sMainThreadId = LLThread::currentID(); mWindowThread = new LLWindowWin32Thread(); mWindowThread->mMaxVRAM = max_vram; - //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways - LoadLibrary(L"opengl32.dll"); - - + //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways + LoadLibrary(L"opengl32.dll"); + + if (mMaxCores != 0) { HANDLE hProcess = GetCurrentProcess(); @@ -530,76 +530,76 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, #endif - mFSAASamples = fsaa_samples; - mIconResource = gIconResource; - mOverrideAspectRatio = 0.f; - mNativeAspectRatio = 0.f; - mInputProcessingPaused = FALSE; - mPreeditor = NULL; - mKeyCharCode = 0; - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mhDC = NULL; - mhRC = NULL; - memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); - memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); - mCustomGammaSet = FALSE; - mWindowHandle = NULL; + mFSAASamples = fsaa_samples; + mIconResource = gIconResource; + mOverrideAspectRatio = 0.f; + mNativeAspectRatio = 0.f; + mInputProcessingPaused = FALSE; + mPreeditor = NULL; + mKeyCharCode = 0; + mKeyScanCode = 0; + mKeyVirtualKey = 0; + mhDC = NULL; + mhRC = NULL; + memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); + memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); + mCustomGammaSet = FALSE; + mWindowHandle = NULL; mRect = {0, 0, 0, 0}; mClientRect = {0, 0, 0, 0}; - - if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) - { - mMouseVanish = TRUE; - } - - // Initialize the keyboard - gKeyboard = new LLKeyboardWin32(); - gKeyboard->setCallbacks(callbacks); - - // Initialize the Drag and Drop functionality - mDragDrop = new LLDragDropWin32; - - // Initialize (boot strap) the Language text input management, - // based on the system's (user's) default settings. - allowLanguageTextInput(mPreeditor, FALSE); - - WNDCLASS wc; - RECT window_rect; - - // Set the window title - if (title.empty()) - { - mWindowTitle = new WCHAR[50]; - wsprintf(mWindowTitle, L"OpenGL Window"); - } - else - { - mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowTitle, title.c_str(), 255); - mWindowTitle[255] = 0; - } - - // Set the window class name - if (name.empty()) - { - mWindowClassName = new WCHAR[50]; - wsprintf(mWindowClassName, L"OpenGL Window"); - } - else - { - mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowClassName, name.c_str(), 255); - mWindowClassName[255] = 0; - } - - - // We're not clipping yet - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - - // Make an instance of our window then define the window class - mhInstance = GetModuleHandle(NULL); + + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) + { + mMouseVanish = TRUE; + } + + // Initialize the keyboard + gKeyboard = new LLKeyboardWin32(); + gKeyboard->setCallbacks(callbacks); + + // Initialize the Drag and Drop functionality + mDragDrop = new LLDragDropWin32; + + // Initialize (boot strap) the Language text input management, + // based on the system's (user's) default settings. + allowLanguageTextInput(mPreeditor, FALSE); + + WNDCLASS wc; + RECT window_rect; + + // Set the window title + if (title.empty()) + { + mWindowTitle = new WCHAR[50]; + wsprintf(mWindowTitle, L"OpenGL Window"); + } + else + { + mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowTitle, title.c_str(), 255); + mWindowTitle[255] = 0; + } + + // Set the window class name + if (name.empty()) + { + mWindowClassName = new WCHAR[50]; + wsprintf(mWindowClassName, L"OpenGL Window"); + } + else + { + mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowClassName, name.c_str(), 255); + mWindowClassName[255] = 0; + } + + + // We're not clipping yet + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + + // Make an instance of our window then define the window class + mhInstance = GetModuleHandle(NULL); // Init Direct Input - needed for joystick / Spacemouse @@ -616,199 +616,199 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, gDirectInput8 = di8_interface; } - mSwapMethod = SWAP_METHOD_UNDEFINED; - - // No WPARAM yet. - mLastSizeWParam = 0; - - // Windows GDI rects don't include rightmost pixel - window_rect.left = (long) 0; - window_rect.right = (long) width; - window_rect.top = (long) 0; - window_rect.bottom = (long) height; - - // Grab screen size to sanitize the window - S32 window_border_y = GetSystemMetrics(SM_CYBORDER); - S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); - S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - if (x < virtual_screen_x) x = virtual_screen_x; - if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; - - if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; - if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; - - if (!sIsClassRegistered) - { - // Force redraw when resized and create a private device context - - // Makes double click messages. - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; - - // Set message handler function - wc.lpfnWndProc = (WNDPROC) mainWindowProc; - - // unused - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - - wc.hInstance = mhInstance; - wc.hIcon = LoadIcon(mhInstance, mIconResource); - - // We will set the cursor ourselves - wc.hCursor = NULL; - - // background color is not used - if (clearBg) - { - wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - } - else - { - wc.hbrBackground = (HBRUSH) NULL; - } - - // we don't use windows menus - wc.lpszMenuName = NULL; - - wc.lpszClassName = mWindowClassName; - - if (!RegisterClass(&wc)) - { - OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), - mCallbacks->translateString("MBError"), OSMB_OK); - return; - } - sIsClassRegistered = TRUE; - } - - //----------------------------------------------------------------------- - // Get the current refresh rate - //----------------------------------------------------------------------- - - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); - } - else - { - current_refresh = 60; - } + mSwapMethod = SWAP_METHOD_UNDEFINED; + + // No WPARAM yet. + mLastSizeWParam = 0; + + // Windows GDI rects don't include rightmost pixel + window_rect.left = (long) 0; + window_rect.right = (long) width; + window_rect.top = (long) 0; + window_rect.bottom = (long) height; + + // Grab screen size to sanitize the window + S32 window_border_y = GetSystemMetrics(SM_CYBORDER); + S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); + S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); + S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + if (x < virtual_screen_x) x = virtual_screen_x; + if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; + + if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; + if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; + + if (!sIsClassRegistered) + { + // Force redraw when resized and create a private device context + + // Makes double click messages. + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + + // Set message handler function + wc.lpfnWndProc = (WNDPROC) mainWindowProc; + + // unused + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + wc.hInstance = mhInstance; + wc.hIcon = LoadIcon(mhInstance, mIconResource); + + // We will set the cursor ourselves + wc.hCursor = NULL; + + // background color is not used + if (clearBg) + { + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + } + else + { + wc.hbrBackground = (HBRUSH) NULL; + } + + // we don't use windows menus + wc.lpszMenuName = NULL; + + wc.lpszClassName = mWindowClassName; + + if (!RegisterClass(&wc)) + { + OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), + mCallbacks->translateString("MBError"), OSMB_OK); + return; + } + sIsClassRegistered = TRUE; + } + + //----------------------------------------------------------------------- + // Get the current refresh rate + //----------------------------------------------------------------------- + + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + DWORD current_refresh; + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); + } + else + { + current_refresh = 60; + } mRefreshRate = current_refresh; - //----------------------------------------------------------------------- - // Drop resolution and go fullscreen - // use a display mode with our desired size and depth, with a refresh - // rate as close at possible to the users' default - //----------------------------------------------------------------------- - if (mFullscreen) - { - BOOL success = FALSE; - DWORD closest_refresh = 0; - - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = TRUE; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } - - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - //success = FALSE; - - if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - success = FALSE; - } - else - { - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; - window_rect.right=width=dev_mode.dmPelsWidth; - window_rect.bottom=height=dev_mode.dmPelsHeight; - success = TRUE; - } - else - { - LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; - success = FALSE; - } - } - } - - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } - - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - // If it failed, we don't want to run fullscreen - if (success) - { - mFullscreen = TRUE; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; - - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; - } - else - { - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - std::map<std::string,std::string> args; - args["[WIDTH]"] = llformat("%d", width); - args["[HEIGHT]"] = llformat ("%d", height); - OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), - mCallbacks->translateString("MBError"), OSMB_OK); - } - } - - // TODO: add this after resolving _WIN32_WINNT issue - // if (!fullscreen) - // { - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = mWindowHandle; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - // } + //----------------------------------------------------------------------- + // Drop resolution and go fullscreen + // use a display mode with our desired size and depth, with a refresh + // rate as close at possible to the users' default + //----------------------------------------------------------------------- + if (mFullscreen) + { + BOOL success = FALSE; + DWORD closest_refresh = 0; + + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = TRUE; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } + + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + //success = FALSE; + + if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + success = FALSE; + } + else + { + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; + window_rect.right=width=dev_mode.dmPelsWidth; + window_rect.bottom=height=dev_mode.dmPelsHeight; + success = TRUE; + } + else + { + LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; + success = FALSE; + } + } + } + + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } + + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + + // If it failed, we don't want to run fullscreen + if (success) + { + mFullscreen = TRUE; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + } + else + { + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + std::map<std::string,std::string> args; + args["[WIDTH]"] = llformat("%d", width); + args["[HEIGHT]"] = llformat ("%d", height); + OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), + mCallbacks->translateString("MBError"), OSMB_OK); + } + } + + // TODO: add this after resolving _WIN32_WINNT issue + // if (!fullscreen) + // { + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = mWindowHandle; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + // } // SL-12971 dual GPU display DISPLAY_DEVICEA display_device; @@ -842,20 +842,20 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, LL_INFOS("Window") << "Total Display Devices: " << display_index << LL_ENDL; - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - LLCoordScreen windowPos(x,y); - LLCoordScreen windowSize(window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top); - if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) - { - return; - } - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + LLCoordScreen windowPos(x,y); + LLCoordScreen windowSize(window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top); + if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) + { + return; + } + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); mRawMouse.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC mRawMouse.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE @@ -864,56 +864,56 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse)); - // Initialize (boot strap) the Language text input management, - // based on the system's (or user's) default settings. - allowLanguageTextInput(NULL, FALSE); + // Initialize (boot strap) the Language text input management, + // based on the system's (or user's) default settings. + allowLanguageTextInput(NULL, FALSE); } LLWindowWin32::~LLWindowWin32() { - delete mDragDrop; + delete mDragDrop; - delete [] mWindowTitle; - mWindowTitle = NULL; + delete [] mWindowTitle; + mWindowTitle = NULL; - delete [] mSupportedResolutions; - mSupportedResolutions = NULL; - - delete [] mWindowClassName; - mWindowClassName = NULL; + delete [] mSupportedResolutions; + mSupportedResolutions = NULL; + delete [] mWindowClassName; + mWindowClassName = NULL; + delete mWindowThread; } void LLWindowWin32::show() { LL_DEBUGS("Window") << "Setting window to show" << LL_ENDL; - ShowWindow(mWindowHandle, SW_SHOW); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); + ShowWindow(mWindowHandle, SW_SHOW); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); } void LLWindowWin32::hide() { - setMouseClipping(FALSE); - ShowWindow(mWindowHandle, SW_HIDE); + setMouseClipping(FALSE); + ShowWindow(mWindowHandle, SW_HIDE); } //virtual void LLWindowWin32::minimize() { - setMouseClipping(FALSE); - showCursor(); - ShowWindow(mWindowHandle, SW_MINIMIZE); + setMouseClipping(FALSE); + showCursor(); + ShowWindow(mWindowHandle, SW_MINIMIZE); } //virtual void LLWindowWin32::restore() { - ShowWindow(mWindowHandle, SW_RESTORE); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); + ShowWindow(mWindowHandle, SW_RESTORE); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); } // See SL-12170 @@ -942,88 +942,88 @@ bool destroy_window_handler(HWND hWnd) // Usually called from LLWindowManager::destroyWindow() void LLWindowWin32::close() { - LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; - // Is window is already closed? - if (!mWindowHandle) - { - return; - } - - mDragDrop->reset(); - - - // Go back to screen mode written in the registry. - if (mFullscreen) - { - resetDisplayResolution(); - } - - // Make sure cursor is visible and we haven't mangled the clipping state. - showCursor(); - setMouseClipping(FALSE); - if (gKeyboard) - { - gKeyboard->resetKeys(); - } - - // Clean up remaining GL state - if (gGLManager.mInited) - { - LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL; - gGLManager.shutdownGL(); - } - - LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; - } - - // Restore gamma to the system values. - restoreGamma(); - - LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; + LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; + // Is window is already closed? + if (!mWindowHandle) + { + return; + } + + mDragDrop->reset(); + + + // Go back to screen mode written in the registry. + if (mFullscreen) + { + resetDisplayResolution(); + } + + // Make sure cursor is visible and we haven't mangled the clipping state. + showCursor(); + setMouseClipping(FALSE); + if (gKeyboard) + { + gKeyboard->resetKeys(); + } + + // Clean up remaining GL state + if (gGLManager.mInited) + { + LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL; + gGLManager.shutdownGL(); + } + + LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } + + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } + + mhRC = NULL; + } + + // Restore gamma to the system values. + restoreGamma(); + + LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; mhDC = NULL; mWindowHandle = NULL; - + mWindowThread->wakeAndDestroy(); } BOOL LLWindowWin32::isValid() { - return (mWindowHandle != NULL); + return (mWindowHandle != NULL); } BOOL LLWindowWin32::getVisible() { - return (mWindowHandle && IsWindowVisible(mWindowHandle)); + return (mWindowHandle && IsWindowVisible(mWindowHandle)); } BOOL LLWindowWin32::getMinimized() { - return (mWindowHandle && IsIconic(mWindowHandle)); + return (mWindowHandle && IsIconic(mWindowHandle)); } BOOL LLWindowWin32::getMaximized() { - return (mWindowHandle && IsZoomed(mWindowHandle)); + return (mWindowHandle && IsZoomed(mWindowHandle)); } BOOL LLWindowWin32::maximize() { - BOOL success = FALSE; - if (!mWindowHandle) return success; + BOOL success = FALSE; + if (!mWindowHandle) return success; mWindowThread->post([=] { @@ -1042,52 +1042,52 @@ BOOL LLWindowWin32::maximize() BOOL LLWindowWin32::getFullscreen() { - return mFullscreen; + return mFullscreen; } BOOL LLWindowWin32::getPosition(LLCoordScreen *position) { position->mX = mRect.left; - position->mY = mRect.top; - return TRUE; + position->mY = mRect.top; + return TRUE; } BOOL LLWindowWin32::getSize(LLCoordScreen *size) { - size->mX = mRect.right - mRect.left; - size->mY = mRect.bottom - mRect.top; - return TRUE; + size->mX = mRect.right - mRect.left; + size->mY = mRect.bottom - mRect.top; + return TRUE; } BOOL LLWindowWin32::getSize(LLCoordWindow *size) { - size->mX = mClientRect.right - mClientRect.left; - size->mY = mClientRect.bottom - mClientRect.top; - return TRUE; + size->mX = mClientRect.right - mClientRect.left; + size->mY = mClientRect.bottom - mClientRect.top; + return TRUE; } BOOL LLWindowWin32::setPosition(const LLCoordScreen position) { - LLCoordScreen size; + LLCoordScreen size; - if (!mWindowHandle) - { - return FALSE; - } - getSize(&size); - moveWindow(position, size); - return TRUE; + if (!mWindowHandle) + { + return FALSE; + } + getSize(&size); + moveWindow(position, size); + return TRUE; } BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) { - LLCoordScreen position; + LLCoordScreen position; - getPosition(&position); - if (!mWindowHandle) - { - return FALSE; - } + getPosition(&position); + if (!mWindowHandle) + { + return FALSE; + } mWindowThread->post([=]() { @@ -1101,33 +1101,33 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) } }); - moveWindow(position, size); - return TRUE; + moveWindow(position, size); + return TRUE; } BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) { - RECT window_rect = {0, 0, size.mX, size.mY }; - DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dw_style = WS_OVERLAPPEDWINDOW; + RECT window_rect = {0, 0, size.mX, size.mY }; + DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dw_style = WS_OVERLAPPEDWINDOW; AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); - return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); + return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); } // changing fullscreen resolution BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BOOL enable_vsync, const LLCoordScreen* const posp) { //called from main thread - GLuint pixel_format; + GLuint pixel_format; DEVMODE dev_mode; ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - DWORD dw_ex_style; - DWORD dw_style; - RECT window_rect = { 0, 0, 0, 0 }; + DWORD current_refresh; + DWORD dw_ex_style; + DWORD dw_style; + RECT window_rect = { 0, 0, 0, 0 }; S32 width = size.mX; S32 height = size.mY; BOOL auto_show = FALSE; @@ -1203,7 +1203,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); } - // Keep a copy of the actual current device mode in case we minimize + // Keep a copy of the actual current device mode in case we minimize // and change the screen resolution. JC EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); @@ -1222,7 +1222,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO << LL_ENDL; window_rect.left = (long)0; - window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel + window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel window_rect.top = (long)0; window_rect.bottom = (long)height; dw_ex_style = WS_EX_APPWINDOW; @@ -1249,7 +1249,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO { mFullscreen = FALSE; window_rect.left = (long)(posp ? posp->mX : 0); - window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel + window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel window_rect.top = (long)(posp ? posp->mY : 0); window_rect.bottom = (long)height + window_rect.top; // Window with an edge @@ -1270,318 +1270,318 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO << " Fullscreen: " << mFullscreen << LL_ENDL; - recreateWindow(window_rect, dw_ex_style, dw_style); - - if (mWindowHandle) - { - LL_INFOS("Window") << "window is created." << LL_ENDL ; - } - else - { - LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; - } - - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - static PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, - BITS_PER_PIXEL, - 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused - 8, // alpha bits - 0, // alpha shift - 0, // accum bits - 0, 0, 0, 0, // accum RGBA - 24, // depth bits - 8, // stencil bits, avi added for stencil test - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - if (!mhDC) - { - close(); - OSMessageBox(mCallbacks->translateString("MBDevContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; + recreateWindow(window_rect, dw_ex_style, dw_style); + + if (mWindowHandle) + { + LL_INFOS("Window") << "window is created." << LL_ENDL ; + } + else + { + LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; + } + + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + static PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + BITS_PER_PIXEL, + 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused + 8, // alpha bits + 0, // alpha shift + 0, // accum bits + 0, 0, 0, 0, // accum RGBA + 24, // depth bits + 8, // stencil bits, avi added for stencil test + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + if (!mhDC) + { + close(); + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; try { // Looks like ChoosePixelFormat can crash in case of faulty driver if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd))) - { + { LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL; OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); + close(); return FALSE; } } catch (...) { LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); - OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), - mCallbacks->translateString("MBError"), OSMB_OK); + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } + return FALSE; + } - LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; + LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), - mCallbacks->translateString("MBError"), OSMB_OK); + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), + mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } - - // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash - LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; - LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; - LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; - LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; - LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; - LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; - LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; - LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; - LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash + LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; + LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; + LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; + LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; + LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; + LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; + LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; + LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; + LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } + return FALSE; + } - if (!(mhRC = SafeCreateContext(mhDC))) - { - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); + if (!(mhRC = SafeCreateContext(mhDC))) + { + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), - mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + if (!wglMakeCurrent(mhDC, mhRC)) + { + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), + mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } - - LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; - - gGLManager.initWGL(); - - if (wglChoosePixelFormatARB) - { - // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we - // can get exactly what we want. - GLint attrib_list[256]; - S32 cur_attrib = 0; - - attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - //attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) - //attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; - attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; - - attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; - attrib_list[cur_attrib++] = 0; - - U32 end_attrib = 0; - if (mFSAASamples > 0) - { - end_attrib = cur_attrib; - attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; - attrib_list[cur_attrib++] = mFSAASamples; - } - - // End the list - attrib_list[cur_attrib++] = 0; - - GLint pixel_formats[256]; - U32 num_formats = 0; - - // First we try and get a 32 bit depth pixel format - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - - while(!result && mFSAASamples > 0) - { - LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; - - mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing - if(mFSAASamples < 2) - { - mFSAASamples = 0 ; - } - - if (mFSAASamples > 0) - { - attrib_list[end_attrib + 3] = mFSAASamples; - } - else - { - cur_attrib = end_attrib ; - end_attrib = 0 ; - attrib_list[cur_attrib++] = 0 ; //end - } - result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - - if(result) - { - LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; - } - } - - if (!result) - { - LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; - - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); - return FALSE; - } - - if (!num_formats) - { - if (end_attrib > 0) - { - LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; - attrib_list[end_attrib] = 0; - - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); - return FALSE; - } - } - - if (!num_formats) - { - LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; - // Try 24-bit format - attrib_list[1] = 24; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); - return FALSE; - } - - if (!num_formats) - { - LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; - attrib_list[1] = 16; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result || !num_formats) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); - return FALSE; - } - } - } - - LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; - } - - LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; - - S32 swap_method = 0; - S32 cur_format = 0; -const S32 max_format = (S32)num_formats - 1; - GLint swap_query = WGL_SWAP_METHOD_ARB; - - // SL-14705 Fix name tags showing in front of objects with AMD GPUs. - // On AMD hardware we need to iterate from the first pixel format to the end. - // Spec: - // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt - while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) - { - if (swap_method == WGL_SWAP_UNDEFINED_ARB) - { - break; - } - else if (cur_format >= max_format) - { - cur_format = 0; - break; - } - - ++cur_format; - } - - pixel_format = pixel_formats[cur_format]; - - if (mhDC != 0) // Does The Window Have A Device Context? - { - wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero - if (mhRC != 0) // Does The Window Have A Rendering Context? - { - wglDeleteContext (mhRC); // Release The Rendering Context - mhRC = 0; // Zero The Rendering Context - } - } + return FALSE; + } + + LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; + + gGLManager.initWGL(); + + if (wglChoosePixelFormatARB) + { + // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we + // can get exactly what we want. + GLint attrib_list[256]; + S32 cur_attrib = 0; + + attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; + attrib_list[cur_attrib++] = 24; + + //attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) + //attrib_list[cur_attrib++] = 8; + + attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; + attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; + + attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; + attrib_list[cur_attrib++] = 24; + + attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; + attrib_list[cur_attrib++] = 0; + + U32 end_attrib = 0; + if (mFSAASamples > 0) + { + end_attrib = cur_attrib; + attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; + attrib_list[cur_attrib++] = mFSAASamples; + } + + // End the list + attrib_list[cur_attrib++] = 0; + + GLint pixel_formats[256]; + U32 num_formats = 0; + + // First we try and get a 32 bit depth pixel format + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + + while(!result && mFSAASamples > 0) + { + LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; + + mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing + if(mFSAASamples < 2) + { + mFSAASamples = 0 ; + } + + if (mFSAASamples > 0) + { + attrib_list[end_attrib + 3] = mFSAASamples; + } + else + { + cur_attrib = end_attrib ; + end_attrib = 0 ; + attrib_list[cur_attrib++] = 0 ; //end + } + result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + + if(result) + { + LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; + } + } + + if (!result) + { + LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; + + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); + return FALSE; + } + + if (!num_formats) + { + if (end_attrib > 0) + { + LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; + attrib_list[end_attrib] = 0; + + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); + return FALSE; + } + } + + if (!num_formats) + { + LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; + // Try 24-bit format + attrib_list[1] = 24; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); + return FALSE; + } + + if (!num_formats) + { + LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; + attrib_list[1] = 16; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result || !num_formats) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); + return FALSE; + } + } + } + + LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; + } + + LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; + + S32 swap_method = 0; + S32 cur_format = 0; +const S32 max_format = (S32)num_formats - 1; + GLint swap_query = WGL_SWAP_METHOD_ARB; + + // SL-14705 Fix name tags showing in front of objects with AMD GPUs. + // On AMD hardware we need to iterate from the first pixel format to the end. + // Spec: + // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt + while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) + { + if (swap_method == WGL_SWAP_UNDEFINED_ARB) + { + break; + } + else if (cur_format >= max_format) + { + cur_format = 0; + break; + } + + ++cur_format; + } + + pixel_format = pixel_formats[cur_format]; + + if (mhDC != 0) // Does The Window Have A Device Context? + { + wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero + if (mhRC != 0) // Does The Window Have A Rendering Context? + { + wglDeleteContext (mhRC); // Release The Rendering Context + mhRC = 0; // Zero The Rendering Context + } + } // will release and recreate mhDC, mWindowHandle - recreateWindow(window_rect, dw_ex_style, dw_style); - + recreateWindow(window_rect, dw_ex_style, dw_style); + RECT rect; RECT client_rect; //initialize immediately on main thread @@ -1592,112 +1592,112 @@ const S32 max_format = (S32)num_formats - 1; mClientRect = client_rect; }; - if (mWindowHandle) - { - LL_INFOS("Window") << "recreate window done." << LL_ENDL ; - } - else - { - // Note: if value is NULL GetDC retrieves the DC for the entire screen. - LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; - } - - if (!mhDC) - { - OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) - { - switch (swap_method) - { - case WGL_SWAP_EXCHANGE_ARB: - mSwapMethod = SWAP_METHOD_EXCHANGE; - LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; - break; - case WGL_SWAP_COPY_ARB: - mSwapMethod = SWAP_METHOD_COPY; - LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; - break; - case WGL_SWAP_UNDEFINED_ARB: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; - break; - default: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; - break; - } - } - } - else - { - LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) - << " Alpha Bits " << S32(pfd.cAlphaBits) - << " Depth Bits " << S32(pfd.cDepthBits) - << LL_ENDL; - - mhRC = 0; - if (wglCreateContextAttribsARB) - { //attempt to create a specific versioned context + if (mWindowHandle) + { + LL_INFOS("Window") << "recreate window done." << LL_ENDL ; + } + else + { + // Note: if value is NULL GetDC retrieves the DC for the entire screen. + LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; + } + + if (!mhDC) + { + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) + { + switch (swap_method) + { + case WGL_SWAP_EXCHANGE_ARB: + mSwapMethod = SWAP_METHOD_EXCHANGE; + LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; + break; + case WGL_SWAP_COPY_ARB: + mSwapMethod = SWAP_METHOD_COPY; + LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; + break; + case WGL_SWAP_UNDEFINED_ARB: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; + break; + default: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; + break; + } + } + } + else + { + LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; + } + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) + << " Alpha Bits " << S32(pfd.cAlphaBits) + << " Depth Bits " << S32(pfd.cDepthBits) + << LL_ENDL; + + mhRC = 0; + if (wglCreateContextAttribsARB) + { //attempt to create a specific versioned context mhRC = (HGLRC) createSharedContext(); if (!mhRC) { return FALSE; } - } + } - if (!wglMakeCurrent(mhDC, mhRC)) - { - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); + if (!wglMakeCurrent(mhDC, mhRC)) + { + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } + return FALSE; + } - if (!gGLManager.initGL()) - { - OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); + if (!gGLManager.initGL()) + { + OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } - - // Disable vertical sync for swap + return FALSE; + } + + // Disable vertical sync for swap toggleVSync(enable_vsync); - SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); + SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); - // register this window as handling drag/drop events from the OS - DragAcceptFiles( mWindowHandle, TRUE ); + // register this window as handling drag/drop events from the OS + DragAcceptFiles( mWindowHandle, TRUE ); - mDragDrop->init( mWindowHandle ); + mDragDrop->init( mWindowHandle ); + + //register joystick timer callback + SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer - //register joystick timer callback - SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer - - // ok to post quit messages now - mPostQuit = TRUE; + // ok to post quit messages now + mPostQuit = TRUE; // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 @@ -1706,17 +1706,17 @@ const S32 max_format = (S32)num_formats - 1; mWindowThread->glReady(); }); - if (auto_show) - { - show(); - glClearColor(0.0f, 0.0f, 0.0f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - swapBuffers(); - } + if (auto_show) + { + show(); + glClearColor(0.0f, 0.0f, 0.0f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + swapBuffers(); + } LL_PROFILER_GPU_CONTEXT; - return TRUE; + return TRUE; } void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) @@ -1771,10 +1771,10 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw windowClassName, windowTitle, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height NULL, NULL, hInstance, @@ -1793,7 +1793,7 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw self->mWindowHandleThrd = handle; self->mhDCThrd = GetDC(handle); } - + updateWindowRect(); // It's important to wake up the future either way. @@ -1909,22 +1909,22 @@ void LLWindowWin32::toggleVSync(bool enable_vsync) void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) { - if( mIsMouseClipping ) - { - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - ClipCursor( &client_rect_in_screen_space ); - } - } - - // if the window was already maximized, MoveWindow seems to still set the maximized flag even if - // the window is smaller than maximized. - // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). - - // THIS CAUSES DEV-15484 and DEV-15949 - //ShowWindow(mWindowHandle, SW_RESTORE); - // NOW we can call MoveWindow + if( mIsMouseClipping ) + { + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + ClipCursor( &client_rect_in_screen_space ); + } + } + + // if the window was already maximized, MoveWindow seems to still set the maximized flag even if + // the window is smaller than maximized. + // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). + + // THIS CAUSES DEV-15484 and DEV-15949 + //ShowWindow(mWindowHandle, SW_RESTORE); + // NOW we can call MoveWindow mWindowThread->post([=]() { MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); @@ -1979,7 +1979,7 @@ BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) } *position = mCursorPosition; - return TRUE; + return TRUE; } BOOL LLWindowWin32::getCursorDelta(LLCoordCommon* delta) @@ -2006,8 +2006,8 @@ void LLWindowWin32::hideCursor() } }); - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; + mCursorHidden = TRUE; + mHideCursorPermanent = TRUE; } void LLWindowWin32::showCursor() @@ -2015,7 +2015,7 @@ void LLWindowWin32::showCursor() LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; ASSERT_MAIN_THREAD(); - + mWindowThread->post([=]() { // makes sure the cursor shows up @@ -2025,103 +2025,103 @@ void LLWindowWin32::showCursor() } }); - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; + mCursorHidden = FALSE; + mHideCursorPermanent = FALSE; } void LLWindowWin32::showCursorFromMouseMove() { - if (!mHideCursorPermanent) - { - showCursor(); - } + if (!mHideCursorPermanent) + { + showCursor(); + } } void LLWindowWin32::hideCursorUntilMouseMove() { - if (!mHideCursorPermanent && mMouseVanish) - { - hideCursor(); - mHideCursorPermanent = FALSE; - } + if (!mHideCursorPermanent && mMouseVanish) + { + hideCursor(); + mHideCursorPermanent = FALSE; + } } BOOL LLWindowWin32::isCursorHidden() { - return mCursorHidden; + return mCursorHidden; } HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) { - return (HCURSOR)LoadImage(mhInstance, - name, - IMAGE_CURSOR, - 0, // default width - 0, // default height - LR_DEFAULTCOLOR); + return (HCURSOR)LoadImage(mhInstance, + name, + IMAGE_CURSOR, + 0, // default width + 0, // default height + LR_DEFAULTCOLOR); } void LLWindowWin32::initCursors() { - mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); - mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); - mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); - mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); - mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); - mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); - mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); - mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); - mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); - mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL); - mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); - mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); - - HMODULE module = GetModuleHandle(NULL); - mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); - mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); - mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); - mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); - mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); - mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); - mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); - mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); - mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); - mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); - mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); - mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); - mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); - mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); - mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); - mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); - mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); - mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT")); - mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); - mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); - mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); - mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); - mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); - mCursor[ UI_CURSOR_TOOLPATHFINDING ] = LoadCursor(module, TEXT("TOOLPATHFINDING")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTARTADD")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTART")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHEND")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHENDADD")); - mCursor[ UI_CURSOR_TOOLNO ] = LoadCursor(module, TEXT("TOOLNO")); - - // Color cursors - mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); - mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); - mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); - - // Note: custom cursors that are not found make LoadCursor() return NULL. - for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) - { - if( !mCursor[i] ) - { - mCursor[i] = LoadCursor(NULL, IDC_ARROW); - } - } + mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); + mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); + mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); + mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); + mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); + mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); + mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); + mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); + mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); + mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL); + mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); + mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); + + HMODULE module = GetModuleHandle(NULL); + mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); + mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); + mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); + mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); + mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); + mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); + mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); + mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); + mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); + mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); + mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); + mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); + mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); + mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); + mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); + mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); + mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); + mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT")); + mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); + mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); + mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); + mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); + mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); + mCursor[ UI_CURSOR_TOOLPATHFINDING ] = LoadCursor(module, TEXT("TOOLPATHFINDING")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTARTADD")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTART")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHEND")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHENDADD")); + mCursor[ UI_CURSOR_TOOLNO ] = LoadCursor(module, TEXT("TOOLNO")); + + // Color cursors + mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); + mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); + mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); + + // Note: custom cursors that are not found make LoadCursor() return NULL. + for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) + { + if( !mCursor[i] ) + { + mCursor[i] = LoadCursor(NULL, IDC_ARROW); + } + } } @@ -2130,43 +2130,43 @@ void LLWindowWin32::updateCursor() { ASSERT_MAIN_THREAD(); LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - - if( mCurrentCursor != mNextCursor ) - { - mCurrentCursor = mNextCursor; + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + + if( mCurrentCursor != mNextCursor ) + { + mCurrentCursor = mNextCursor; auto nextCursor = mCursor[mNextCursor]; mWindowThread->post([=]() { SetCursor(nextCursor); }); - } + } } ECursorType LLWindowWin32::getCursor() const { - return mCurrentCursor; + return mCurrentCursor; } void LLWindowWin32::captureMouse() { - SetCapture(mWindowHandle); + SetCapture(mWindowHandle); } void LLWindowWin32::releaseMouse() { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - ReleaseCapture(); + ReleaseCapture(); } void LLWindowWin32::delayInputProcessing() { - mInputProcessingPaused = TRUE; + mInputProcessingPaused = TRUE; } @@ -2190,7 +2190,7 @@ void LLWindowWin32::gatherInput() LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage"); kickWindowThread(); } - + while (mWindowThread->mMessageQueue.tryPopBack(msg)) { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue"); @@ -2234,7 +2234,7 @@ void LLWindowWin32::gatherInput() LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move"); mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask); } - + mLastCursorPosition = mCursorPosition; { @@ -2247,9 +2247,9 @@ void LLWindowWin32::gatherInput() } } - mInputProcessingPaused = FALSE; + mInputProcessingPaused = FALSE; - updateCursor(); + updateCursor(); } static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); @@ -2296,9 +2296,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ switch (u_msg) { - RECT update_rect; - S32 update_width; - S32 update_height; + RECT update_rect; + S32 update_width; + S32 update_height; case WM_TIMER: { @@ -2313,7 +2313,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) { WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - + return TRUE; } break; @@ -2374,7 +2374,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ if (window_imp->mFullscreen) { - // When we run fullscreen, restoring or minimizing the app needs + // When we run fullscreen, restoring or minimizing the app needs // to switch the screen resolution if (activating) { @@ -2410,7 +2410,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->interruptLanguageTextInput(); } }); - + break; } @@ -2488,7 +2488,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ gKeyboard->handleKeyDown(w_param, mask); }); - if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress break; } case WM_SYSKEYUP: @@ -2510,7 +2510,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ gKeyboard->handleKeyUp(w_param, mask); } }); - if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress break; } case WM_IME_SETCONTEXT: @@ -2583,7 +2583,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // it is worth trying. The good old WM_CHAR works just fine even for supplementary // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's // by ourselves. It is not that tough. -- Alissa Sabre @ SL - + // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, // we *did* processed the event, so I believe we should not pass it to DefWindowProc... window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); @@ -2611,12 +2611,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->postMouseButtonEvent([=]() { sHandleLeftMouseUp = true; - + if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); } - + MASK mask = gKeyboard->currentMask(TRUE); auto gl_coord = window_imp->mCursorPosition.convert(); window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); @@ -2663,7 +2663,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } sHandleDoubleClick = true; - + MASK mask = gKeyboard->currentMask(TRUE); // generate move event to update mouse coordinates window_imp->mCursorPosition = window_coord; @@ -2711,7 +2711,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_MBUTTONDOWN: - // case WM_MBUTTONDBLCLK: + // case WM_MBUTTONDBLCLK: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN"); { @@ -2759,7 +2759,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); }); - + } break; @@ -2784,7 +2784,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL"); static short z_delta = 0; - RECT client_rect; + RECT client_rect; // eat scroll events that occur outside our window, since we use mouse position to direct scroll // instead of keyboard focus @@ -2827,12 +2827,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { window_imp->mCallbacks->handleMouseLeave(window_imp); - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = h_wnd; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = h_wnd; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); return 0; } */ @@ -2841,7 +2841,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL"); static short h_delta = 0; - RECT client_rect; + RECT client_rect; // eat scroll events that occur outside our window, since we use mouse position to direct scroll // instead of keyboard focus @@ -2876,7 +2876,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MOUSEMOVE: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE"); - // DO NOT use mouse event queue for move events to ensure cursor position is updated + // DO NOT use mouse event queue for move events to ensure cursor position is updated // when button events are handled WINDOW_IMP_POST( { @@ -2908,12 +2908,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE"); window_imp->updateWindowRect(); - // There's an odd behavior with WM_SIZE that I would call a bug. If + // There's an odd behavior with WM_SIZE that I would call a bug. If // the window is maximized, and you call MoveWindow() with a size smaller - // than a maximized window, it ends up sending WM_SIZE with w_param set + // than a maximized window, it ends up sending WM_SIZE with w_param set // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. - // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see - // LLWindowWin32::moveWindow in this file). + // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see + // LLWindowWin32::moveWindow in this file). // If we are now restored, but we weren't before, this // means that the window was un-minimized. @@ -2957,7 +2957,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ S32 new_width = lprc_new_scale->right - lprc_new_scale->left; S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; WINDOW_IMP_POST(window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height)); - + SetWindowPos(h_wnd, HWND_TOP, lprc_new_scale->left, @@ -2965,7 +2965,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ new_width, new_height, SWP_NOZORDER | SWP_NOACTIVATE); - + return 0; } @@ -3015,17 +3015,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } break; - + case WM_INPUT: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT"); - + UINT dwSize = 0; GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); llassert(dwSize < 1024); U8 lpb[1024]; - + if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) { RAWINPUT* raw = (RAWINPUT*)lpb; @@ -3121,175 +3121,175 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) { - S32 client_height; - RECT client_rect; - LLCoordWindow window_position; + S32 client_height; + RECT client_rect; + LLCoordWindow window_position; - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == to) - { - return FALSE; - } + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == to) + { + return FALSE; + } - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; + to->mX = from.mX; + client_height = client_rect.bottom - client_rect.top; + to->mY = client_height - from.mY - 1; - return TRUE; + return TRUE; } BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) { - S32 client_height; - RECT client_rect; + S32 client_height; + RECT client_rect; - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == to) - { - return FALSE; - } + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == to) + { + return FALSE; + } - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; + to->mX = from.mX; + client_height = client_rect.bottom - client_rect.top; + to->mY = client_height - from.mY - 1; - return TRUE; + return TRUE; } BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - POINT mouse_point; +{ + POINT mouse_point; - mouse_point.x = from.mX; - mouse_point.y = from.mY; - BOOL result = ScreenToClient(mWindowHandle, &mouse_point); + mouse_point.x = from.mX; + mouse_point.y = from.mY; + BOOL result = ScreenToClient(mWindowHandle, &mouse_point); - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } - return result; + return result; } BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) { - POINT mouse_point; + POINT mouse_point; - mouse_point.x = from.mX; - mouse_point.y = from.mY; - BOOL result = ClientToScreen(mWindowHandle, &mouse_point); + mouse_point.x = from.mX; + mouse_point.y = from.mY; + BOOL result = ClientToScreen(mWindowHandle, &mouse_point); - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } - return result; + return result; } BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - if (!mWindowHandle || (NULL == to)) - { - return FALSE; - } + if (!mWindowHandle || (NULL == to)) + { + return FALSE; + } - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return TRUE; + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return TRUE; } BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - if (!mWindowHandle || (NULL == to)) - { - return FALSE; - } + if (!mWindowHandle || (NULL == to)) + { + return FALSE; + } - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return TRUE; + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return TRUE; } BOOL LLWindowWin32::isClipboardTextAvailable() { - return IsClipboardFormatAvailable(CF_UNICODETEXT); + return IsClipboardFormatAvailable(CF_UNICODETEXT); } BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) { - BOOL success = FALSE; + BOOL success = FALSE; - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) - { - if (OpenClipboard(mWindowHandle)) - { - HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); - if (h_data) - { - WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); - if (utf16str) - { - dst = utf16str_to_wstring(utf16str); - LLWStringUtil::removeWindowsCR(dst); - GlobalUnlock(h_data); - success = TRUE; - } - } - CloseClipboard(); - } - } + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + if (OpenClipboard(mWindowHandle)) + { + HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); + if (h_data) + { + WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); + if (utf16str) + { + dst = utf16str_to_wstring(utf16str); + LLWStringUtil::removeWindowsCR(dst); + GlobalUnlock(h_data); + success = TRUE; + } + } + CloseClipboard(); + } + } - return success; + return success; } BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) { - BOOL success = FALSE; + BOOL success = FALSE; - if (OpenClipboard(mWindowHandle)) - { - EmptyClipboard(); + if (OpenClipboard(mWindowHandle)) + { + EmptyClipboard(); - // Provide a copy of the data in Unicode format. - LLWString sanitized_string(wstr); - LLWStringUtil::addCRLF(sanitized_string); - llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); - const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); + // Provide a copy of the data in Unicode format. + LLWString sanitized_string(wstr); + LLWStringUtil::addCRLF(sanitized_string); + llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); + const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); - // Memory is allocated and then ownership of it is transfered to the system. - HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); - if (hglobal_copy_utf16) - { - WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); - if (copy_utf16) - { - memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ - GlobalUnlock(hglobal_copy_utf16); + // Memory is allocated and then ownership of it is transfered to the system. + HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); + if (hglobal_copy_utf16) + { + WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); + if (copy_utf16) + { + memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ + GlobalUnlock(hglobal_copy_utf16); - if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) - { - success = TRUE; - } - } - } + if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) + { + success = TRUE; + } + } + } - CloseClipboard(); - } + CloseClipboard(); + } - return success; + return success; } // Constrains the mouse to the window. @@ -3297,32 +3297,32 @@ void LLWindowWin32::setMouseClipping( BOOL b ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; ASSERT_MAIN_THREAD(); - if( b != mIsMouseClipping ) - { - BOOL success = FALSE; - - if( b ) - { - GetClipCursor( &mOldMouseClip ); - - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - success = ClipCursor( &client_rect_in_screen_space ); - } - } - else - { - // Must restore the old mouse clip, which may be set by another window. - success = ClipCursor( &mOldMouseClip ); - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - } - - if( success ) - { - mIsMouseClipping = b; - } - } + if( b != mIsMouseClipping ) + { + BOOL success = FALSE; + + if( b ) + { + GetClipCursor( &mOldMouseClip ); + + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + success = ClipCursor( &client_rect_in_screen_space ); + } + } + else + { + // Must restore the old mouse clip, which may be set by another window. + success = ClipCursor( &mOldMouseClip ); + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + } + + if( success ) + { + mIsMouseClipping = b; + } + } } BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) @@ -3371,29 +3371,29 @@ void LLWindowWin32::flashIcon(F32 seconds) F32 LLWindowWin32::getGamma() { - return mCurrentGamma; + return mCurrentGamma; } BOOL LLWindowWin32::restoreGamma() { ASSERT_MAIN_THREAD(); - if (mCustomGammaSet != FALSE) - { + if (mCustomGammaSet != FALSE) + { LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; - mCustomGammaSet = FALSE; - return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); - } - return TRUE; + mCustomGammaSet = FALSE; + return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); + } + return TRUE; } BOOL LLWindowWin32::setGamma(const F32 gamma) { ASSERT_MAIN_THREAD(); - mCurrentGamma = gamma; + mCurrentGamma = gamma; - //Get the previous gamma ramp to restore later. - if (mCustomGammaSet == FALSE) - { + //Get the previous gamma ramp to restore later. + if (mCustomGammaSet == FALSE) + { if (!gGLManager.mIsIntel) // skip for Intel GPUs (see SL-11341) { LL_DEBUGS("Window") << "Getting the previous gamma ramp to restore later" << LL_ENDL; @@ -3403,192 +3403,192 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) return FALSE; } } - mCustomGammaSet = TRUE; - } + mCustomGammaSet = TRUE; + } - LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; + LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; - for ( int i = 0; i < 256; ++i ) - { - int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); + for ( int i = 0; i < 256; ++i ) + { + int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); - int value = mult * i; + int value = mult * i; - if ( value > 0xffff ) - value = 0xffff; + if ( value > 0xffff ) + value = 0xffff; - mCurrentGammaRamp[0][i] = - mCurrentGammaRamp[1][i] = - mCurrentGammaRamp[2][i] = (WORD) value; - }; + mCurrentGammaRamp[0][i] = + mCurrentGammaRamp[1][i] = + mCurrentGammaRamp[2][i] = (WORD) value; + }; - return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); + return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); } void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) { ASSERT_MAIN_THREAD(); - mFSAASamples = fsaa_samples; + mFSAASamples = fsaa_samples; } U32 LLWindowWin32::getFSAASamples() { - return mFSAASamples; + return mFSAASamples; } LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { ASSERT_MAIN_THREAD(); - if (!mSupportedResolutions) - { - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - - mNumSupportedResolutions = 0; - for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && - dev_mode.dmPelsWidth >= 800 && - dev_mode.dmPelsHeight >= 600) - { - BOOL resolution_exists = FALSE; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && - mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) - { - resolution_exists = TRUE; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; - mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; - mNumSupportedResolutions++; - } - } - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; + if (!mSupportedResolutions) + { + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + + mNumSupportedResolutions = 0; + for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && + dev_mode.dmPelsWidth >= 800 && + dev_mode.dmPelsHeight >= 600) + { + BOOL resolution_exists = FALSE; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && + mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) + { + resolution_exists = TRUE; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; + mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; + mNumSupportedResolutions++; + } + } + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; } F32 LLWindowWin32::getNativeAspectRatio() { - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } - else if (mNativeAspectRatio > 0.f) - { - // we grabbed this value at startup, based on the user's desktop settings - return mNativeAspectRatio; - } - // RN: this hack presumes that the largest supported resolution is monitor-limited - // and that pixels in that mode are square, therefore defining the native aspect ratio - // of the monitor...this seems to work to a close approximation for most CRTs/LCDs - S32 num_resolutions; - LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + else if (mNativeAspectRatio > 0.f) + { + // we grabbed this value at startup, based on the user's desktop settings + return mNativeAspectRatio; + } + // RN: this hack presumes that the largest supported resolution is monitor-limited + // and that pixels in that mode are square, therefore defining the native aspect ratio + // of the monitor...this seems to work to a close approximation for most CRTs/LCDs + S32 num_resolutions; + LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); + return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); } F32 LLWindowWin32::getPixelAspectRatio() { - F32 pixel_aspect = 1.f; - if (getFullscreen()) - { - LLCoordScreen screen_size; - getSize(&screen_size); - pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + getSize(&screen_size); + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } - return pixel_aspect; + return pixel_aspect; } // Change display resolution. Returns true if successful. // protected BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) { - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - BOOL success = FALSE; - - // Don't change anything if we don't have to - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == bits && - dev_mode.dmDisplayFrequency == refresh ) - { - // ...display mode identical, do nothing - return TRUE; - } - } - - memset(&dev_mode, 0, sizeof(dev_mode)); - dev_mode.dmSize = sizeof(dev_mode); - dev_mode.dmPelsWidth = width; - dev_mode.dmPelsHeight = height; - dev_mode.dmBitsPerPel = bits; - dev_mode.dmDisplayFrequency = refresh; - dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - - // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. - LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); - - success = (DISP_CHANGE_SUCCESSFUL == cds_result); - - if (!success) - { - LL_WARNS("Window") << "setDisplayResolution failed, " - << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; - } - - return success; + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + BOOL success = FALSE; + + // Don't change anything if we don't have to + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == bits && + dev_mode.dmDisplayFrequency == refresh ) + { + // ...display mode identical, do nothing + return TRUE; + } + } + + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + dev_mode.dmPelsWidth = width; + dev_mode.dmPelsHeight = height; + dev_mode.dmBitsPerPel = bits; + dev_mode.dmDisplayFrequency = refresh; + dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + + // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. + LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); + + success = (DISP_CHANGE_SUCCESSFUL == cds_result); + + if (!success) + { + LL_WARNS("Window") << "setDisplayResolution failed, " + << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; + } + + return success; } // protected BOOL LLWindowWin32::setFullscreenResolution() { - if (mFullscreen) - { - return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); - } - else - { - return FALSE; - } + if (mFullscreen) + { + return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); + } + else + { + return FALSE; + } } // protected BOOL LLWindowWin32::resetDisplayResolution() { - LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; + LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; - LONG cds_result = ChangeDisplaySettings(NULL, 0); + LONG cds_result = ChangeDisplaySettings(NULL, 0); - BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); + BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); - if (!success) - { - LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; - } + if (!success) + { + LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; + } - LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; + LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; - return success; + return success; } void LLWindowWin32::swapBuffers() @@ -3609,7 +3609,7 @@ void LLWindowWin32::swapBuffers() // LLSplashScreenImp // LLSplashScreenWin32::LLSplashScreenWin32() -: mWindow(NULL) +: mWindow(NULL) { } @@ -3619,14 +3619,14 @@ LLSplashScreenWin32::~LLSplashScreenWin32() void LLSplashScreenWin32::showImpl() { - // This appears to work. ??? - HINSTANCE hinst = GetModuleHandle(NULL); + // This appears to work. ??? + HINSTANCE hinst = GetModuleHandle(NULL); - mWindow = CreateDialog(hinst, - TEXT("SPLASHSCREEN"), - NULL, // no parent - (DLGPROC) LLSplashScreenWin32::windowProc); - ShowWindow(mWindow, SW_SHOW); + mWindow = CreateDialog(hinst, + TEXT("SPLASHSCREEN"), + NULL, // no parent + (DLGPROC) LLSplashScreenWin32::windowProc); + ShowWindow(mWindow, SW_SHOW); // Should set taskbar text without creating a header for the window (caption) SetWindowTextA(mWindow, "Second Life"); @@ -3635,46 +3635,46 @@ void LLSplashScreenWin32::showImpl() void LLSplashScreenWin32::updateImpl(const std::string& mesg) { - if (!mWindow) return; + if (!mWindow) return; - int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); - if( output_str_len>1024 ) - return; + int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); + if( output_str_len>1024 ) + return; - WCHAR w_mesg[1025];//big enought to keep null terminatos + WCHAR w_mesg[1025];//big enought to keep null terminatos - MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); + MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); - //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 - w_mesg[output_str_len] = 0; + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 + w_mesg[output_str_len] = 0; - SendDlgItemMessage(mWindow, - 666, // HACK: text id - WM_SETTEXT, - FALSE, - (LPARAM)w_mesg); + SendDlgItemMessage(mWindow, + 666, // HACK: text id + WM_SETTEXT, + FALSE, + (LPARAM)w_mesg); } void LLSplashScreenWin32::hideImpl() { - if (mWindow) - { + if (mWindow) + { if (!destroy_window_handler(mWindow)) { LL_WARNS("Window") << "Failed to properly close splash screen window!" << LL_ENDL; } - mWindow = NULL; - } + mWindow = NULL; + } } // static LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param) + WPARAM w_param, LPARAM l_param) { - // Just give it to windows - return DefWindowProc(h_wnd, u_msg, w_param, l_param); + // Just give it to windows + return DefWindowProc(h_wnd, u_msg, w_param, l_param); } // @@ -3683,148 +3683,155 @@ LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) { - UINT uType; - - switch(type) - { - case OSMB_OK: - uType = MB_OK; - break; - case OSMB_OKCANCEL: - uType = MB_OKCANCEL; - break; - case OSMB_YESNO: - uType = MB_YESNO; - break; - default: - uType = MB_OK; - break; - } - - int retval_win = MessageBoxW(NULL, // HWND - ll_convert_string_to_wide(text).c_str(), - ll_convert_string_to_wide(caption).c_str(), - uType); - S32 retval; + UINT uType; + + switch(type) + { + case OSMB_OK: + uType = MB_OK; + break; + case OSMB_OKCANCEL: + uType = MB_OKCANCEL; + break; + case OSMB_YESNO: + uType = MB_YESNO; + break; + default: + uType = MB_OK; + break; + } + + int retval_win = MessageBoxW(NULL, // HWND + ll_convert_string_to_wide(text).c_str(), + ll_convert_string_to_wide(caption).c_str(), + uType); + S32 retval; + + switch(retval_win) + { + case IDYES: + retval = OSBTN_YES; + break; + case IDNO: + retval = OSBTN_NO; + break; + case IDOK: + retval = OSBTN_OK; + break; + case IDCANCEL: + retval = OSBTN_CANCEL; + break; + default: + retval = OSBTN_CANCEL; + break; + } + + return retval; +} + +void shell_open(const std::string &file, bool async) +{ + std::wstring url_utf16 = ll_convert(file); - switch(retval_win) + // let the OS decide what to use to open the URL + SHELLEXECUTEINFO sei = {sizeof(sei)}; + // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange + // necessary for ShellExecuteEx to complete + if (async) { - case IDYES: - retval = OSBTN_YES; - break; - case IDNO: - retval = OSBTN_NO; - break; - case IDOK: - retval = OSBTN_OK; - break; - case IDCANCEL: - retval = OSBTN_CANCEL; - break; - default: - retval = OSBTN_CANCEL; - break; + sei.fMask = SEE_MASK_ASYNCOK; } - - return retval; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"open"; + sei.lpFile = url_utf16.c_str(); + ShellExecuteEx(&sei); } - void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) { - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) - { - found = true; - break; - } - } + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) + { + found = true; + break; + } + } - if (!found) - { - LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } + if (!found) + { + LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } - LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; + LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; - // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work - // reliablly on Vista. + // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work + // reliablly on Vista. - // this is madness.. no, this is.. - LLWString url_wstring = utf8str_to_wstring( escaped_url ); - llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); + shell_open(escaped_url, async); +} - // let the OS decide what to use to open the URL - SHELLEXECUTEINFO sei = { sizeof( sei ) }; - // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange - // necessary for ShellExecuteEx to complete - if (async) - { - sei.fMask = SEE_MASK_ASYNCOK; - } - sei.nShow = SW_SHOWNORMAL; - sei.lpVerb = L"open"; - sei.lpFile = url_utf16.c_str(); - ShellExecuteEx( &sei ); +void LLWindowWin32::openFolder(const std::string &path) +{ + shell_open(path, false); } /* - Make the raw keyboard data available - used to poke through to LLQtWebKit so - that Qt/Webkit has access to the virtual keycodes etc. that it needs + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs */ LLSD LLWindowWin32::getNativeKeyData() { - LLSD result = LLSD::emptyMap(); + LLSD result = LLSD::emptyMap(); - result["scan_code"] = (S32)mKeyScanCode; - result["virtual_key"] = (S32)mKeyVirtualKey; - result["msg"] = ll_sd_from_U32(mRawMsg); - result["w_param"] = ll_sd_from_U32(mRawWParam); - result["l_param"] = ll_sd_from_U32(mRawLParam); + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["msg"] = ll_sd_from_U32(mRawMsg); + result["w_param"] = ll_sd_from_U32(mRawWParam); + result["l_param"] = ll_sd_from_U32(mRawLParam); - return result; + return result; } BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) { - BOOL retval = FALSE; - - static CHOOSECOLOR cc; - static COLORREF crCustColors[16]; - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = mWindowHandle; - cc.hInstance = NULL; - cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); - //cc.rgbResult = RGB (0x80,0x80,0x80); - cc.lpCustColors = crCustColors; - cc.Flags = CC_RGBINIT | CC_FULLOPEN; - cc.lCustData = 0; - cc.lpfnHook = NULL; - cc.lpTemplateName = NULL; - - // This call is modal, so pause agent - //send_agent_pause(); // this is in newview and we don't want to set up a dependency - { - retval = ChooseColor(&cc); - } - //send_agent_resume(); // this is in newview and we don't want to set up a dependency - - *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; - - *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; - - *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; - - return (retval); + BOOL retval = FALSE; + + static CHOOSECOLOR cc; + static COLORREF crCustColors[16]; + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = mWindowHandle; + cc.hInstance = NULL; + cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); + //cc.rgbResult = RGB (0x80,0x80,0x80); + cc.lpCustColors = crCustColors; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.lCustData = 0; + cc.lpfnHook = NULL; + cc.lpTemplateName = NULL; + + // This call is modal, so pause agent + //send_agent_pause(); // this is in newview and we don't want to set up a dependency + { + retval = ChooseColor(&cc); + } + //send_agent_resume(); // this is in newview and we don't want to set up a dependency + + *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; + + *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; + + *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; + + return (retval); } void *LLWindowWin32::getPlatformWindow() { - return (void*)mWindowHandle; + return (void*)mWindowHandle; } void LLWindowWin32::bringToFront() @@ -3846,40 +3853,40 @@ void LLWindowWin32::focusClient() void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { - if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) - { - return; - } - - if (preeditor != mPreeditor && !b) - { - // This condition may occur with a call to - // setEnabled(BOOL) from LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - if (sLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - sLanguageTextInputAllowed = b; + if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) + { + return; + } + + if (preeditor != mPreeditor && !b) + { + // This condition may occur with a call to + // setEnabled(BOOL) from LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + if (sLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + sLanguageTextInputAllowed = b; if (sLanguageTextInputAllowed) { mWindowThread->post([=]() { - // Allowing: Restore the previous IME status, so that the user has a feeling that the previous - // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps + // Allowing: Restore the previous IME status, so that the user has a feeling that the previous + // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps // using same Input Locale (aka Keyboard Layout). if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) { @@ -3907,7 +3914,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); - // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's + // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's // keyboard hooking, because Some IME reacts only on the former and some other on the latter... LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); LLWinImm::setOpenStatus(himc, FALSE); @@ -3918,194 +3925,194 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) } } -void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, - CANDIDATEFORM *form) +void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, + CANDIDATEFORM *form) { - LLCoordWindow caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + LLCoordWindow caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - memset(form, 0, sizeof(CANDIDATEFORM)); - form->dwStyle = CFS_EXCLUDE; - form->ptCurrentPos.x = caret_coord.mX; - form->ptCurrentPos.y = caret_coord.mY; - form->rcArea.left = top_left.mX; - form->rcArea.top = top_left.mY; - form->rcArea.right = bottom_right.mX; - form->rcArea.bottom = bottom_right.mY; + memset(form, 0, sizeof(CANDIDATEFORM)); + form->dwStyle = CFS_EXCLUDE; + form->ptCurrentPos.x = caret_coord.mX; + form->ptCurrentPos.y = caret_coord.mY; + form->rcArea.left = top_left.mX; + form->rcArea.top = top_left.mY; + form->rcArea.right = bottom_right.mX; + form->rcArea.bottom = bottom_right.mY; } // Put the IME window at the right place (near current text input). Point coordinates should be the top of the current text line. void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) { - if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); + if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); - LLCoordWindow win_pos; - convertCoords( position, &win_pos ); + LLCoordWindow win_pos; + convertCoords( position, &win_pos ); - if ( win_pos.mX >= 0 && win_pos.mY >= 0 && - (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) - { - COMPOSITIONFORM ime_form; - memset( &ime_form, 0, sizeof(ime_form) ); - ime_form.dwStyle = CFS_POINT; - ime_form.ptCurrentPos.x = win_pos.mX; - ime_form.ptCurrentPos.y = win_pos.mY; + if ( win_pos.mX >= 0 && win_pos.mY >= 0 && + (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) + { + COMPOSITIONFORM ime_form; + memset( &ime_form, 0, sizeof(ime_form) ); + ime_form.dwStyle = CFS_POINT; + ime_form.ptCurrentPos.x = win_pos.mX; + ime_form.ptCurrentPos.y = win_pos.mY; - LLWinImm::setCompositionWindow( himc, &ime_form ); + LLWinImm::setCompositionWindow( himc, &ime_form ); - sWinIMEWindowPosition = win_pos; - } + sWinIMEWindowPosition = win_pos; + } - LLWinImm::releaseContext(mWindowHandle, himc); - } + LLWinImm::releaseContext(mWindowHandle, himc); + } } void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, - IMECHARPOSITION *char_position) + IMECHARPOSITION *char_position) { - LLCoordScreen caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + LLCoordScreen caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - char_position->pt.x = caret_coord.mX; - char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... - char_position->cLineHeight = bottom_right.mY - top_left.mY; - char_position->rcDocument.left = top_left.mX; - char_position->rcDocument.top = top_left.mY; - char_position->rcDocument.right = bottom_right.mX; - char_position->rcDocument.bottom = bottom_right.mY; + char_position->pt.x = caret_coord.mX; + char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... + char_position->cLineHeight = bottom_right.mY - top_left.mY; + char_position->rcDocument.left = top_left.mX; + char_position->rcDocument.top = top_left.mY; + char_position->rcDocument.right = bottom_right.mX; + char_position->rcDocument.bottom = bottom_right.mY; } void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) { - // Our font is a list of FreeType recognized font files that may - // not have a corresponding ones in Windows' fonts. Hence, we - // can't simply tell Windows which font we are using. We will - // notify a _standard_ font for a current input locale instead. - // We use a hard-coded knowledge about the Windows' standard - // configuration to do so... - - memset(logfont, 0, sizeof(LOGFONT)); - - const WORD lang_id = LOWORD(GetKeyboardLayout(0)); - switch (PRIMARYLANGID(lang_id)) - { - case LANG_CHINESE: - // We need to identify one of two Chinese fonts. - switch (SUBLANGID(lang_id)) - { - case SUBLANG_CHINESE_SIMPLIFIED: - case SUBLANG_CHINESE_SINGAPORE: - logfont->lfCharSet = GB2312_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("SimHei")); - break; - case SUBLANG_CHINESE_TRADITIONAL: - case SUBLANG_CHINESE_HONGKONG: - case SUBLANG_CHINESE_MACAU: - default: - logfont->lfCharSet = CHINESEBIG5_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); - break; - } - break; - case LANG_JAPANESE: - logfont->lfCharSet = SHIFTJIS_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); - break; - case LANG_KOREAN: - logfont->lfCharSet = HANGUL_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Gulim")); - break; - default: - logfont->lfCharSet = ANSI_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); - break; - } - - logfont->lfHeight = mPreeditor->getPreeditFontSize(); - logfont->lfWeight = FW_NORMAL; -} + // Our font is a list of FreeType recognized font files that may + // not have a corresponding ones in Windows' fonts. Hence, we + // can't simply tell Windows which font we are using. We will + // notify a _standard_ font for a current input locale instead. + // We use a hard-coded knowledge about the Windows' standard + // configuration to do so... + + memset(logfont, 0, sizeof(LOGFONT)); + + const WORD lang_id = LOWORD(GetKeyboardLayout(0)); + switch (PRIMARYLANGID(lang_id)) + { + case LANG_CHINESE: + // We need to identify one of two Chinese fonts. + switch (SUBLANGID(lang_id)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + case SUBLANG_CHINESE_SINGAPORE: + logfont->lfCharSet = GB2312_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("SimHei")); + break; + case SUBLANG_CHINESE_TRADITIONAL: + case SUBLANG_CHINESE_HONGKONG: + case SUBLANG_CHINESE_MACAU: + default: + logfont->lfCharSet = CHINESEBIG5_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); + break; + } + break; + case LANG_JAPANESE: + logfont->lfCharSet = SHIFTJIS_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); + break; + case LANG_KOREAN: + logfont->lfCharSet = HANGUL_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Gulim")); + break; + default: + logfont->lfCharSet = ANSI_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); + break; + } + + logfont->lfHeight = mPreeditor->getPreeditFontSize(); + logfont->lfWeight = FW_NORMAL; +} U32 LLWindowWin32::fillReconvertString(const LLWString &text, - S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) + S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) { - const llutf16string text_utf16 = wstring_to_utf16str(text); - const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); - if (reconvert_string && reconvert_string->dwSize >= required_size) - { - const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); - const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); - - reconvert_string->dwVersion = 0; - reconvert_string->dwStrLen = text_utf16.length(); - reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); - reconvert_string->dwCompStrLen = focus_utf16_length; - reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); - reconvert_string->dwTargetStrLen = 0; - reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); - - const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); - memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); - } - return required_size; + const llutf16string text_utf16 = wstring_to_utf16str(text); + const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); + if (reconvert_string && reconvert_string->dwSize >= required_size) + { + const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); + const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); + + reconvert_string->dwVersion = 0; + reconvert_string->dwStrLen = text_utf16.length(); + reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); + reconvert_string->dwCompStrLen = focus_utf16_length; + reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); + reconvert_string->dwTargetStrLen = 0; + reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); + + const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); + memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); + } + return required_size; } void LLWindowWin32::updateLanguageTextInputArea() { - if (!mPreeditor || !LLWinImm::isAvailable()) - { - return; - } - - LLCoordGL caret_coord; - LLRect preedit_bounds; - if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) - { - mLanguageTextInputPointGL = caret_coord; - mLanguageTextInputAreaGL = preedit_bounds; - - CANDIDATEFORM candidate_form; - fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); - - HIMC himc = LLWinImm::getContext(mWindowHandle); - // Win32 document says there may be up to 4 candidate windows. - // This magic number 4 appears only in the document, and - // there are no constant/macro for the value... - for (int i = 3; i >= 0; --i) - { - candidate_form.dwIndex = i; - LLWinImm::setCandidateWindow(himc, &candidate_form); - } - LLWinImm::releaseContext(mWindowHandle, himc); - } + if (!mPreeditor || !LLWinImm::isAvailable()) + { + return; + } + + LLCoordGL caret_coord; + LLRect preedit_bounds; + if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) + { + mLanguageTextInputPointGL = caret_coord; + mLanguageTextInputAreaGL = preedit_bounds; + + CANDIDATEFORM candidate_form; + fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); + + HIMC himc = LLWinImm::getContext(mWindowHandle); + // Win32 document says there may be up to 4 candidate windows. + // This magic number 4 appears only in the document, and + // there are no constant/macro for the value... + for (int i = 3; i >= 0; --i) + { + candidate_form.dwIndex = i; + LLWinImm::setCandidateWindow(himc, &candidate_form); + } + LLWinImm::releaseContext(mWindowHandle, himc); + } } void LLWindowWin32::interruptLanguageTextInput() { ASSERT_MAIN_THREAD(); - if (mPreeditor && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - } + if (mPreeditor && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + } } void LLWindowWin32::handleStartCompositionMessage() { - // Let IME know the font to use in feedback UI. - LOGFONT logfont; - fillCompositionLogfont(&logfont); - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setCompositionFont(himc, &logfont); - LLWinImm::releaseContext(mWindowHandle, himc); + // Let IME know the font to use in feedback UI. + LOGFONT logfont; + fillCompositionLogfont(&logfont); + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::setCompositionFont(himc, &logfont); + LLWinImm::releaseContext(mWindowHandle, himc); } // Handle WM_IME_COMPOSITION message. @@ -4116,156 +4123,156 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) { return; } - BOOL needs_update = FALSE; - LLWString result_string; - LLWString preedit_string; - S32 preedit_string_utf16_length = 0; - LLPreeditor::segment_lengths_t preedit_segment_lengths; - LLPreeditor::standouts_t preedit_standouts; - - // Step I: Receive details of preedits from IME. - - HIMC himc = LLWinImm::getContext(mWindowHandle); - - if (indexes & GCS_RESULTSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); - if (size > 0) - { - result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = TRUE; - } - } - - if (indexes & GCS_COMPSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); - if (size > 0) - { - preedit_string_utf16_length = size / sizeof(WCHAR); - preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = TRUE; - } - } - - if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); - if (size > 0) - { - const LPDWORD data = new DWORD[size / sizeof(DWORD)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); - if (size >= sizeof(DWORD) * 2 - && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) - { - preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); - preedit_segment_lengths[i] = length; - offset += length; - } - } - delete[] data; - } - } - - if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); - if (size > 0) - { - const LPBYTE data = new BYTE[size / sizeof(BYTE)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); - if (size == preedit_string_utf16_length) - { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) - { - preedit_standouts[i] = TRUE; - } - offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); - } - } - delete[] data; - } - } - - S32 caret_position = preedit_string.length(); - if (indexes & GCS_CURSORPOS) - { - const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); - if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) - { - caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); - } - } - - if (indexes == 0) - { - // I'm not sure this condition really happens, but - // Windows SDK document says it is an indication - // of "reset everything." - needs_update = TRUE; - } - - LLWinImm::releaseContext(mWindowHandle, himc); - - // Step II: Update the active preeditor. - - if (needs_update) - { + BOOL needs_update = FALSE; + LLWString result_string; + LLWString preedit_string; + S32 preedit_string_utf16_length = 0; + LLPreeditor::segment_lengths_t preedit_segment_lengths; + LLPreeditor::standouts_t preedit_standouts; + + // Step I: Receive details of preedits from IME. + + HIMC himc = LLWinImm::getContext(mWindowHandle); + + if (indexes & GCS_RESULTSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); + if (size > 0) + { + result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = TRUE; + } + } + + if (indexes & GCS_COMPSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); + if (size > 0) + { + preedit_string_utf16_length = size / sizeof(WCHAR); + preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = TRUE; + } + } + + if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); + if (size > 0) + { + const LPDWORD data = new DWORD[size / sizeof(DWORD)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); + if (size >= sizeof(DWORD) * 2 + && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) + { + preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); + preedit_segment_lengths[i] = length; + offset += length; + } + } + delete[] data; + } + } + + if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); + if (size > 0) + { + const LPBYTE data = new BYTE[size / sizeof(BYTE)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); + if (size == preedit_string_utf16_length) + { + preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) + { + preedit_standouts[i] = TRUE; + } + offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); + } + } + delete[] data; + } + } + + S32 caret_position = preedit_string.length(); + if (indexes & GCS_CURSORPOS) + { + const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); + if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) + { + caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); + } + } + + if (indexes == 0) + { + // I'm not sure this condition really happens, but + // Windows SDK document says it is an indication + // of "reset everything." + needs_update = TRUE; + } + + LLWinImm::releaseContext(mWindowHandle, himc); + + // Step II: Update the active preeditor. + + if (needs_update) + { if (preedit_string.length() != 0 || result_string.length() != 0) { mPreeditor->resetPreedit(); } - if (result_string.length() > 0) - { - for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) - { - mPreeditor->handleUnicodeCharHere(*i); - } - } - - if (preedit_string.length() == 0) - { - preedit_segment_lengths.clear(); - preedit_standouts.clear(); - } - else - { - if (preedit_segment_lengths.size() == 0) - { - preedit_segment_lengths.assign(1, preedit_string.length()); - } - if (preedit_standouts.size() == 0) - { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); - } - } - mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); - - // Some IME doesn't query char position after WM_IME_COMPOSITION, - // so we need to update them actively. - updateLanguageTextInputArea(); - } + if (result_string.length() > 0) + { + for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) + { + mPreeditor->handleUnicodeCharHere(*i); + } + } + + if (preedit_string.length() == 0) + { + preedit_segment_lengths.clear(); + preedit_standouts.clear(); + } + else + { + if (preedit_segment_lengths.size() == 0) + { + preedit_segment_lengths.assign(1, preedit_string.length()); + } + if (preedit_standouts.size() == 0) + { + preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + } + } + mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); + + // Some IME doesn't query char position after WM_IME_COMPOSITION, + // so we need to update them actively. + updateLanguageTextInputArea(); + } } // Given a text and a focus range, find_context finds and returns a @@ -4275,24 +4282,24 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) { - static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. + static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. - const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); - S32 end = focus + focus_length; - while (end < e && '\n' != wtext[end]) - { - end++; - } + const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); + S32 end = focus + focus_length; + while (end < e && '\n' != wtext[end]) + { + end++; + } - const S32 s = llmax(0, focus - CONTEXT_EXCESS); - S32 start = focus; - while (start > s && '\n' != wtext[start - 1]) - { - --start; - } + const S32 s = llmax(0, focus - CONTEXT_EXCESS); + S32 start = focus; + while (start > s && '\n' != wtext[start - 1]) + { + --start; + } - *offset = start; - return wtext.substr(start, end - start); + *offset = start; + return wtext.substr(start, end - start); } // final stage of handling drop requests - both from WM_DROPFILES message @@ -4300,7 +4307,7 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ) { ASSERT_MAIN_THREAD(); - return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); + return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); } // Handle WM_IME_REQUEST message. @@ -4310,153 +4317,153 @@ LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( cons BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result) { - if ( mPreeditor ) - { - switch (request) - { - case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx - { - LLCoordGL caret_coord; - LLRect preedit_bounds; - mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); - - CANDIDATEFORM *const form = (CANDIDATEFORM *)param; - DWORD const dwIndex = form->dwIndex; - fillCandidateForm(caret_coord, preedit_bounds, form); - form->dwIndex = dwIndex; - - *result = 1; - return TRUE; - } - case IMR_QUERYCHARPOSITION: - { - IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; - - // char_position->dwCharPos counts in number of - // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the - // number to getPreeditLocation. - - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - LLCoordGL caret_coord; - LLRect preedit_bounds, text_control; - const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); - - if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) - { - LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; - return FALSE; - } - - fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); - - *result = 1; - return TRUE; - } - case IMR_COMPOSITIONFONT: - { - fillCompositionLogfont((LOGFONT *)param); - - *result = 1; - return TRUE; - } - case IMR_RECONVERTSTRING: - { - mPreeditor->resetPreedit(); - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 select, select_length; - mPreeditor->getSelectionRange(&select, &select_length); - - S32 context_offset; - const LLWString context = find_context(wtext, select, select_length, &context_offset); - - RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; - const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); - if (reconvert_string) - { - if (select_length == 0) - { - // Let the IME to decide the reconversion range, and - // adjust the reconvert_string structure accordingly. - HIMC himc = LLWinImm::getContext(mWindowHandle); - const BOOL adjusted = LLWinImm::setCompositionString(himc, - SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - if (adjusted) - { - const llutf16string & text_utf16 = wstring_to_utf16str(context); - const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); - const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; - select = utf16str_wstring_length(text_utf16, new_preedit_start); - select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; - select += context_offset; - } - } - mPreeditor->markAsPreedit(select, select_length); - } - - *result = size; - return TRUE; - } - case IMR_CONFIRMRECONVERTSTRING: - { - *result = FALSE; - return TRUE; - } - case IMR_DOCUMENTFEED: - { - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - - S32 context_offset; - LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); - preedit -= context_offset; - preedit_length = llmin(preedit_length, (S32)context.length() - preedit); - if (preedit_length > 0 && preedit >= 0) - { - // IMR_DOCUMENTFEED may be called when we have an active preedit. - // We should pass the context string *excluding* the preedit string. - // Otherwise, some IME are confused. - context.erase(preedit, preedit_length); - } - - RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; - *result = fillReconvertString(context, preedit, 0, reconvert_string); - return TRUE; - } - default: - return FALSE; - } - } - - return FALSE; + if ( mPreeditor ) + { + switch (request) + { + case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx + { + LLCoordGL caret_coord; + LLRect preedit_bounds; + mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); + + CANDIDATEFORM *const form = (CANDIDATEFORM *)param; + DWORD const dwIndex = form->dwIndex; + fillCandidateForm(caret_coord, preedit_bounds, form); + form->dwIndex = dwIndex; + + *result = 1; + return TRUE; + } + case IMR_QUERYCHARPOSITION: + { + IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; + + // char_position->dwCharPos counts in number of + // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the + // number to getPreeditLocation. + + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + LLCoordGL caret_coord; + LLRect preedit_bounds, text_control; + const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); + + if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) + { + LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; + return FALSE; + } + + fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); + + *result = 1; + return TRUE; + } + case IMR_COMPOSITIONFONT: + { + fillCompositionLogfont((LOGFONT *)param); + + *result = 1; + return TRUE; + } + case IMR_RECONVERTSTRING: + { + mPreeditor->resetPreedit(); + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 select, select_length; + mPreeditor->getSelectionRange(&select, &select_length); + + S32 context_offset; + const LLWString context = find_context(wtext, select, select_length, &context_offset); + + RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; + const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); + if (reconvert_string) + { + if (select_length == 0) + { + // Let the IME to decide the reconversion range, and + // adjust the reconvert_string structure accordingly. + HIMC himc = LLWinImm::getContext(mWindowHandle); + const BOOL adjusted = LLWinImm::setCompositionString(himc, + SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + if (adjusted) + { + const llutf16string & text_utf16 = wstring_to_utf16str(context); + const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); + const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; + select = utf16str_wstring_length(text_utf16, new_preedit_start); + select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; + select += context_offset; + } + } + mPreeditor->markAsPreedit(select, select_length); + } + + *result = size; + return TRUE; + } + case IMR_CONFIRMRECONVERTSTRING: + { + *result = FALSE; + return TRUE; + } + case IMR_DOCUMENTFEED: + { + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + + S32 context_offset; + LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); + preedit -= context_offset; + preedit_length = llmin(preedit_length, (S32)context.length() - preedit); + if (preedit_length > 0 && preedit >= 0) + { + // IMR_DOCUMENTFEED may be called when we have an active preedit. + // We should pass the context string *excluding* the preedit string. + // Otherwise, some IME are confused. + context.erase(preedit, preedit_length); + } + + RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; + *result = fillReconvertString(context, preedit, 0, reconvert_string); + return TRUE; + } + default: + return FALSE; + } + } + + return FALSE; } //static void LLWindowWin32::setDPIAwareness() { - HMODULE hShcore = LoadLibrary(L"shcore.dll"); - if (hShcore != NULL) - { - SetProcessDpiAwarenessType pSPDA; - pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); - if (pSPDA) - { - - HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); - if (hr != S_OK) - { - LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; - } - } - FreeLibrary(hShcore); - } - else - { - LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; - } + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + if (hShcore != NULL) + { + SetProcessDpiAwarenessType pSPDA; + pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); + if (pSPDA) + { + + HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); + if (hr != S_OK) + { + LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } } void* LLWindowWin32::getDirectInput8() @@ -4483,76 +4490,76 @@ bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_c F32 LLWindowWin32::getSystemUISize() { - F32 scale_value = 1.f; - HWND hWnd = (HWND)getPlatformWindow(); - HDC hdc = GetDC(hWnd); - HMONITOR hMonitor; - HANDLE hProcess = GetCurrentProcess(); - PROCESS_DPI_AWARENESS dpi_awareness; - - HMODULE hShcore = LoadLibrary(L"shcore.dll"); - - if (hShcore != NULL) - { - GetProcessDpiAwarenessType pGPDA; - pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); - GetDpiForMonitorType pGDFM; - pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); - if (pGPDA != NULL && pGDFM != NULL) - { - pGPDA(hProcess, &dpi_awareness); - if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) - { - POINT pt; - UINT dpix = 0, dpiy = 0; - HRESULT hr = E_FAIL; - RECT rect; - - GetWindowRect(hWnd, &rect); - // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor - pt.x = (rect.left + rect.right) / 2; - pt.y = (rect.top + rect.bottom) / 2; - hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); - hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); - if (hr == S_OK) - { - scale_value = F32(dpix) / F32(USER_DEFAULT_SCREEN_DPI); - } - else - { - LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; - scale_value = 1.0f; - } - } - else - { - LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; - scale_value = 1.0f; - } - } - FreeLibrary(hShcore); - } - else - { - LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; - scale_value = F32(GetDeviceCaps(hdc, LOGPIXELSX)) / F32(USER_DEFAULT_SCREEN_DPI); - } - - ReleaseDC(hWnd, hdc); - return scale_value; + F32 scale_value = 1.f; + HWND hWnd = (HWND)getPlatformWindow(); + HDC hdc = GetDC(hWnd); + HMONITOR hMonitor; + HANDLE hProcess = GetCurrentProcess(); + PROCESS_DPI_AWARENESS dpi_awareness; + + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + + if (hShcore != NULL) + { + GetProcessDpiAwarenessType pGPDA; + pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); + GetDpiForMonitorType pGDFM; + pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); + if (pGPDA != NULL && pGDFM != NULL) + { + pGPDA(hProcess, &dpi_awareness); + if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) + { + POINT pt; + UINT dpix = 0, dpiy = 0; + HRESULT hr = E_FAIL; + RECT rect; + + GetWindowRect(hWnd, &rect); + // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor + pt.x = (rect.left + rect.right) / 2; + pt.y = (rect.top + rect.bottom) / 2; + hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); + if (hr == S_OK) + { + scale_value = F32(dpix) / F32(USER_DEFAULT_SCREEN_DPI); + } + else + { + LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + else + { + LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; + scale_value = F32(GetDeviceCaps(hdc, LOGPIXELSX)) / F32(USER_DEFAULT_SCREEN_DPI); + } + + ReleaseDC(hWnd, hdc); + return scale_value; } //static std::vector<std::string> LLWindowWin32::getDisplaysResolutionList() -{ - return sMonitorInfo.getResolutionsList(); +{ + return sMonitorInfo.getResolutionsList(); } //static std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() { - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector<std::string>(); + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector<std::string>(); } U32 LLWindowWin32::getAvailableVRAMMegabytes() @@ -4736,7 +4743,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) { mD3D = Direct3DCreate9(D3D_SDK_VERSION); - + D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); @@ -4744,7 +4751,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); - + if (FAILED(res)) { LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL; @@ -4801,7 +4808,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() U32 afr_mb = info.AvailableForReservation / 1024 / 1024; // correct for systems that misreport budget if (budget_mb == 0) - { + { // fall back to available for reservation clamped between 512MB and 2GB budget_mb = llclamp(afr_mb, (U32) 512, (U32) 2048); } @@ -4822,7 +4829,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() } U32 target_mb = budget_mb; - if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free + if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free { target_mb -= 2048; } @@ -4834,7 +4841,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0; #if 0 - + F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb; LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024 << "\nBudget: " << info.Budget / 1024 / 1024 @@ -4908,7 +4915,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() //process any pending functions getQueue().runPending(); } - + // update available vram once every 3 seconds static LLFrameTimer vramTimer; if (vramTimer.getElapsedTimeF32() > 3.f) @@ -5064,11 +5071,11 @@ void LLWindowWin32::updateWindowRect() //called from window thread RECT rect; RECT client_rect; - + if (GetWindowRect(mWindowHandle, &rect) && GetClientRect(mWindowHandle, &client_rect)) { - post([=] + post([=] { mRect = rect; mClientRect = client_rect; diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 6598215f97..320c1c8b88 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -1,25 +1,25 @@ -/** +/** * @file llwindowwin32.h * @brief Windows implementation of LLWindow class * * $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$ */ @@ -45,90 +45,92 @@ typedef void (*LLW32MsgCallback)(const MSG &msg); class LLWindowWin32 : public LLWindow { public: - /*virtual*/ void show(); - /*virtual*/ void hide(); - /*virtual*/ void close(); - /*virtual*/ BOOL getVisible(); - /*virtual*/ BOOL getMinimized(); - /*virtual*/ BOOL getMaximized(); - /*virtual*/ BOOL maximize(); - /*virtual*/ void minimize(); - /*virtual*/ void restore(); - /*virtual*/ BOOL getFullscreen(); - /*virtual*/ BOOL getPosition(LLCoordScreen *position); - /*virtual*/ BOOL getSize(LLCoordScreen *size); - /*virtual*/ BOOL getSize(LLCoordWindow *size); - /*virtual*/ BOOL setPosition(LLCoordScreen position); - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); - /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ void show(); + /*virtual*/ void hide(); + /*virtual*/ void close(); + /*virtual*/ BOOL getVisible(); + /*virtual*/ BOOL getMinimized(); + /*virtual*/ BOOL getMaximized(); + /*virtual*/ BOOL maximize(); + /*virtual*/ void minimize(); + /*virtual*/ void restore(); + /*virtual*/ BOOL getFullscreen(); + /*virtual*/ BOOL getPosition(LLCoordScreen *position); + /*virtual*/ BOOL getSize(LLCoordScreen *size); + /*virtual*/ BOOL getSize(LLCoordWindow *size); + /*virtual*/ BOOL setPosition(LLCoordScreen position); + /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); + /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL); /*virtual*/ void setTitle(const std::string title); void* createSharedContext() override; void makeContextCurrent(void* context) override; void destroySharedContext(void* context) override; /*virtual*/ void toggleVSync(bool enable_vsync); - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); + /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); + /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta); - /*virtual*/ void showCursor(); - /*virtual*/ void hideCursor(); - /*virtual*/ void showCursorFromMouseMove(); - /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ BOOL isCursorHidden(); - /*virtual*/ void updateCursor(); - /*virtual*/ ECursorType getCursor() const; - /*virtual*/ void captureMouse(); - /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( BOOL b ); - /*virtual*/ BOOL isClipboardTextAvailable(); - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); - /*virtual*/ BOOL copyTextToClipboard(const LLWString &src); - /*virtual*/ void flashIcon(F32 seconds); - /*virtual*/ F32 getGamma(); - /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma - /*virtual*/ void setFSAASamples(const U32 fsaa_samples); - /*virtual*/ U32 getFSAASamples(); - /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) - /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput(); - /*virtual*/ void delayInputProcessing(); - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; - - // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + /*virtual*/ void showCursor(); + /*virtual*/ void hideCursor(); + /*virtual*/ void showCursorFromMouseMove(); + /*virtual*/ void hideCursorUntilMouseMove(); + /*virtual*/ BOOL isCursorHidden(); + /*virtual*/ void updateCursor(); + /*virtual*/ ECursorType getCursor() const; + /*virtual*/ void captureMouse(); + /*virtual*/ void releaseMouse(); + /*virtual*/ void setMouseClipping( BOOL b ); + /*virtual*/ BOOL isClipboardTextAvailable(); + /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); + /*virtual*/ BOOL copyTextToClipboard(const LLWString &src); + /*virtual*/ void flashIcon(F32 seconds); + /*virtual*/ F32 getGamma(); + /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma + /*virtual*/ void setFSAASamples(const U32 fsaa_samples); + /*virtual*/ U32 getFSAASamples(); + /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } + /*virtual*/ void gatherInput(); + /*virtual*/ void delayInputProcessing(); + /*virtual*/ void swapBuffers(); + /*virtual*/ void restoreGLContext() {}; + + // handy coordinate space conversion routines + /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); + /*virtual*/ F32 getNativeAspectRatio(); + /*virtual*/ F32 getPixelAspectRatio(); + /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } U32 getAvailableVRAMMegabytes() override; + + /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); - /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); + /*virtual*/ void *getPlatformWindow(); + /*virtual*/ void bringToFront(); + /*virtual*/ void focusClient(); - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); - /*virtual*/ void focusClient(); + /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); + /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); + /*virtual*/ void updateLanguageTextInputArea(); + /*virtual*/ void interruptLanguageTextInput(); + /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); - /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); - /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); - /*virtual*/ void updateLanguageTextInputArea(); - /*virtual*/ void interruptLanguageTextInput(); - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + void openFolder(const std::string &path) override; - /*virtual*/ F32 getSystemUISize(); + /*virtual*/ F32 getSystemUISize(); - LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); + LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); - static std::vector<std::string> getDisplaysResolutionList(); - static std::vector<std::string> getDynamicFallbackFontList(); - static void setDPIAwareness(); + static std::vector<std::string> getDisplaysResolutionList(); + static std::vector<std::string> getDynamicFallbackFontList(); + static void setDPIAwareness(); /*virtual*/ void* getDirectInput8(); /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata); @@ -136,67 +138,67 @@ public: U32 getRawWParam() { return mRawWParam; } protected: - LLWindowWin32(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); - ~LLWindowWin32(); - - void initCursors(); - void initInputDevices(); - HCURSOR loadColorCursor(LPCTSTR name); - BOOL isValid(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - virtual LLSD getNativeKeyData(); - - // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - - // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); - - // Restore the display resolution to its value before we ran the app. - BOOL resetDisplayResolution(); - - BOOL shouldPostQuit() { return mPostQuit; } - - void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); - void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); - void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); - void fillCompositionLogfont(LOGFONT *logfont); - U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); - void handleStartCompositionMessage(); - void handleCompositionMessage(U32 indexes); - BOOL handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); + LLWindowWin32(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, + BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); + ~LLWindowWin32(); + + void initCursors(); + void initInputDevices(); + HCURSOR loadColorCursor(LPCTSTR name); + BOOL isValid(); + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + virtual LLSD getNativeKeyData(); + + // Changes display resolution. Returns true if successful + BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + + // Go back to last fullscreen display resolution. + BOOL setFullscreenResolution(); + + // Restore the display resolution to its value before we ran the app. + BOOL resetDisplayResolution(); + + BOOL shouldPostQuit() { return mPostQuit; } + + void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); + void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); + void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); + void fillCompositionLogfont(LOGFONT *logfont); + U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); + void handleStartCompositionMessage(); + void handleCompositionMessage(U32 indexes); + BOOL handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); protected: - // - // Platform specific methods - // + // + // Platform specific methods + // - BOOL getClientRectInScreenSpace(RECT* rectp); - void updateJoystick( ); + BOOL getClientRectInScreenSpace(RECT* rectp); + void updateJoystick( ); - static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); - static BOOL CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); + static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); + static BOOL CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); - // - // Platform specific variables - // - WCHAR *mWindowTitle; - WCHAR *mWindowClassName; + // + // Platform specific variables + // + WCHAR *mWindowTitle; + WCHAR *mWindowClassName; - HWND mWindowHandle = 0; // window handle - HGLRC mhRC = 0; // OpenGL rendering context - HDC mhDC = 0; // Windows Device context handle - HINSTANCE mhInstance; // handle to application instance - RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - WPARAM mLastSizeWParam; - F32 mOverrideAspectRatio; - F32 mNativeAspectRatio; + HWND mWindowHandle = 0; // window handle + HGLRC mhRC = 0; // OpenGL rendering context + HDC mhDC = 0; // Windows Device context handle + HINSTANCE mhInstance; // handle to application instance + RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + WPARAM mLastSizeWParam; + F32 mOverrideAspectRatio; + F32 mNativeAspectRatio; - HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors + HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors LLCoordWindow mCursorPosition; // mouse cursor position, should only be mutated on main thread LLMutex mRawMouseMutex; RAWINPUTDEVICE mRawMouse; @@ -206,86 +208,86 @@ protected: MASK mMouseMask; - static BOOL sIsClassRegistered; // has the window class been registered? + static BOOL sIsClassRegistered; // has the window class been registered? - F32 mCurrentGamma; - U32 mFSAASamples; + F32 mCurrentGamma; + U32 mFSAASamples; U32 mMaxCores; // for debugging only -- maximum number of CPU cores to use, or 0 for no limit F32 mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6) - WORD mPrevGammaRamp[3][256]; - WORD mCurrentGammaRamp[3][256]; - BOOL mCustomGammaSet; - - LPWSTR mIconResource; - BOOL mInputProcessingPaused; - - // The following variables are for Language Text Input control. - // They are all static, since one context is shared by all LLWindowWin32 - // instances. - static BOOL sLanguageTextInputAllowed; - static BOOL sWinIMEOpened; - static HKL sWinInputLocale; - static DWORD sWinIMEConversionMode; - static DWORD sWinIMESentenceMode; - static LLCoordWindow sWinIMEWindowPosition; - LLCoordGL mLanguageTextInputPointGL; - LLRect mLanguageTextInputAreaGL; - - LLPreeditor *mPreeditor; - - LLDragDropWin32* mDragDrop; - - U32 mKeyCharCode; - U32 mKeyScanCode; - U32 mKeyVirtualKey; - U32 mRawMsg; - U32 mRawWParam; - U32 mRawLParam; - - BOOL mMouseVanish; + WORD mPrevGammaRamp[3][256]; + WORD mCurrentGammaRamp[3][256]; + BOOL mCustomGammaSet; + + LPWSTR mIconResource; + BOOL mInputProcessingPaused; + + // The following variables are for Language Text Input control. + // They are all static, since one context is shared by all LLWindowWin32 + // instances. + static BOOL sLanguageTextInputAllowed; + static BOOL sWinIMEOpened; + static HKL sWinInputLocale; + static DWORD sWinIMEConversionMode; + static DWORD sWinIMESentenceMode; + static LLCoordWindow sWinIMEWindowPosition; + LLCoordGL mLanguageTextInputPointGL; + LLRect mLanguageTextInputAreaGL; + + LLPreeditor *mPreeditor; + + LLDragDropWin32* mDragDrop; + + U32 mKeyCharCode; + U32 mKeyScanCode; + U32 mKeyVirtualKey; + U32 mRawMsg; + U32 mRawWParam; + U32 mRawLParam; + + BOOL mMouseVanish; // Cached values of GetWindowRect and GetClientRect to be used by app thread void updateWindowRect(); - RECT mRect; + RECT mRect; RECT mClientRect; - struct LLWindowWin32Thread; - LLWindowWin32Thread* mWindowThread = nullptr; - LLThreadSafeQueue<std::function<void()>> mFunctionQueue; - LLThreadSafeQueue<std::function<void()>> mMouseQueue; - void post(const std::function<void()>& func); - void postMouseButtonEvent(const std::function<void()>& func); - void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); - void kickWindowThread(HWND windowHandle=0); + struct LLWindowWin32Thread; + LLWindowWin32Thread* mWindowThread = nullptr; + LLThreadSafeQueue<std::function<void()>> mFunctionQueue; + LLThreadSafeQueue<std::function<void()>> mMouseQueue; + void post(const std::function<void()>& func); + void postMouseButtonEvent(const std::function<void()>& func); + void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); + void kickWindowThread(HWND windowHandle=0); - friend class LLWindowManager; + friend class LLWindowManager; }; class LLSplashScreenWin32 : public LLSplashScreen { public: - LLSplashScreenWin32(); - virtual ~LLSplashScreenWin32(); + LLSplashScreenWin32(); + virtual ~LLSplashScreenWin32(); - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); + /*virtual*/ void showImpl(); + /*virtual*/ void updateImpl(const std::string& mesg); + /*virtual*/ void hideImpl(); #if LL_WINDOWS - static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param); + static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, + WPARAM w_param, LPARAM l_param); #endif private: #if LL_WINDOWS - HWND mWindow; + HWND mWindow; #endif }; extern LLW32MsgCallback gAsyncMsgCallback; extern LPWSTR gIconResource; -static void handleMessage( const MSG& msg ); +static void handleMessage( const MSG& msg ); S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 264bf0c5b4..a2178ed77d 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcontrol.cpp * @brief Holds global state for viewer. * * $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$ */ @@ -109,60 +109,60 @@ std::string SETTINGS_PROFILE = "settings_profile.log"; bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) { - bool result = false; - switch (mType) - { - case TYPE_U32: - case TYPE_S32: - result = a.asInteger() == b.asInteger(); - break; - case TYPE_BOOLEAN: - result = a.asBoolean() == b.asBoolean(); - break; - case TYPE_F32: - result = a.asReal() == b.asReal(); - break; - case TYPE_VEC3: - case TYPE_VEC3D: - result = LLVector3d(a) == LLVector3d(b); - break; - case TYPE_QUAT: - result = LLQuaternion(a) == LLQuaternion(b); - break; - case TYPE_RECT: - result = LLRect(a) == LLRect(b); - break; - case TYPE_COL4: - result = LLColor4(a) == LLColor4(b); - break; - case TYPE_COL3: - result = LLColor3(a) == LLColor3(b); - break; - case TYPE_STRING: - result = a.asString() == b.asString(); - break; - default: - break; - } - - return result; + bool result = false; + switch (mType) + { + case TYPE_U32: + case TYPE_S32: + result = a.asInteger() == b.asInteger(); + break; + case TYPE_BOOLEAN: + result = a.asBoolean() == b.asBoolean(); + break; + case TYPE_F32: + result = a.asReal() == b.asReal(); + break; + case TYPE_VEC3: + case TYPE_VEC3D: + result = LLVector3d(a) == LLVector3d(b); + break; + case TYPE_QUAT: + result = LLQuaternion(a) == LLQuaternion(b); + break; + case TYPE_RECT: + result = LLRect(a) == LLRect(b); + break; + case TYPE_COL4: + result = LLColor4(a) == LLColor4(b); + break; + case TYPE_COL3: + result = LLColor3(a) == LLColor3(b); + break; + case TYPE_STRING: + result = a.asString() == b.asString(); + break; + default: + break; + } + + return result; } LLControlVariable::LLControlVariable(const std::string& name, eControlType type, - LLSD initial, const std::string& comment, - ePersist persist, bool hidefromsettingseditor) - : mName(name), - mComment(comment), - mType(type), - mPersist(persist), - mHideFromSettingsEditor(hidefromsettingseditor) -{ - if ((persist != PERSIST_NO) && mComment.empty()) - { - LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; - } - //Push back versus setValue'ing here, since we don't want to call a signal yet - mValues.push_back(initial); + LLSD initial, const std::string& comment, + ePersist persist, bool hidefromsettingseditor) + : mName(name), + mComment(comment), + mType(type), + mPersist(persist), + mHideFromSettingsEditor(hidefromsettingseditor) +{ + if ((persist != PERSIST_NO) && mComment.empty()) + { + LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; + } + //Push back versus setValue'ing here, since we don't want to call a signal yet + mValues.push_back(initial); } @@ -173,70 +173,70 @@ LLControlVariable::~LLControlVariable() LLSD LLControlVariable::getComparableValue(const LLSD& value) { - // *FIX:MEP - The following is needed to make the LLSD::ImplString - // work with boolean controls... - LLSD storable_value; - if(TYPE_BOOLEAN == type() && value.isString()) - { - BOOL temp; - if(LLStringUtil::convertToBOOL(value.asString(), temp)) - { - storable_value = (bool)temp; - } - else - { - storable_value = false; - } - } - else if (TYPE_LLSD == type() && value.isString()) - { - LLPointer<LLSDNotationParser> parser = new LLSDNotationParser; - LLSD result; - std::stringstream value_stream(value.asString()); - if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) - { - storable_value = result; - } - else - { - storable_value = value; - } - } - else - { - storable_value = value; - } - - return storable_value; + // *FIX:MEP - The following is needed to make the LLSD::ImplString + // work with boolean controls... + LLSD storable_value; + if(TYPE_BOOLEAN == type() && value.isString()) + { + BOOL temp; + if(LLStringUtil::convertToBOOL(value.asString(), temp)) + { + storable_value = (bool)temp; + } + else + { + storable_value = false; + } + } + else if (TYPE_LLSD == type() && value.isString()) + { + LLPointer<LLSDNotationParser> parser = new LLSDNotationParser; + LLSD result; + std::stringstream value_stream(value.asString()); + if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) + { + storable_value = result; + } + else + { + storable_value = value; + } + } + else + { + storable_value = value; + } + + return storable_value; } void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) { - if (mValidateSignal(this, new_value) == false) - { - // can not set new value, exit - return; - } - - LLSD storable_value = getComparableValue(new_value); - LLSD original_value = getValue(); - bool value_changed = llsd_compare(original_value, storable_value) == FALSE; - if(saved_value) - { - // If we're going to save this value, return to default but don't fire - resetToDefault(false); - if (llsd_compare(mValues.back(), storable_value) == FALSE) - { - mValues.push_back(storable_value); - } - } + if (mValidateSignal(this, new_value) == false) + { + // can not set new value, exit + return; + } + + LLSD storable_value = getComparableValue(new_value); + LLSD original_value = getValue(); + bool value_changed = llsd_compare(original_value, storable_value) == FALSE; + if(saved_value) + { + // If we're going to save this value, return to default but don't fire + resetToDefault(false); + if (llsd_compare(mValues.back(), storable_value) == FALSE) + { + mValues.push_back(storable_value); + } + } else { // This is an unsaved value. Its needs to reside at - // mValues[2] (or greater). It must not affect + // mValues[2] (or greater). It must not affect // the result of getSaveValue() - if (llsd_compare(mValues.back(), storable_value) == FALSE) - { + if (llsd_compare(mValues.back(), storable_value) == FALSE) + { while(mValues.size() > 2) { // Remove any unsaved values. @@ -251,107 +251,107 @@ void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) // Add the 'un-save' value. mValues.push_back(storable_value); - } + } } if(value_changed) { - firePropertyChanged(original_value); + firePropertyChanged(original_value); } } void LLControlVariable::setDefaultValue(const LLSD& value) { - // Set the control variables value and make it - // the default value. If the active value is changed, - // send the signal. - // *NOTE: Default values are not saved, only read. + // Set the control variables value and make it + // the default value. If the active value is changed, + // send the signal. + // *NOTE: Default values are not saved, only read. - LLSD comparable_value = getComparableValue(value); - LLSD original_value = getValue(); - bool value_changed = (llsd_compare(original_value, comparable_value) == FALSE); - resetToDefault(false); - mValues[0] = comparable_value; - if(value_changed) - { - firePropertyChanged(original_value); - } + LLSD comparable_value = getComparableValue(value); + LLSD original_value = getValue(); + bool value_changed = (llsd_compare(original_value, comparable_value) == FALSE); + resetToDefault(false); + mValues[0] = comparable_value; + if(value_changed) + { + firePropertyChanged(original_value); + } } void LLControlVariable::setPersist(ePersist state) { - mPersist = state; + mPersist = state; } void LLControlVariable::setHiddenFromSettingsEditor(bool hide) { - mHideFromSettingsEditor = hide; + mHideFromSettingsEditor = hide; } void LLControlVariable::setComment(const std::string& comment) { - mComment = comment; + mComment = comment; } void LLControlVariable::resetToDefault(bool fire_signal) { - //The first setting is always the default - //Pop to it and fire off the listener - LLSD originalValue = mValues.back(); + //The first setting is always the default + //Pop to it and fire off the listener + LLSD originalValue = mValues.back(); - while(mValues.size() > 1) - { - mValues.pop_back(); - } - - if(fire_signal) - { - firePropertyChanged(originalValue); - } + while(mValues.size() > 1) + { + mValues.pop_back(); + } + + if(fire_signal) + { + firePropertyChanged(originalValue); + } } bool LLControlVariable::shouldSave(bool nondefault_only) { - // This method is used to decide whether we should save a given - // variable. Two of the three values of mPersist are easy. - if (mPersist == PERSIST_NO) - return false; + // This method is used to decide whether we should save a given + // variable. Two of the three values of mPersist are easy. + if (mPersist == PERSIST_NO) + return false; - if (mPersist == PERSIST_ALWAYS) - return true; + if (mPersist == PERSIST_ALWAYS) + return true; - // PERSIST_NONDFT - // If caller doesn't need us to filter, just save. - if (! nondefault_only) - return true; + // PERSIST_NONDFT + // If caller doesn't need us to filter, just save. + if (! nondefault_only) + return true; - // PERSIST_NONDFT: caller only wants us to save this variable if its value - // differs from default. - if (isDefault()) // never been altered - return false; + // PERSIST_NONDFT: caller only wants us to save this variable if its value + // differs from default. + if (isDefault()) // never been altered + return false; - // We've set at least one other value: compare it to default. Save only if - // they differ. - return ! llsd_compare(getSaveValue(), getDefault()); + // We've set at least one other value: compare it to default. Save only if + // they differ. + return ! llsd_compare(getSaveValue(), getDefault()); } LLSD LLControlVariable::getSaveValue() const { - //The first level of the stack is default - //We assume that the second level is user preferences that should be saved - if(mValues.size() > 1) return mValues[1]; - return mValues[0]; + //The first level of the stack is default + //We assume that the second level is user preferences that should be saved + if(mValues.size() > 1) return mValues[1]; + return mValues[0]; } LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name) { - if (mSettingsProfile) - { - incrCount(name); - } + if (mSettingsProfile) + { + incrCount(name); + } - ctrl_name_table_t::iterator iter = mNameTable.find(name); - return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second; + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second; } @@ -373,296 +373,296 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32" }; LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker<LLControlGroup, std::string>(name), - mSettingsProfile(false) +: LLInstanceTracker<LLControlGroup, std::string>(name), + mSettingsProfile(false) { - if (NULL != getenv("LL_SETTINGS_PROFILE")) - { - mSettingsProfile = true; - } + if (NULL != getenv("LL_SETTINGS_PROFILE")) + { + mSettingsProfile = true; + } } LLControlGroup::~LLControlGroup() { - cleanup(); + cleanup(); } static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs) { - return lhs.second > rhs.second; + return lhs.second > rhs.second; }; void LLControlGroup::cleanup() { - if(mSettingsProfile && getCount.size() != 0) - { - std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); - LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ - if(!out) - { - LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; - } - else - { - F64 end_time = LLTimer::getTotalSeconds(); - U32 total_seconds = (U32)(end_time - start_time); - - std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds); - std::ostringstream data_msg; - - data_msg << msg; - size_t data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) - { - LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; - } - - for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) - { - getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); - } - sort(getCount_v.begin(), getCount_v.end(), compareRoutine); - - for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) - { - U32 access_rate = 0; - if (total_seconds != 0) - { - access_rate = iter->second / total_seconds; - } - if (access_rate >= 2) - { - std::ostringstream data_msg; - msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str()); - data_msg << msg << "\n"; - size_t data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) - { - LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; - } - } - } - getCount = LLSD::emptyMap(); - fclose(out); - } - } - - mNameTable.clear(); + if(mSettingsProfile && getCount.size() != 0) + { + std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); + LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ + if(!out) + { + LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; + } + else + { + F64 end_time = LLTimer::getTotalSeconds(); + U32 total_seconds = (U32)(end_time - start_time); + + std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds); + std::ostringstream data_msg; + + data_msg << msg; + size_t data_size = data_msg.str().size(); + if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) + { + LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; + } + + for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) + { + getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); + } + sort(getCount_v.begin(), getCount_v.end(), compareRoutine); + + for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) + { + U32 access_rate = 0; + if (total_seconds != 0) + { + access_rate = iter->second / total_seconds; + } + if (access_rate >= 2) + { + std::ostringstream data_msg; + msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str()); + data_msg << msg << "\n"; + size_t data_size = data_msg.str().size(); + if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) + { + LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; + } + } + } + getCount = LLSD::emptyMap(); + fclose(out); + } + } + + mNameTable.clear(); } eControlType LLControlGroup::typeStringToEnum(const std::string& typestr) { - for(int i = 0; i < (int)TYPE_COUNT; ++i) - { - if(mTypeString[i] == typestr) return (eControlType)i; - } - return (eControlType)-1; + for(int i = 0; i < (int)TYPE_COUNT; ++i) + { + if(mTypeString[i] == typestr) return (eControlType)i; + } + return (eControlType)-1; } std::string LLControlGroup::typeEnumToString(eControlType typeenum) { - return mTypeString[typeenum]; + return mTypeString[typeenum]; } LLControlVariable* LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor) { - LLControlVariable* existing_control = getControl(name); - if (existing_control) - { - if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type)) - { - if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val)) - { - // Sometimes we need to declare a control *after* it has been loaded from a settings file. - LLSD cur_value = existing_control->getValue(); // get the current value - existing_control->setDefaultValue(initial_val); // set the default to the declared value - existing_control->setValue(cur_value); // now set to the loaded value - } - } - else - { - LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; - } - return existing_control; - } - - // if not, create the control and add it to the name table - LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor); - mNameTable[name] = control; - return control; + LLControlVariable* existing_control = getControl(name); + if (existing_control) + { + if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type)) + { + if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val)) + { + // Sometimes we need to declare a control *after* it has been loaded from a settings file. + LLSD cur_value = existing_control->getValue(); // get the current value + existing_control->setDefaultValue(initial_val); // set the default to the declared value + existing_control->setValue(cur_value); // now set to the loaded value + } + } + else + { + LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; + } + return existing_control; + } + + // if not, create the control and add it to the name table + LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor); + mNameTable[name] = control; + return control; } LLControlVariable* LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist); + return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_S32, initial_val, comment, persist); + return declareControl(name, TYPE_S32, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_F32, initial_val, comment, persist); + return declareControl(name, TYPE_F32, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareBOOL(const std::string& name, const BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist); + return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_STRING, initial_val, comment, persist); + return declareControl(name, TYPE_STRING, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) { - return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) { - return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) { - return declareControl(name, TYPE_LLSD, initial_val, comment, persist); + return declareControl(name, TYPE_LLSD, initial_val, comment, persist); } void LLControlGroup::incrCount(const std::string& name) { - if (0.0 == start_time) - { - start_time = LLTimer::getTotalSeconds(); - } - getCount[name] = getCount[name].asInteger() + 1; + if (0.0 == start_time) + { + start_time = LLTimer::getTotalSeconds(); + } + getCount[name] = getCount[name].asInteger() + 1; } BOOL LLControlGroup::getBOOL(const std::string& name) { - return (BOOL)get<bool>(name); + return (BOOL)get<bool>(name); } S32 LLControlGroup::getS32(const std::string& name) { - return get<S32>(name); + return get<S32>(name); } U32 LLControlGroup::getU32(const std::string& name) { - return get<U32>(name); + return get<U32>(name); } F32 LLControlGroup::getF32(const std::string& name) { - return get<F32>(name); + return get<F32>(name); } std::string LLControlGroup::getString(const std::string& name) { - return get<std::string>(name); + return get<std::string>(name); } LLWString LLControlGroup::getWString(const std::string& name) { - return get<LLWString>(name); + return get<LLWString>(name); } std::string LLControlGroup::getText(const std::string& name) { - std::string utf8_string = getString(name); - LLStringUtil::replaceChar(utf8_string, '^', '\n'); - LLStringUtil::replaceChar(utf8_string, '%', ' '); - return (utf8_string); + std::string utf8_string = getString(name); + LLStringUtil::replaceChar(utf8_string, '^', '\n'); + LLStringUtil::replaceChar(utf8_string, '%', ' '); + return (utf8_string); } LLVector3 LLControlGroup::getVector3(const std::string& name) { - return get<LLVector3>(name); + return get<LLVector3>(name); } LLVector3d LLControlGroup::getVector3d(const std::string& name) { - return get<LLVector3d>(name); + return get<LLVector3d>(name); } LLQuaternion LLControlGroup::getQuaternion(const std::string& name) { - return get<LLQuaternion>(name); + return get<LLQuaternion>(name); } LLRect LLControlGroup::getRect(const std::string& name) { - return get<LLRect>(name); + return get<LLRect>(name); } LLColor4 LLControlGroup::getColor(const std::string& name) { - return get<LLColor4>(name); + return get<LLColor4>(name); } LLColor4 LLControlGroup::getColor4(const std::string& name) { - return get<LLColor4>(name); + return get<LLColor4>(name); } LLColor3 LLControlGroup::getColor3(const std::string& name) { - return get<LLColor3>(name); + return get<LLColor3>(name); } LLSD LLControlGroup::getLLSD(const std::string& name) { - return get<LLSD>(name); + return get<LLSD>(name); } LLSD LLControlGroup::asLLSD(bool diffs_only) { - // Dump all stored values as LLSD - LLSD result = LLSD::emptyArray(); - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - LLControlVariable *control = iter->second; - if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) - { - continue; - } - const std::string& name = iter->first; - result[name] = getLLSD(name); - } - return result; + // Dump all stored values as LLSD + LLSD result = LLSD::emptyArray(); + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + LLControlVariable *control = iter->second; + if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) + { + continue; + } + const std::string& name = iter->first; + result[name] = getLLSD(name); + } + return result; } BOOL LLControlGroup::controlExists(const std::string& name) { - ctrl_name_table_t::iterator iter = mNameTable.find(name); - return iter != mNameTable.end(); + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter != mNameTable.end(); } @@ -672,81 +672,81 @@ BOOL LLControlGroup::controlExists(const std::string& name) void LLControlGroup::setBOOL(const std::string& name, BOOL val) { - set<bool>(name, val); + set<bool>(name, val); } void LLControlGroup::setS32(const std::string& name, S32 val) { - set(name, val); + set(name, val); } void LLControlGroup::setF32(const std::string& name, F32 val) { - set(name, val); + set(name, val); } void LLControlGroup::setU32(const std::string& name, U32 val) { - set(name, val); + set(name, val); } void LLControlGroup::setString(const std::string& name, const std::string &val) { - set(name, val); + set(name, val); } void LLControlGroup::setVector3(const std::string& name, const LLVector3 &val) { - set(name, val); + set(name, val); } void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val) { - set(name, val); + set(name, val); } void LLControlGroup::setQuaternion(const std::string& name, const LLQuaternion &val) { - set(name, val); + set(name, val); } void LLControlGroup::setRect(const std::string& name, const LLRect &val) { - set(name, val); + set(name, val); } void LLControlGroup::setColor4(const std::string& name, const LLColor4 &val) { - set(name, val); + set(name, val); } void LLControlGroup::setLLSD(const std::string& name, const LLSD& val) { - set(name, val); + set(name, val); } -void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val) +void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val, bool saved_value) { - if (name.empty()) - { - return; - } - - LLControlVariable* control = getControl(name); + if (name.empty()) + { + return; + } - if (control) - { - control->setValue(val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << LL_ENDL; - } + LLControlVariable* control = getControl(name); + + if (control) + { + control->setValue(val, saved_value); + } + else + { + CONTROL_ERRS << "Invalid control " << name << LL_ENDL; + } } @@ -757,388 +757,388 @@ void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val) // Returns number of controls loaded, so 0 if failure U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require_declaration, eControlType declare_as) { - std::string name; - - LLXmlTree xml_controls; - - if (!xml_controls.parseFile(filename)) - { - LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL; - return 0; - } - - LLXmlTreeNode* rootp = xml_controls.getRoot(); - if (!rootp || !rootp->hasAttribute("version")) - { - LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL; - return 0; - } - - U32 validitems = 0; - S32 version; - - rootp->getAttributeS32("version", version); - - // Check file version - if (version != CURRENT_VERSION) - { - LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; - return 0; - } - - LLXmlTreeNode* child_nodep = rootp->getFirstChild(); - while(child_nodep) - { - name = child_nodep->getName(); - - BOOL declared = controlExists(name); - - if (require_declaration && !declared) - { - // Declaration required, but this name not declared. - // Complain about non-empty names. - if (!name.empty()) - { - //read in to end of line - LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; - } - child_nodep = rootp->getNextChild(); - continue; - } - - // Got an item. Load it up. - // If not declared, assume it's a string - if (!declared) - { - switch(declare_as) - { - case TYPE_COL4: - declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO); - break; - case TYPE_STRING: - default: - declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO); - break; - } - } - - // Control name has been declared in code. - LLControlVariable *control = getControl(name); - - llassert(control); - - switch(control->mType) - { - case TYPE_F32: - { - F32 initial = 0.f; - - child_nodep->getAttributeF32("value", initial); - - control->set(initial); - validitems++; - } - break; - case TYPE_S32: - { - S32 initial = 0; - - child_nodep->getAttributeS32("value", initial); - - control->set(initial); - validitems++; - } - break; - case TYPE_U32: - { - U32 initial = 0; - child_nodep->getAttributeU32("value", initial); - control->set((LLSD::Integer) initial); - validitems++; - } - break; - case TYPE_BOOLEAN: - { - BOOL initial = FALSE; - - child_nodep->getAttributeBOOL("value", initial); - control->set(initial); - - validitems++; - } - break; - case TYPE_STRING: - { - std::string string; - child_nodep->getAttributeString("value", string); - control->set(string); - validitems++; - } - break; - case TYPE_VEC3: - { - LLVector3 vector; - - child_nodep->getAttributeVector3("value", vector); - control->set(vector.getValue()); - validitems++; - } - break; - case TYPE_VEC3D: - { - LLVector3d vector; - - child_nodep->getAttributeVector3d("value", vector); - - control->set(vector.getValue()); - validitems++; - } - break; - case TYPE_QUAT: - { - LLQuaternion quat; - - child_nodep->getAttributeQuat("value", quat); - - control->set(quat.getValue()); - validitems++; - } - break; - case TYPE_RECT: - { - //RN: hack to support reading rectangles from a string - std::string rect_string; - - child_nodep->getAttributeString("value", rect_string); - std::istringstream istream(rect_string); - S32 left, bottom, width, height; - - istream >> left >> bottom >> width >> height; - - LLRect rect; - rect.setOriginAndSize(left, bottom, width, height); - - control->set(rect.getValue()); - validitems++; - } - break; - case TYPE_COL4: - { - LLColor4 color; - - child_nodep->getAttributeColor4("value", color); - control->set(color.getValue()); - validitems++; - } - break; - case TYPE_COL3: - { - LLVector3 color; - - child_nodep->getAttributeVector3("value", color); - control->set(LLColor3(color.mV).getValue()); - validitems++; - } - break; - - default: - break; - - } - - child_nodep = rootp->getNextChild(); - } - - return validitems; + std::string name; + + LLXmlTree xml_controls; + + if (!xml_controls.parseFile(filename)) + { + LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL; + return 0; + } + + LLXmlTreeNode* rootp = xml_controls.getRoot(); + if (!rootp || !rootp->hasAttribute("version")) + { + LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL; + return 0; + } + + U32 validitems = 0; + S32 version; + + rootp->getAttributeS32("version", version); + + // Check file version + if (version != CURRENT_VERSION) + { + LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; + return 0; + } + + LLXmlTreeNode* child_nodep = rootp->getFirstChild(); + while(child_nodep) + { + name = child_nodep->getName(); + + BOOL declared = controlExists(name); + + if (require_declaration && !declared) + { + // Declaration required, but this name not declared. + // Complain about non-empty names. + if (!name.empty()) + { + //read in to end of line + LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; + } + child_nodep = rootp->getNextChild(); + continue; + } + + // Got an item. Load it up. + // If not declared, assume it's a string + if (!declared) + { + switch(declare_as) + { + case TYPE_COL4: + declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO); + break; + case TYPE_STRING: + default: + declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO); + break; + } + } + + // Control name has been declared in code. + LLControlVariable *control = getControl(name); + + llassert(control); + + switch(control->mType) + { + case TYPE_F32: + { + F32 initial = 0.f; + + child_nodep->getAttributeF32("value", initial); + + control->set(initial); + validitems++; + } + break; + case TYPE_S32: + { + S32 initial = 0; + + child_nodep->getAttributeS32("value", initial); + + control->set(initial); + validitems++; + } + break; + case TYPE_U32: + { + U32 initial = 0; + child_nodep->getAttributeU32("value", initial); + control->set((LLSD::Integer) initial); + validitems++; + } + break; + case TYPE_BOOLEAN: + { + BOOL initial = FALSE; + + child_nodep->getAttributeBOOL("value", initial); + control->set(initial); + + validitems++; + } + break; + case TYPE_STRING: + { + std::string string; + child_nodep->getAttributeString("value", string); + control->set(string); + validitems++; + } + break; + case TYPE_VEC3: + { + LLVector3 vector; + + child_nodep->getAttributeVector3("value", vector); + control->set(vector.getValue()); + validitems++; + } + break; + case TYPE_VEC3D: + { + LLVector3d vector; + + child_nodep->getAttributeVector3d("value", vector); + + control->set(vector.getValue()); + validitems++; + } + break; + case TYPE_QUAT: + { + LLQuaternion quat; + + child_nodep->getAttributeQuat("value", quat); + + control->set(quat.getValue()); + validitems++; + } + break; + case TYPE_RECT: + { + //RN: hack to support reading rectangles from a string + std::string rect_string; + + child_nodep->getAttributeString("value", rect_string); + std::istringstream istream(rect_string); + S32 left, bottom, width, height; + + istream >> left >> bottom >> width >> height; + + LLRect rect; + rect.setOriginAndSize(left, bottom, width, height); + + control->set(rect.getValue()); + validitems++; + } + break; + case TYPE_COL4: + { + LLColor4 color; + + child_nodep->getAttributeColor4("value", color); + control->set(color.getValue()); + validitems++; + } + break; + case TYPE_COL3: + { + LLVector3 color; + + child_nodep->getAttributeVector3("value", color); + control->set(LLColor3(color.mV).getValue()); + validitems++; + } + break; + + default: + break; + + } + + child_nodep = rootp->getNextChild(); + } + + return validitems; } U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { - LLSD settings; - int num_saved = 0; - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - LLControlVariable* control = iter->second; - if (!control) - { - LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL; - } - else if( control->shouldSave(nondefault_only) ) - { - settings[iter->first]["Type"] = typeEnumToString(control->type()); - settings[iter->first]["Comment"] = control->getComment(); - settings[iter->first]["Value"] = control->getSaveValue(); - ++num_saved; - } - } - llofstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::toPrettyXML(settings, file); - file.close(); - LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL; - } - else - { + LLSD settings; + int num_saved = 0; + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + LLControlVariable* control = iter->second; + if (!control) + { + LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL; + } + else if( control->shouldSave(nondefault_only) ) + { + settings[iter->first]["Type"] = typeEnumToString(control->type()); + settings[iter->first]["Comment"] = control->getComment(); + settings[iter->first]["Value"] = control->getSaveValue(); + ++num_saved; + } + } + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(settings, file); + file.close(); + LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL; + } + else + { // This is a warning because sometime we want to use settings files which can't be written... - LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL; - return 0; - } - return num_saved; + LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL; + return 0; + } + return num_saved; } U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values) { - LLSD settings; - llifstream infile; - infile.open(filename.c_str()); - if(!infile.is_open()) - { - LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL; - return 0; - } - - if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile)) - { - infile.close(); - LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; - return loadFromFileLegacy(filename, TRUE, TYPE_STRING); - } - - U32 validitems = 0; - bool hidefromsettingseditor = false; - - for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) - { - LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT; - std::string const & name = itr->first; - LLSD const & control_map = itr->second; - - if(control_map.has("Persist")) - { - persist = control_map["Persist"].asInteger()? - LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO; - } - - // Sometimes we want to use the settings system to provide cheap persistence, but we - // don't want the settings themselves to be easily manipulated in the UI because - // doing so can cause support problems. So we have this option: - if(control_map.has("HideFromEditor")) - { - hidefromsettingseditor = control_map["HideFromEditor"].asInteger(); - } - else - { - hidefromsettingseditor = false; - } - - // If the control exists just set the value from the input file. - LLControlVariable* existing_control = getControl(name); - if(existing_control) - { - // set_default_values is true when we're loading the initial, - // immutable files from app_settings, e.g. settings.xml. - if(set_default_values) - { - // Override all previously set properties of this control. - // ... except for type. The types must match. - eControlType new_type = typeStringToEnum(control_map["Type"].asString()); - if(existing_control->isType(new_type)) - { - existing_control->setDefaultValue(control_map["Value"]); - existing_control->setPersist(persist); - existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor); - existing_control->setComment(control_map["Comment"].asString()); - } - else - { - LL_ERRS() << "Mismatched type of control variable '" - << name << "' found while loading '" - << filename << "'." << LL_ENDL; - } - } - else if(existing_control->isPersisted()) - { - // save_values is specifically false for (e.g.) - // SessionSettingsFile and UserSessionSettingsFile -- in other - // words, for a file that's supposed to be transient. - existing_control->setValue(control_map["Value"], save_values); - } - // *NOTE: If not persisted and not setting defaults, - // the value should not get loaded. - } - else - { - // We've never seen this control before. Either we're loading up - // the initial set of default settings files (set_default_values) - // -- or we're loading user settings last saved by a viewer that - // supports a superset of the variables we know. - // CHOP-962: if we're loading an unrecognized user setting, make - // sure we save it later. If you try an experimental viewer, tweak - // a new setting, briefly revert to an old viewer, then return to - // the new one, we don't want the old viewer to discard the - // setting you changed. - if (! set_default_values) - { - // Using PERSIST_ALWAYS insists that saveToFile() (which calls - // LLControlVariable::shouldSave()) must save this control - // variable regardless of its value. We can safely set this - // LLControlVariable persistent because the 'persistent' flag - // is not itself persisted! - persist = LLControlVariable::PERSIST_ALWAYS; - // We want to mention unrecognized user settings variables - // (e.g. from a newer version of the viewer) in the log. But - // we also arrive here for Boolean variables generated by - // the notifications subsystem when the user checks "Don't - // show me this again." These aren't declared in settings.xml; - // they're actually named for the notification they suppress. - // We don't want to mention those. Apologies, this is a bit of - // a hack: we happen to know that user settings go into an - // LLControlGroup whose name is "Global". - if (getKey() == "Global") - { - LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey() - << " settings variable " << name << LL_ENDL; - } - } - - declareControl(name, - typeStringToEnum(control_map["Type"].asString()), - control_map["Value"], - control_map["Comment"].asString(), - persist, - hidefromsettingseditor - ); - } - - ++validitems; - } - - LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL; - return validitems; + LLSD settings; + llifstream infile; + infile.open(filename.c_str()); + if(!infile.is_open()) + { + LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL; + return 0; + } + + if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile)) + { + infile.close(); + LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; + return loadFromFileLegacy(filename, TRUE, TYPE_STRING); + } + + U32 validitems = 0; + bool hidefromsettingseditor = false; + + for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) + { + LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT; + std::string const & name = itr->first; + LLSD const & control_map = itr->second; + + if(control_map.has("Persist")) + { + persist = control_map["Persist"].asInteger()? + LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO; + } + + // Sometimes we want to use the settings system to provide cheap persistence, but we + // don't want the settings themselves to be easily manipulated in the UI because + // doing so can cause support problems. So we have this option: + if(control_map.has("HideFromEditor")) + { + hidefromsettingseditor = control_map["HideFromEditor"].asInteger(); + } + else + { + hidefromsettingseditor = false; + } + + // If the control exists just set the value from the input file. + LLControlVariable* existing_control = getControl(name); + if(existing_control) + { + // set_default_values is true when we're loading the initial, + // immutable files from app_settings, e.g. settings.xml. + if(set_default_values) + { + // Override all previously set properties of this control. + // ... except for type. The types must match. + eControlType new_type = typeStringToEnum(control_map["Type"].asString()); + if(existing_control->isType(new_type)) + { + existing_control->setDefaultValue(control_map["Value"]); + existing_control->setPersist(persist); + existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor); + existing_control->setComment(control_map["Comment"].asString()); + } + else + { + LL_ERRS() << "Mismatched type of control variable '" + << name << "' found while loading '" + << filename << "'." << LL_ENDL; + } + } + else if(existing_control->isPersisted()) + { + // save_values is specifically false for (e.g.) + // SessionSettingsFile and UserSessionSettingsFile -- in other + // words, for a file that's supposed to be transient. + existing_control->setValue(control_map["Value"], save_values); + } + // *NOTE: If not persisted and not setting defaults, + // the value should not get loaded. + } + else + { + // We've never seen this control before. Either we're loading up + // the initial set of default settings files (set_default_values) + // -- or we're loading user settings last saved by a viewer that + // supports a superset of the variables we know. + // CHOP-962: if we're loading an unrecognized user setting, make + // sure we save it later. If you try an experimental viewer, tweak + // a new setting, briefly revert to an old viewer, then return to + // the new one, we don't want the old viewer to discard the + // setting you changed. + if (! set_default_values) + { + // Using PERSIST_ALWAYS insists that saveToFile() (which calls + // LLControlVariable::shouldSave()) must save this control + // variable regardless of its value. We can safely set this + // LLControlVariable persistent because the 'persistent' flag + // is not itself persisted! + persist = LLControlVariable::PERSIST_ALWAYS; + // We want to mention unrecognized user settings variables + // (e.g. from a newer version of the viewer) in the log. But + // we also arrive here for Boolean variables generated by + // the notifications subsystem when the user checks "Don't + // show me this again." These aren't declared in settings.xml; + // they're actually named for the notification they suppress. + // We don't want to mention those. Apologies, this is a bit of + // a hack: we happen to know that user settings go into an + // LLControlGroup whose name is "Global". + if (getKey() == "Global") + { + LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey() + << " settings variable " << name << LL_ENDL; + } + } + + declareControl(name, + typeStringToEnum(control_map["Type"].asString()), + control_map["Value"], + control_map["Comment"].asString(), + persist, + hidefromsettingseditor + ); + } + + ++validitems; + } + + LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL; + return validitems; } void LLControlGroup::resetToDefaults() { - ctrl_name_table_t::iterator control_iter; - for (control_iter = mNameTable.begin(); - control_iter != mNameTable.end(); - ++control_iter) - { - LLControlVariable* control = (*control_iter).second; - control->resetToDefault(); - } + ctrl_name_table_t::iterator control_iter; + for (control_iter = mNameTable.begin(); + control_iter != mNameTable.end(); + ++control_iter) + { + LLControlVariable* control = (*control_iter).second; + control->resetToDefault(); + } } void LLControlGroup::applyToAll(ApplyFunctor* func) { - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - func->apply(iter->first, iter->second); - } + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + func->apply(iter->first, iter->second); + } } //============================================================================ @@ -1146,335 +1146,335 @@ void LLControlGroup::applyToAll(ApplyFunctor* func) #ifdef TEST_HARNESS void main() { - F32_CONTROL foo, getfoo; - - S32_CONTROL bar, getbar; + F32_CONTROL foo, getfoo; - BOOL_CONTROL baz; + S32_CONTROL bar, getbar; + + BOOL_CONTROL baz; - U32 count = gGlobals.loadFromFile("controls.ini"); - LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL; + U32 count = gGlobals.loadFromFile("controls.ini"); + LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL; - // test insertion - foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f); - gGlobals.addEntry("gFoo", foo); + // test insertion + foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f); + gGlobals.addEntry("gFoo", foo); - bar = new LLControlVariable<S32>("gBar", 10, 2, 22); - gGlobals.addEntry("gBar", bar); + bar = new LLControlVariable<S32>("gBar", 10, 2, 22); + gGlobals.addEntry("gBar", bar); - baz = new LLControlVariable<BOOL>("gBaz", FALSE); - gGlobals.addEntry("gBaz", baz); + baz = new LLControlVariable<BOOL>("gBaz", FALSE); + gGlobals.addEntry("gBaz", baz); - // test retrieval - getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo"); - getfoo->dump(); + // test retrieval + getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo"); + getfoo->dump(); - getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); - getbar->dump(); + getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); + getbar->dump(); - // change data - getfoo->set(10.f); - getfoo->dump(); + // change data + getfoo->set(10.f); + getfoo->dump(); - // Failure modes + // Failure modes - // ...min > max - // badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f); + // ...min > max + // badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f); - // ...initial > max - // badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000); + // ...initial > max + // badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000); - // ...misspelled name - // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); - // getfoo->dump(); + // ...misspelled name + // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); + // getfoo->dump(); - // ...invalid data type - getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo"); - getfoo->set(TRUE); - getfoo->dump(); + // ...invalid data type + getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo"); + getfoo->set(TRUE); + getfoo->dump(); - // ...out of range data - // getfoo->set(100000000.f); - // getfoo->dump(); + // ...out of range data + // getfoo->set(100000000.f); + // getfoo->dump(); - // Clean Up - delete foo; - delete bar; - delete baz; + // Clean Up + delete foo; + delete bar; + delete baz; } #endif -template <> eControlType get_control_type<U32>() -{ - return TYPE_U32; +template <> eControlType get_control_type<U32>() +{ + return TYPE_U32; } -template <> eControlType get_control_type<S32>() -{ - return TYPE_S32; +template <> eControlType get_control_type<S32>() +{ + return TYPE_S32; } -template <> eControlType get_control_type<F32>() -{ - return TYPE_F32; +template <> eControlType get_control_type<F32>() +{ + return TYPE_F32; } -template <> eControlType get_control_type<bool> () -{ - return TYPE_BOOLEAN; +template <> eControlType get_control_type<bool> () +{ + return TYPE_BOOLEAN; } /* // Yay BOOL, its really an S32. -template <> eControlType get_control_type<BOOL> () -{ - return TYPE_BOOLEAN; +template <> eControlType get_control_type<BOOL> () +{ + return TYPE_BOOLEAN; } */ -template <> eControlType get_control_type<std::string>() -{ - return TYPE_STRING; +template <> eControlType get_control_type<std::string>() +{ + return TYPE_STRING; } -template <> eControlType get_control_type<LLVector3>() -{ - return TYPE_VEC3; +template <> eControlType get_control_type<LLVector3>() +{ + return TYPE_VEC3; } -template <> eControlType get_control_type<LLVector3d>() -{ - return TYPE_VEC3D; +template <> eControlType get_control_type<LLVector3d>() +{ + return TYPE_VEC3D; } template <> eControlType get_control_type<LLQuaternion>() { - return TYPE_QUAT; + return TYPE_QUAT; } -template <> eControlType get_control_type<LLRect>() -{ - return TYPE_RECT; +template <> eControlType get_control_type<LLRect>() +{ + return TYPE_RECT; } -template <> eControlType get_control_type<LLColor4>() -{ - return TYPE_COL4; +template <> eControlType get_control_type<LLColor4>() +{ + return TYPE_COL4; } -template <> eControlType get_control_type<LLColor3>() -{ - return TYPE_COL3; +template <> eControlType get_control_type<LLColor3>() +{ + return TYPE_COL3; } -template <> eControlType get_control_type<LLSD>() -{ - return TYPE_LLSD; +template <> eControlType get_control_type<LLSD>() +{ + return TYPE_LLSD; } -template <> LLSD convert_to_llsd<U32>(const U32& in) -{ - return (LLSD::Integer)in; +template <> LLSD convert_to_llsd<U32>(const U32& in) +{ + return (LLSD::Integer)in; } -template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in) +{ + return in.getValue(); } template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in) { - return in.getValue(); + return in.getValue(); } -template <> LLSD convert_to_llsd<LLRect>(const LLRect& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd<LLRect>(const LLRect& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in) +{ + return in.getValue(); } template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_BOOLEAN) - return sd.asBoolean(); - else - { - CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return FALSE; - } + if (type == TYPE_BOOLEAN) + return sd.asBoolean(); + else + { + CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return FALSE; + } } template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_S32) - return sd.asInteger(); - else - { - CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0; - } + if (type == TYPE_S32) + return sd.asInteger(); + else + { + CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return 0; + } } template<> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_U32) - return sd.asInteger(); - else - { - CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0; - } + if (type == TYPE_U32) + return sd.asInteger(); + else + { + CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return 0; + } } template<> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_F32) - return (F32) sd.asReal(); - else - { - CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0.0f; - } + if (type == TYPE_F32) + return (F32) sd.asReal(); + else + { + CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return 0.0f; + } } template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_STRING) - return sd.asString(); - else - { - CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLStringUtil::null; - } + if (type == TYPE_STRING) + return sd.asString(); + else + { + CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLStringUtil::null; + } } template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name) { - return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name)); + return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name)); } template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_VEC3) - return (LLVector3)sd; - else - { - CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLVector3::zero; - } + if (type == TYPE_VEC3) + return (LLVector3)sd; + else + { + CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLVector3::zero; + } } template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_VEC3D) - return (LLVector3d)sd; - else - { - CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLVector3d::zero; - } + if (type == TYPE_VEC3D) + return (LLVector3d)sd; + else + { + CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLVector3d::zero; + } } template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_QUAT) - return (LLQuaternion)sd; - else - { - CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLQuaternion(); - } + if (type == TYPE_QUAT) + return (LLQuaternion)sd; + else + { + CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLQuaternion(); + } } template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_RECT) - return LLRect(sd); - else - { - CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLRect::null; - } + if (type == TYPE_RECT) + return LLRect(sd); + else + { + CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLRect::null; + } } template<> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_COL4) - { - LLColor4 color(sd); - if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL; - } - else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL; - } - else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL; - } - else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; - } - - return LLColor4(sd); - } - else - { - CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; - return LLColor4::white; - } + if (type == TYPE_COL4) + { + LLColor4 color(sd); + if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) + { + LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL; + } + else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) + { + LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL; + } + else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) + { + LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL; + } + else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) + { + LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; + } + + return LLColor4(sd); + } + else + { + CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; + return LLColor4::white; + } } template<> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_COL3) - return sd; - else - { - CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLColor3::white; - } + if (type == TYPE_COL3) + return sd; + else + { + CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLColor3::white; + } } template<> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name) { - return sd; + return sd; } @@ -1502,21 +1502,21 @@ static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hah void test_cached_control() { #define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL - TEST_LLCC(U32, 666); - TEST_LLCC(S32, (S32)-666); - TEST_LLCC(F32, (F32)-666.666); - TEST_LLCC(bool, true); - TEST_LLCC(BOOL, FALSE); - if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; - TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); - TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); - TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); - TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); - TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); - TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); -//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); - - if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; + TEST_LLCC(U32, 666); + TEST_LLCC(S32, (S32)-666); + TEST_LLCC(F32, (F32)-666.666); + TEST_LLCC(bool, true); + TEST_LLCC(BOOL, FALSE); + if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; + TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); + TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); + TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); + TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); + TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); + TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); +//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); + + if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; } #endif // TEST_CACHED_CONTROL diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 37663a6fb2..5a8d688892 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -1,25 +1,25 @@ -/** +/** * @file llcontrol.h * @brief A mechanism for storing "control state" for a program * * $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$ */ @@ -48,13 +48,13 @@ #include <boost/bind.hpp> #if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) #endif #include <boost/signals2.hpp> #if LL_WINDOWS - #pragma warning (pop) + #pragma warning (pop) #endif #if LL_WINDOWS @@ -72,241 +72,241 @@ class LLColor3; // if this is changed, also modify mTypeString in llcontrol.h typedef enum e_control_type { - TYPE_U32 = 0, - TYPE_S32, - TYPE_F32, - TYPE_BOOLEAN, - TYPE_STRING, - TYPE_VEC3, - TYPE_VEC3D, - TYPE_QUAT, - TYPE_RECT, - TYPE_COL4, - TYPE_COL3, - TYPE_LLSD, - TYPE_COUNT + TYPE_U32 = 0, + TYPE_S32, + TYPE_F32, + TYPE_BOOLEAN, + TYPE_STRING, + TYPE_VEC3, + TYPE_VEC3D, + TYPE_QUAT, + TYPE_RECT, + TYPE_COL4, + TYPE_COL3, + TYPE_LLSD, + TYPE_COUNT } eControlType; class LLControlVariable : public LLRefCount { - LOG_CLASS(LLControlVariable); - - friend class LLControlGroup; + LOG_CLASS(LLControlVariable); + friend class LLControlGroup; + public: - typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t; - typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t; + typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t; + typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t; - enum ePersist - { - PERSIST_NO, // don't save this var - PERSIST_NONDFT, // save this var if differs from default - PERSIST_ALWAYS // save this var even if has default value - }; + enum ePersist + { + PERSIST_NO, // don't save this var + PERSIST_NONDFT, // save this var if differs from default + PERSIST_ALWAYS // save this var even if has default value + }; private: - std::string mName; - std::string mComment; - eControlType mType; - ePersist mPersist; - bool mHideFromSettingsEditor; - std::vector<LLSD> mValues; - - commit_signal_t mCommitSignal; - validate_signal_t mValidateSignal; - + std::string mName; + std::string mComment; + eControlType mType; + ePersist mPersist; + bool mHideFromSettingsEditor; + std::vector<LLSD> mValues; + + commit_signal_t mCommitSignal; + validate_signal_t mValidateSignal; + public: - LLControlVariable(const std::string& name, eControlType type, - LLSD initial, const std::string& comment, - ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false); - - virtual ~LLControlVariable(); - - const std::string& getName() const { return mName; } - const std::string& getComment() const { return mComment; } - - eControlType type() { return mType; } - bool isType(eControlType tp) { return tp == mType; } - - void resetToDefault(bool fire_signal = false); - - commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal - commit_signal_t* getCommitSignal() { return &mCommitSignal; } - validate_signal_t* getValidateSignal() { return &mValidateSignal; } - - bool isDefault() { return (mValues.size() == 1); } - bool shouldSave(bool nondefault_only); - bool isPersisted() { return mPersist != PERSIST_NO; } - bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; } - LLSD get() const { return getValue(); } - LLSD getValue() const { return mValues.back(); } - LLSD getDefault() const { return mValues.front(); } - LLSD getSaveValue() const; - - void set(const LLSD& val) { setValue(val); } - void setValue(const LLSD& value, bool saved_value = TRUE); - void setDefaultValue(const LLSD& value); - void setPersist(ePersist); - void setHiddenFromSettingsEditor(bool hide); - void setComment(const std::string& comment); + LLControlVariable(const std::string& name, eControlType type, + LLSD initial, const std::string& comment, + ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false); + + virtual ~LLControlVariable(); + + const std::string& getName() const { return mName; } + const std::string& getComment() const { return mComment; } + + eControlType type() { return mType; } + bool isType(eControlType tp) { return tp == mType; } + + void resetToDefault(bool fire_signal = false); + + commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal + commit_signal_t* getCommitSignal() { return &mCommitSignal; } + validate_signal_t* getValidateSignal() { return &mValidateSignal; } + + bool isDefault() { return (mValues.size() == 1); } + bool shouldSave(bool nondefault_only); + bool isPersisted() { return mPersist != PERSIST_NO; } + bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; } + LLSD get() const { return getValue(); } + LLSD getValue() const { return mValues.back(); } + LLSD getDefault() const { return mValues.front(); } + LLSD getSaveValue() const; + + void set(const LLSD& val, bool saved_value = true) { setValue(val, saved_value); } + void setValue(const LLSD& value, bool saved_value = TRUE); + void setDefaultValue(const LLSD& value); + void setPersist(ePersist); + void setHiddenFromSettingsEditor(bool hide); + void setComment(const std::string& comment); private: - void firePropertyChanged(const LLSD &pPreviousValue) - { - mCommitSignal(this, mValues.back(), pPreviousValue); - } - LLSD getComparableValue(const LLSD& value); - bool llsd_compare(const LLSD& a, const LLSD & b); + void firePropertyChanged(const LLSD &pPreviousValue) + { + mCommitSignal(this, mValues.back(), pPreviousValue); + } + LLSD getComparableValue(const LLSD& value); + bool llsd_compare(const LLSD& a, const LLSD & b); }; typedef LLPointer<LLControlVariable> LLControlVariablePtr; //! Helper functions for converting between static types and LLControl values -template <class T> +template <class T> eControlType get_control_type() { - LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL; - return TYPE_COUNT; + LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL; + return TYPE_COUNT; } -template <class T> +template <class T> LLSD convert_to_llsd(const T& in) { - // default implementation - return LLSD(in); + // default implementation + return LLSD(in); } template <class T> T convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - // needs specialization - return T(sd); + // needs specialization + return T(sd); } //const U32 STRING_CACHE_SIZE = 10000; class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string> { - LOG_CLASS(LLControlGroup); + LOG_CLASS(LLControlGroup); protected: - typedef std::map<std::string, LLControlVariablePtr > ctrl_name_table_t; - ctrl_name_table_t mNameTable; - static const std::string mTypeString[TYPE_COUNT]; + typedef std::map<std::string, LLControlVariablePtr > ctrl_name_table_t; + ctrl_name_table_t mNameTable; + static const std::string mTypeString[TYPE_COUNT]; public: - static eControlType typeStringToEnum(const std::string& typestr); - static std::string typeEnumToString(eControlType typeenum); - - LLControlGroup(const std::string& name); - ~LLControlGroup(); - void cleanup(); - - LLControlVariablePtr getControl(const std::string& name); - - struct ApplyFunctor - { - virtual ~ApplyFunctor() {}; - virtual void apply(const std::string& name, LLControlVariable* control) = 0; - }; - void applyToAll(ApplyFunctor* func); - - LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor = FALSE); - LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - - std::string getString(const std::string& name); - std::string getText(const std::string& name); - BOOL getBOOL(const std::string& name); - S32 getS32(const std::string& name); - F32 getF32(const std::string& name); - U32 getU32(const std::string& name); - - LLWString getWString(const std::string& name); - LLVector3 getVector3(const std::string& name); - LLVector3d getVector3d(const std::string& name); - LLRect getRect(const std::string& name); - LLSD getLLSD(const std::string& name); - LLQuaternion getQuaternion(const std::string& name); - - LLColor4 getColor(const std::string& name); - LLColor4 getColor4(const std::string& name); - LLColor3 getColor3(const std::string& name); - - LLSD asLLSD(bool diffs_only); - - // generic getter - template<typename T> T get(const std::string& name) - { + static eControlType typeStringToEnum(const std::string& typestr); + static std::string typeEnumToString(eControlType typeenum); + + LLControlGroup(const std::string& name); + ~LLControlGroup(); + void cleanup(); + + LLControlVariablePtr getControl(const std::string& name); + + struct ApplyFunctor + { + virtual ~ApplyFunctor() {}; + virtual void apply(const std::string& name, LLControlVariable* control) = 0; + }; + void applyToAll(ApplyFunctor* func); + + LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor = FALSE); + LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + + std::string getString(const std::string& name); + std::string getText(const std::string& name); + BOOL getBOOL(const std::string& name); + S32 getS32(const std::string& name); + F32 getF32(const std::string& name); + U32 getU32(const std::string& name); + + LLWString getWString(const std::string& name); + LLVector3 getVector3(const std::string& name); + LLVector3d getVector3d(const std::string& name); + LLRect getRect(const std::string& name); + LLSD getLLSD(const std::string& name); + LLQuaternion getQuaternion(const std::string& name); + + LLColor4 getColor(const std::string& name); + LLColor4 getColor4(const std::string& name); + LLColor3 getColor3(const std::string& name); + + LLSD asLLSD(bool diffs_only); + + // generic getter + template<typename T> T get(const std::string& name) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - LLControlVariable* control = getControl(name); - LLSD value; - eControlType type = TYPE_COUNT; - - if (control) - { - value = control->get(); - type = control->type(); - } - else - { - LL_WARNS() << "Control " << name << " not found." << LL_ENDL; - return T(); - } - return convert_from_llsd<T>(value, type, name); - } - - void setBOOL(const std::string& name, BOOL val); - void setS32(const std::string& name, S32 val); - void setF32(const std::string& name, F32 val); - void setU32(const std::string& name, U32 val); - void setString(const std::string& name, const std::string& val); - void setVector3(const std::string& name, const LLVector3 &val); - void setVector3d(const std::string& name, const LLVector3d &val); - void setQuaternion(const std::string& name, const LLQuaternion &val); - void setRect(const std::string& name, const LLRect &val); - void setColor4(const std::string& name, const LLColor4 &val); - void setLLSD(const std::string& name, const LLSD& val); - - // type agnostic setter that takes LLSD - void setUntypedValue(const std::string& name, const LLSD& val); - - // generic setter - template<typename T> void set(const std::string& name, const T& val) - { - LLControlVariable* control = getControl(name); - - if (control && control->isType(get_control_type<T>())) - { - control->set(convert_to_llsd(val)); - } - else - { - LL_WARNS() << "Invalid control " << name << LL_ENDL; - } - } - - BOOL controlExists(const std::string& name); - - // Returns number of controls loaded, 0 if failed - // If require_declaration is false, will auto-declare controls it finds - // as the given type. - U32 loadFromFileLegacy(const std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); - U32 saveToFile(const std::string& filename, BOOL nondefault_only); - U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); - void resetToDefaults(); - void incrCount(const std::string& name); - - bool mSettingsProfile; + LLControlVariable* control = getControl(name); + LLSD value; + eControlType type = TYPE_COUNT; + + if (control) + { + value = control->get(); + type = control->type(); + } + else + { + LL_WARNS() << "Control " << name << " not found." << LL_ENDL; + return T(); + } + return convert_from_llsd<T>(value, type, name); + } + + void setBOOL(const std::string& name, BOOL val); + void setS32(const std::string& name, S32 val); + void setF32(const std::string& name, F32 val); + void setU32(const std::string& name, U32 val); + void setString(const std::string& name, const std::string& val); + void setVector3(const std::string& name, const LLVector3 &val); + void setVector3d(const std::string& name, const LLVector3d &val); + void setQuaternion(const std::string& name, const LLQuaternion &val); + void setRect(const std::string& name, const LLRect &val); + void setColor4(const std::string& name, const LLColor4 &val); + void setLLSD(const std::string& name, const LLSD& val); + + // type agnostic setter that takes LLSD + void setUntypedValue(const std::string& name, const LLSD& val, bool saved_value = true); + + // generic setter + template<typename T> void set(const std::string& name, const T& val) + { + LLControlVariable* control = getControl(name); + + if (control && control->isType(get_control_type<T>())) + { + control->set(convert_to_llsd(val)); + } + else + { + LL_WARNS() << "Invalid control " << name << LL_ENDL; + } + } + + BOOL controlExists(const std::string& name); + + // Returns number of controls loaded, 0 if failed + // If require_declaration is false, will auto-declare controls it finds + // as the given type. + U32 loadFromFileLegacy(const std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); + U32 saveToFile(const std::string& filename, BOOL nondefault_only); + U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); + void resetToDefaults(); + void incrCount(const std::string& name); + + bool mSettingsProfile; }; @@ -319,124 +319,124 @@ template <class T> class LLControlCache : public LLRefCount, public LLInstanceTracker<LLControlCache<T>, std::string> { public: - // This constructor will declare a control if it doesn't exist in the contol group - LLControlCache(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment) - : LLInstanceTracker<LLControlCache<T>, std::string >(name) - { - if(!group.controlExists(name)) - { - if(!declareTypedControl(group, name, default_value, comment)) - { - LL_ERRS() << "The control could not be created!!!" << LL_ENDL; - } - } - - bindToControl(group, name); - } - - LLControlCache(LLControlGroup& group, - const std::string& name) - : LLInstanceTracker<LLControlCache<T>, std::string >(name) - { - if(!group.controlExists(name)) - { - LL_ERRS() << "Control named " << name << "not found." << LL_ENDL; - } - - bindToControl(group, name); - } - - ~LLControlCache() - { - } - - const T& getValue() const { return mCachedValue; } - + // This constructor will declare a control if it doesn't exist in the contol group + LLControlCache(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment) + : LLInstanceTracker<LLControlCache<T>, std::string >(name) + { + if(!group.controlExists(name)) + { + if(!declareTypedControl(group, name, default_value, comment)) + { + LL_ERRS() << "The control could not be created!!!" << LL_ENDL; + } + } + + bindToControl(group, name); + } + + LLControlCache(LLControlGroup& group, + const std::string& name) + : LLInstanceTracker<LLControlCache<T>, std::string >(name) + { + if(!group.controlExists(name)) + { + LL_ERRS() << "Control named " << name << "not found." << LL_ENDL; + } + + bindToControl(group, name); + } + + ~LLControlCache() + { + } + + const T& getValue() const { return mCachedValue; } + private: - void bindToControl(LLControlGroup& group, const std::string& name) - { - LLControlVariablePtr controlp = group.getControl(name); - mType = controlp->type(); - mCachedValue = convert_from_llsd<T>(controlp->get(), mType, name); - - // Add a listener to the controls signal... - // NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last - mConnection = controlp->getSignal()->connect(0, - boost::bind(&LLControlCache<T>::handleValueChange, this, _2) - ); - mType = controlp->type(); - } - bool declareTypedControl(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment) - { - LLSD init_value; - eControlType type = get_control_type<T>(); - init_value = convert_to_llsd(default_value); - if(type < TYPE_COUNT) - { - group.declareControl(name, type, init_value, comment, LLControlVariable::PERSIST_NO); - return true; - } - return false; - } - - bool handleValueChange(const LLSD& newvalue) - { - mCachedValue = convert_from_llsd<T>(newvalue, mType, ""); - return true; - } + void bindToControl(LLControlGroup& group, const std::string& name) + { + LLControlVariablePtr controlp = group.getControl(name); + mType = controlp->type(); + mCachedValue = convert_from_llsd<T>(controlp->get(), mType, name); + + // Add a listener to the controls signal... + // NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last + mConnection = controlp->getSignal()->connect(0, + boost::bind(&LLControlCache<T>::handleValueChange, this, _2) + ); + mType = controlp->type(); + } + bool declareTypedControl(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment) + { + LLSD init_value; + eControlType type = get_control_type<T>(); + init_value = convert_to_llsd(default_value); + if(type < TYPE_COUNT) + { + group.declareControl(name, type, init_value, comment, LLControlVariable::PERSIST_NO); + return true; + } + return false; + } + + bool handleValueChange(const LLSD& newvalue) + { + mCachedValue = convert_from_llsd<T>(newvalue, mType, ""); + return true; + } private: - T mCachedValue; - eControlType mType; - boost::signals2::scoped_connection mConnection; + T mCachedValue; + eControlType mType; + boost::signals2::scoped_connection mConnection; }; template <typename T> class LLCachedControl { public: - LLCachedControl(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment = "Declared In Code") - { - mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); - if (! mCachedControlPtr) - { - mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment); - } - } - - LLCachedControl(LLControlGroup& group, - const std::string& name) - { - mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); - if (! mCachedControlPtr) - { - mCachedControlPtr = new LLControlCache<T>(group, name); - } - } - - operator const T&() const { return mCachedControlPtr->getValue(); } - operator boost::function<const T&()> () const { return boost::function<const T&()>(*this); } - const T& operator()() { return mCachedControlPtr->getValue(); } + LLCachedControl(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment = "Declared In Code") + { + mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); + if (! mCachedControlPtr) + { + mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment); + } + } + + LLCachedControl(LLControlGroup& group, + const std::string& name) + { + mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); + if (! mCachedControlPtr) + { + mCachedControlPtr = new LLControlCache<T>(group, name); + } + } + + operator const T&() const { return mCachedControlPtr->getValue(); } + operator boost::function<const T&()> () const { return boost::function<const T&()>(*this); } + const T& operator()() { return mCachedControlPtr->getValue(); } private: - LLPointer<LLControlCache<T> > mCachedControlPtr; + LLPointer<LLControlCache<T> > mCachedControlPtr; }; template <> eControlType get_control_type<U32>(); template <> eControlType get_control_type<S32>(); template <> eControlType get_control_type<F32>(); -template <> eControlType get_control_type<bool>(); +template <> eControlType get_control_type<bool>(); // Yay BOOL, its really an S32. -//template <> eControlType get_control_type<BOOL> () +//template <> eControlType get_control_type<BOOL> () template <> eControlType get_control_type<std::string>(); template <> eControlType get_control_type<LLVector3>(); template <> eControlType get_control_type<LLVector3d>(); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a6ae041935..f2d5ed26ee 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -48,6 +48,7 @@ include(VulkanGltf) 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 @@ -242,6 +243,8 @@ set(viewer_SOURCE_FILES llfloaterlandholdings.cpp llfloaterlinkreplace.cpp llfloaterloadprefpreset.cpp + llfloaterluadebug.cpp + llfloaterluascripts.cpp llfloatermarketplacelistings.cpp llfloatermap.cpp llfloatermediasettings.cpp @@ -371,6 +374,7 @@ set(viewer_SOURCE_FILES lllogchat.cpp llloginhandler.cpp lllogininstance.cpp + llluamanager.cpp llmachineid.cpp llmanip.cpp llmaniprotate.cpp @@ -899,6 +903,8 @@ set(viewer_HEADER_FILES llfloaterlandholdings.h llfloaterlinkreplace.h llfloaterloadprefpreset.h + llfloaterluadebug.h + llfloaterluascripts.h llfloatermap.h llfloatermarketplacelistings.h llfloatermediasettings.h @@ -1026,6 +1032,7 @@ set(viewer_HEADER_FILES lllogchat.h llloginhandler.h lllogininstance.h + llluamanager.h llmachineid.h llmanip.h llmaniprotate.h @@ -1804,20 +1811,6 @@ if (WINDOWS) if (PACKAGE) add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz - 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} ARGS @@ -1846,9 +1839,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.xz) endif (PACKAGE) elseif (DARWIN) @@ -1909,14 +1899,15 @@ target_link_libraries(${VIEWER_BINARY_NAME} llcorehttp llcommon llmeshoptimizer - ll::ndof lllogin llprimitive llappearance ${LLPHYSICSEXTENSIONS_LIBRARIES} ll::bugsplat - ll::tracy ll::icu4c + ll::lualibs + ll::ndof + ll::tracy ) if( TARGET ll::intel_memops ) @@ -2315,6 +2306,11 @@ if (LL_TESTS) "${test_libs}" ) + LL_ADD_INTEGRATION_TEST(llluamanager + "llluamanager.cpp" + "${test_libs};ll::lualibs" + ) + LL_ADD_INTEGRATION_TEST(llsechandler_basic llsechandler_basic.cpp "${test_libs}" @@ -2369,4 +2365,3 @@ if (LL_TESTS) endif (LL_TESTS) check_message_template(${VIEWER_BINARY_NAME}) - 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 2f7c256b49..68eb3093be 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> @@ -5398,6 +5398,28 @@ <key>Value</key> <string>Monospace</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> @@ -17339,6 +17361,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/llappviewer.cpp b/indra/newview/llappviewer.cpp index 754ee5aa23..0b566cbc73 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" @@ -108,7 +109,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llperfstats.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -148,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 @@ -316,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; @@ -338,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; @@ -384,59 +385,62 @@ 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 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; @@ -451,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 } @@ -584,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; } //---------------------------------------------------------------------------- @@ -634,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) @@ -1080,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 @@ -1192,22 +1196,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); - } - for (const auto& 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. @@ -1215,8 +1207,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) { @@ -1225,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")); - LLAgentLanguage::init(); + LLStringOps::sAM = LLTrans::getString("dateTimeAM"); + LLStringOps::sPM = LLTrans::getString("dateTimePM"); + } + + LLAgentLanguage::init(); /// Tell the Coprocedure manager how to discover and store the pool sizes // what I wanted @@ -1251,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(); @@ -1286,23 +1291,44 @@ bool LLAppViewer::init() } #endif - return true; + 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. - //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") ; @@ -1319,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() @@ -1447,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"); @@ -1527,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() @@ -1704,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; - } + delete gAudiop; + gAudiop = NULL; + } - // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. + // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. - // 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; + // 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; - // delete some of the files left around in the cache. - removeCacheFiles("*.wav"); - removeCacheFiles("*.tmp"); - removeCacheFiles("*.lso"); - removeCacheFiles("*.out"); - removeCacheFiles("*.dsf"); - removeCacheFiles("*.bodypart"); - removeCacheFiles("*.clothing"); + // 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() << "Cache files removed" << LL_ENDL; + LL_INFOS() << "Cache files removed" << LL_ENDL; - LL_INFOS() << "Shutting down Views" << LL_ENDL; + LL_INFOS() << "Shutting down Views" << LL_ENDL; - // Destroy the UI - if( gViewerWindow) - gViewerWindow->shutdownViews(); + // Destroy the UI + if( gViewerWindow) + gViewerWindow->shutdownViews(); - LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; + LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; - // Cleanup Inventory after the UI since it will delete any remaining observers - // (Deleted observers should have already removed themselves) - gInventory.cleanupInventory(); + // Cleanup Inventory after the UI since it will delete any remaining observers + // (Deleted observers should have already removed themselves) + gInventory.cleanupInventory(); - LLCoros::getInstance()->printActiveCoroutines(); + LLCoros::getInstance()->printActiveCoroutines(); - LL_INFOS() << "Cleaning up Selections" << LL_ENDL; + LL_INFOS() << "Cleaning up Selections" << 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(); + // 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() << "Shutting down OpenGL" << LL_ENDL; + LL_INFOS() << "Shutting down OpenGL" << 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; - } + // 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()) { @@ -1905,142 +1931,142 @@ 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(); + // 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(); - 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 (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) { @@ -2050,32 +2076,32 @@ bool LLAppViewer::cleanup() 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(); - } + // 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() ; + sTextureFetch->shutDownTextureCacheThread() ; LLLFSThread::sLocal->shutdown(); - LL_INFOS() << "Shutting down message system" << LL_ENDL; - end_messaging_system(); + LL_INFOS() << "Shutting down message system" << LL_ENDL; + end_messaging_system(); - // Non-LLCurl libcurl library - mAppCoreHttp.cleanup(); + // Non-LLCurl libcurl library + mAppCoreHttp.cleanup(); - SUBSYSTEM_CLEANUP(LLFilePickerThread); - SUBSYSTEM_CLEANUP(LLDirPickerThread); + SUBSYSTEM_CLEANUP(LLFilePickerThread); + SUBSYSTEM_CLEANUP(LLDirPickerThread); - //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) - delete sTextureCache; + //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) + delete sTextureCache; sTextureCache = NULL; if (sTextureFetch) { @@ -2084,101 +2110,101 @@ bool LLAppViewer::cleanup() 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() @@ -2194,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"); @@ -2213,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) @@ -2289,7 +2315,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() if (mSecondInstance) { LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); - + LLUUID uid; uid.generate(); LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); @@ -2360,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 @@ -2484,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)) @@ -2536,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")) { @@ -2722,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. @@ -2767,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")) { @@ -2789,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 @@ -2847,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 @@ -2992,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() @@ -3238,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"); @@ -3267,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; @@ -3317,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 @@ -3351,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. @@ -3370,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() @@ -3583,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 @@ -3684,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() @@ -3965,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 @@ -4185,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); + 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 (!read_only) + { if (gSavedSettings.getS32("DiskCacheVersion") != LLAppViewer::getDiskCacheVersion()) { LLDiskCache::getInstance()->clearCache(); @@ -4282,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. @@ -4449,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"); @@ -4544,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"); @@ -4587,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 @@ -4709,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 @@ -4822,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()) - { - 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 + // 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; - } - - // 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) @@ -5196,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; @@ -5238,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 { @@ -5387,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() @@ -5437,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 @@ -5448,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; @@ -5456,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; @@ -5475,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")); } @@ -5488,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() @@ -5521,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"); } //---------------------------------------------------------------------------- @@ -5650,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); + } } /** @@ -5662,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 bfdede37bc..68952c96c5 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 @@ -64,6 +64,7 @@ LLFilePicker LLFilePicker::sInstance; #define MATERIAL_TEXTURES_FILTER L"GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.gltf;*.glb;*.tga;*.bmp;*.jpg;*.jpeg;*.png\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 @@ -75,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"; @@ -228,70 +229,74 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) IMAGE_FILTER \ L"\0"; break; - case FFLOAD_SCRIPT: - mOFN.lpstrFilter = SCRIPT_FILTER \ + 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; - case FFLOAD_DICTIONARY: - mOFN.lpstrFilter = DICTIONARY_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, @@ -305,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, @@ -391,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, @@ -685,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) @@ -711,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, @@ -724,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; } @@ -785,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 = "\?\?\?\?"; @@ -803,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 = "\?\?\?\?"; @@ -819,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(); - gViewerWindow->getWindow()->beforeDialog(); - - // Run the dialog - std::unique_ptr<std::string> filev = doSaveDialog(&namestring, + // 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, @@ -856,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"; @@ -875,57 +880,57 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; - - BOOL success = 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(); + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + 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; } @@ -943,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. { @@ -964,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; } @@ -1022,7 +1027,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, } reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1033,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; - } - - reset(); + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } + 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, @@ -1078,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 ) { @@ -1086,7 +1091,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; return doNavSaveDialogModeless(filter, filename, callback, userdata); @@ -1100,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; @@ -1515,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; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + BOOL rtn = FALSE; - gViewerWindow->getWindow()->beforeDialog(); + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } - reset(); + gViewerWindow->getWindow()->beforeDialog(); - GtkWindow* picker = buildFilePicker(false, false, "openfile"); + reset(); + + 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 @@ -1582,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, @@ -1612,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, @@ -1645,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, @@ -1670,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 7149ced34a..f00f076d1c 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,118 +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, - }; - - 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); + 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); 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(); - - // 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(); + // 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(); - // This utility function extracts the current file name without - // doing any incrementing. - const std::string getCurFile(); + // 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(); - // Returns the index of the current file. - S32 getCurFileNum() const { return mCurrentFile; } + // This utility function extracts the current file name without + // doing any incrementing. + const std::string getCurFile(); - S32 getFileCount() const { return (S32)mFiles.size(); } + // Returns the index of the current file. + S32 getCurFileNum() const { return mCurrentFile; } - // see lldir.h : getBaseFileName and getDirName to extract base or directory names + S32 getFileCount() const { return (S32)mFiles.size(); } - // clear any lists of buffers or whatever, and make sure the file - // picker isn't locked. - void reset(); + // 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(); 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, @@ -184,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; - - static LLFilePicker sInstance; + std::vector<std::string> mFiles; + S32 mCurrentFile; + bool mLocked; + 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 new file mode 100644 index 0000000000..6fd11dd1c7 --- /dev/null +++ b/indra/newview/llfloaterluadebug.cpp @@ -0,0 +1,155 @@ +/** + * @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 "llcheckboxctrl.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" +#include "llsdutil.h" +#include "lua_function.h" +#include "stringize.h" + + +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"); + mOutConnection = LLEventPumps::instance().obtain("lua output") + .listen("LLFloaterLUADebug", + [mResultOutput=mResultOutput](const LLSD& data) + { + mResultOutput->pasteTextWithLinebreaks(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)); + getChild<LLButton>("run_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnRun, this)); + mLineInput->setCommitCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this)); + mLineInput->setSelectAllonCommit(false); + + return TRUE; +} + +LLFloaterLUADebug::~LLFloaterLUADebug() +{} + +void LLFloaterLUADebug::onExecuteClicked() +{ + mResultOutput->setValue(""); + + std::string cmd = mLineInput->getText(); + cleanLuaState(); + LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) + { + completion(count, result); + }); +} + +void LLFloaterLUADebug::onBtnBrowse() +{ + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterLUADebug::runSelectedScript, this, _1), LLFilePicker::FFLOAD_LUA, false); +} + +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(""); + + std::string filepath = filenames[0]; + if (!filepath.empty()) + { + mScriptPath->setText(filepath); + 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 + LLStyle::Params params; + params.readonly_color = LLUIColorTable::instance().getColor("LtRed"); + mResultOutput->appendText(result.asString(), false, params); + mResultOutput->endOfDoc(); + return; + } + if (count == 1) + { + // single result + mResultOutput->pasteTextWithLinebreaks(stringize(result)); + return; + } + // 0 or multiple results + const char* sep = ""; + for (const auto& item : llsd::inArray(result)) + { + mResultOutput->insertText(sep); + mResultOutput->pasteTextWithLinebreaks(stringize(item)); + 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 new file mode 100644 index 0000000000..7418174570 --- /dev/null +++ b/indra/newview/llfloaterluadebug.h @@ -0,0 +1,72 @@ +/** + * @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 "llevents.h" +#include "llfloater.h" +#include "lua_function.h" + +extern "C" +{ +#include "luau/luacode.h" +#include "luau/lua.h" +#include "luau/luaconf.h" +#include "luau/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 onBtnRun(); + + void runSelectedScript(const std::vector<std::string> &filenames); + +private: + void completion(int count, const LLSD& result); + void cleanLuaState(); + + LLTempBoundListener mOutConnection; + + LLTextEditor* mResultOutput; + LLLineEditor* mLineInput; + LLLineEditor* mScriptPath; + LuaState mState; +}; + +#endif // LL_LLFLOATERLUADEBUG_H + diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp new file mode 100644 index 0000000000..39d5816b0d --- /dev/null +++ b/indra/newview/llfloaterluascripts.cpp @@ -0,0 +1,131 @@ +/** + * @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) + { + 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) + { + if (mScriptList->hasSelectedItem()) + { + std::string coro_name = mScriptList->getSelectedValue(); + LLCoros::instance().killreq(coro_name); + } + }); +} + + +BOOL LLFloaterLUAScripts::postBuild() +{ + mScriptList = getChild<LLScrollListCtrl>("scripts_list"); + 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()); + if (menu) + { + mContextMenuHandle = menu->getHandle(); + } + + return TRUE; +} + +LLFloaterLUAScripts::~LLFloaterLUAScripts() +{ + auto menu = mContextMenuHandle.get(); + if (menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } +} + +void LLFloaterLUAScripts::draw() +{ + if (mUpdateTimer->checkExpirationAndReset(REFRESH_INTERVAL)) + { + 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); +} + +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) + { + 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..932c5c78dd --- /dev/null +++ b/indra/newview/llfloaterluascripts.h @@ -0,0 +1,54 @@ +/** + * @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); + + std::unique_ptr<LLTimer> mUpdateTimer; + LLScrollListCtrl* mScriptList; + + LLHandle<LLContextMenu> mContextMenuHandle; +}; + +#endif // LL_LLFLOATERLUASCRIPTS_H + diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 0c5762e4b1..e1df6a4b1f 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$ */ @@ -34,14 +34,15 @@ #include "llcolorswatch.h" #include "llviewercontrol.h" #include "lltexteditor.h" +#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() @@ -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,11 +62,13 @@ 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)); - return TRUE; + return TRUE; } void LLFloaterSettingsDebug::draw() @@ -75,7 +80,7 @@ void LLFloaterSettingsDebug::draw() updateControl(controlp); } - LLFloater::draw(); + LLFloater::draw(); } void LLFloaterSettingsDebug::onCommitSettings() @@ -87,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); } @@ -181,31 +186,32 @@ 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); - 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(); @@ -218,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; + } + } } @@ -494,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) { @@ -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 5a392e766c..6ff3e344b4 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$ */ @@ -31,30 +31,32 @@ #include "llfloater.h" 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(); @@ -64,9 +66,11 @@ private: void hideUIControls(); LLScrollListCtrl* mSettingList; - + protected: - class LLTextEditor* mComment; + class LLTextEditor* mComment; + LLTextBox* mSettingName; + LLButton* mCopyBtn; std::string mSearchFilter; }; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 168099f1e7..7d1252ee31 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. - - if (!model) - { - return FALSE; - } + // NOTE: This function doesn't check the folder's children. + // See LLFolderBridge::isItemRemovable for a function that does + // consider the children. - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - if (!isAgentAvatarValid()) return FALSE; + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } - const LLInventoryCategory* category = model->getCategory(id); - if (!category) - { - return FALSE; - } + if (!isAgentAvatarValid()) return FALSE; - const LLFolderType::EType folder_type = category->getPreferredType(); + const LLInventoryCategory* category = model->getCategory(id); + if (!category) + { + return FALSE; + } - if (LLFolderType::lookupIsProtectedType(folder_type)) - { - return FALSE; - } + const LLFolderType::EType folder_type = category->getPreferredType(); + + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + return FALSE; + } - // 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; - } - } + // 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; + 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,120 +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) +{ + 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, @@ -2727,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) @@ -2798,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... @@ -2962,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" @@ -3007,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; @@ -3066,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; @@ -3294,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) { @@ -3345,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); @@ -3368,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; @@ -3377,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"); } @@ -3417,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) @@ -3444,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 0c4b64586d..edc83147f2 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,28 @@ 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; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// 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; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -397,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); + }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -424,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; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -451,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; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -482,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); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -496,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 @@ -529,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 @@ -569,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 0787266adb..3a930684a4 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; + //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 +// 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); - } + 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 +// 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(); + 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) + 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); - } + 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 +// 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,65 +4775,76 @@ 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) + { + } } +*/ ///---------------------------------------------------------------------------- /// Local function definitions @@ -4843,41 +4854,41 @@ std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const #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 @@ -4887,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/llluamanager.cpp b/indra/newview/llluamanager.cpp new file mode 100644 index 0000000000..97779a12ad --- /dev/null +++ b/indra/newview/llluamanager.cpp @@ -0,0 +1,509 @@ +/** + * @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 "fsyspath.h" +#include "llcoros.h" +#include "llerror.h" +#include "lleventcoro.h" +#include "llviewercontrol.h" +#include "lua_function.h" +#include "lualistener.h" +#include "stringize.h" + +#include <boost/algorithm/string/replace.hpp> + +#include "luau/luacode.h" +#include "luau/lua.h" +#include "luau/luaconf.h" +#include "luau/lualib.h" + +#include <sstream> +#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); + lua_pop(L, 1); + llcoro::suspendUntilTimeout(seconds); + lluau::set_interrupts_counter(L, 0); + return 0; +}; + +// 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, 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; + 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, top = lua_gettop(L); p <= top; ++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(). + // 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); + out << lua_tostring(L, -1); + lua_pop(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)); + + llcoro::suspend(); + return msg; +} + +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, "print_info(args...): INFO level logging") +{ + LL_INFOS("Lua") << lua_print_msg(L, "INFO") << LL_ENDL; + return 0; +} + +lua_function(print_warning, "print_warning(args...): WARNING level logging") +{ + LL_WARNS("Lua") << lua_print_msg(L, "WARN") << LL_ENDL; + return 0; +} + +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) }; + lua_pop(L, 2); + LL_DEBUGS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL; + LLEventPumps::instance().obtain(pumpname).post(data); + return 0; +} + +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()).") +{ + luaL_checkstack(L, 2, nullptr); + 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); + lluau::set_interrupts_counter(L, 0); + return 2; +} + +LLCoros::Future<std::pair<int, LLSD>> +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(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) +{ + return startScriptFile(filename).get(); +} + +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]() + { + ScriptObserver observer(LLCoros::getName(), filename); + 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 (result_cb) + { + result_cb(count, result); + } + } + else + { + auto msg{ stringize("unable to open script file '", filename, "'") }; + LL_WARNS("Lua") << msg << LL_ENDL; + if (result_cb) + { + result_cb(-1, msg); + } + } + }); +} + +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) +{ + // 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& chunk) +{ + return startScriptLine(L, chunk).get(); +} + +void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_result_fn cb) +{ + // find a suitable abbreviation for the chunk string + std::string shortchunk{ chunk }; + const size_t shortlen = 40; + std::string::size_type eol = shortchunk.find_first_of("\r\n"); + if (eol != std::string::npos) + shortchunk = shortchunk.substr(0, eol); + if (shortchunk.length() > shortlen) + shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); + + std::string desc{ stringize("lua: ", shortchunk) }; + LLCoros::instance().launch(desc, [&L, desc, chunk, cb]() + { + auto [count, result] = L.expr(desc, chunk); + if (cb) + { + cb(count, result); + } + }); +} + +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; + in_file.open(name.c_str()); + + if (in_file.is_open()) + { + return std::string{std::istreambuf_iterator<char>(in_file), {}}; + } + + return {}; +} + +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(fsyspath(path).lexically_normal()), + L(L) +{ + mSourceDir = lluau::source_path(L).parent_path(); + + if (mPathToResolve.is_absolute()) + 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() +{ + // 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); + // 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; + + // not already cached - prep error message just in case + auto fail{ + [L=L, path=mPathToResolve.u8string()]() + { luaL_error(L, "could not find require('%s')", path.data()); }}; + + if (mPathToResolve.is_absolute()) + { + // no point searching known directories for an absolute path + fail(); + } + + 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. + fsyspath(__FILE__).parent_path() / "scripts" / "lua", +#endif + }; + + for (const auto& path : lib_paths) + { + std::string absolutePathOpt = (path / mPathToResolve).u8string(); + + if (absolutePathOpt.empty()) + luaL_error(L, "error requiring module '%s'", mPathToResolve.u8string().data()); + + if (findModuleImpl(absolutePathOpt)) + return; + } + + // not found + fail(); +} + +// 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[] = {absolutePath + ".luau", absolutePath + ".lua"}; + + for (const auto& suffixedPath : possibleSuffixedPaths) + { + // Check _MODULES cache for module + lua_getfield(L, -1, suffixedPath.data()); + if (!lua_isnil(L, -1)) + { + return true; + } + lua_pop(L, 1); + + // Try to read the matching file + std::string source = read_file(suffixedPath); + if (!source.empty()) + { + // 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); + + // If the stack top is an error message string, raise it. + if (lua_isstring(L, -1)) + lua_error(L); + + // duplicate the new module: _MODULES newmodule newmodule + lua_pushvalue(L, -1); + // store _MODULES[found path] = newmodule + lua_setfield(L, -3, suffixedPath.data()); + + return true; + } + } + + return false; +} + +// push string error message or new module +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); + + { + // 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); + // we expect one return value + int status = lua_pcall(ML, 0, 1, 0); + + 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)) + 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_pushfstring(ML, "module %s can not yield", desc.data()); + } + else if (!lua_isstring(ML, -1)) + { + lua_pushfstring(ML, "unknown error while running module %s", desc.data()); + } + } + } + // There's now a return value (string error message or module) on top of ML. + // Move return value to L's stack. + if (ML != L) + { + 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); +} diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h new file mode 100644 index 0000000000..af9dcf70c2 --- /dev/null +++ b/indra/newview/llluamanager.h @@ -0,0 +1,124 @@ +/** + * @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 + +#include "fsyspath.h" +#include "llcoros.h" +#include "llsd.h" +#include <functional> +#include <string> +#include <utility> // std::pair + +#include "luau/lua.h" +#include "luau/lualib.h" + +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. + 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_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); + // 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 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& chunk); + + static void runScriptOnLogin(); + + static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } + + private: + static std::map<std::string, std::string> sScriptNames; +}; + +class LLRequireResolver +{ + public: + static void resolveRequire(lua_State *L, std::string path); + + private: + fsyspath mPathToResolve; + fsyspath mSourceDir; + + LLRequireResolver(lua_State *L, const std::string& path); + + void findModule(); + lua_State *L; + + 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 diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4ad0228bd0..a8ba75ab5f 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" @@ -208,6 +208,7 @@ #include "llstacktrace.h" #include "threadpool.h" +#include "llluamanager.h" #include "llperfstats.h" @@ -236,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; @@ -290,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(); } // @@ -320,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) { @@ -334,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(); } @@ -344,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 @@ -660,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(); @@ -927,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 @@ -952,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()) @@ -1130,58 +1131,58 @@ 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. + { + // *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 { @@ -1200,215 +1201,215 @@ 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 ); - } + 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; @@ -1422,9 +1423,9 @@ bool idle_startup() } reset_login(); } - else - { - U32 num_retries = regionp->getNumSeedCapRetries(); + 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; @@ -1438,29 +1439,29 @@ bool idle_startup() } 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(); + 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 @@ -1470,291 +1471,291 @@ bool idle_startup() 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 + 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(); + // 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; @@ -1766,47 +1767,47 @@ bool idle_startup() 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; - } + // 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 response = LLLoginInstance::getInstance()->getResponse(); LLSD inv_skel_lib = response["inventory-skel-lib"]; if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) @@ -1838,113 +1839,113 @@ bool idle_startup() { 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"); - } - + 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(); + gInventory.createCommonSystemCategories(); LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); display_startup(); @@ -1952,7 +1953,7 @@ bool idle_startup() } //--------------------------------------------------------------------- - // STATE_INVENTORY_CALLBACKS + // STATE_INVENTORY_CALLBACKS //--------------------------------------------------------------------- if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) { @@ -1974,86 +1975,86 @@ bool idle_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(); + // 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(); // Load stored local environment if needed. LLEnvironment::instance().loadFromSettings(); @@ -2061,368 +2062,370 @@ bool idle_startup() // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) //check_merchant_status(); - 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(); + 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(); + 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(); + } + + 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(); LLPerfStats::StatsRecorder::setAutotuneInit(); - return TRUE; - } + LLLUAmanager::runScriptOnLogin(); - return TRUE; + return TRUE; + } + + return TRUE; } // @@ -2431,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) @@ -2556,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 ) { @@ -2595,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; @@ -2818,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) @@ -2870,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)); @@ -2938,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() @@ -2963,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; } @@ -2972,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()) @@ -3062,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 @@ -3185,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()); @@ -3867,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 2519c57e86..a4e6d20181 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,474 +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; + 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; + 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; - } - - 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; - - 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 d5e4a587d7..d20d682710 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,27 +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: - BOOL addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ); - 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/lluilistener.cpp b/indra/newview/lluilistener.cpp index beae71e7bf..97a2be6aa3 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$ */ @@ -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 { @@ -88,7 +88,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) { reply["value"] = ctrl->getValue(); } @@ -96,6 +96,6 @@ void LLUIListener::getValue(const LLSD&event) const { // *TODO: ??? return something indicating failure to resolve } - + sendReply(reply, event); } diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index 70455c2c68..e53984dae2 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$ */ @@ -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/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 6f77e21fcc..16c4084a77 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,179 +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; - - if (request.has("value")) - { - info.control->setValue(request["value"]); - } - else - { - info.control->resetToDefault(); - } + Info info(request); + if (! info.control) + return; + + 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(); + } } //static void LLViewerControlListener::toggle(LLSD const & request) { - Info info(request); - if (! info.control) - return; - - if (info.control->isType(TYPE_BOOLEAN)) - { - info.control->set(! info.control->get().asBoolean()); - } - else - { - info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname - << "' control '" << info.key - << "', type is " - << LLControlGroup::typeEnumToString(info.control->type()))); - } + Info info(request); + if (! info.control) + return; + + 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()))); + } } 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 ceda2675d5..60add691c5 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$ */ @@ -94,6 +94,8 @@ #include "llfloaterlandholdings.h" #include "llfloaterlinkreplace.h" #include "llfloaterloadprefpreset.h" +#include "llfloaterluadebug.h" +#include "llfloaterluascripts.h" #include "llfloatermap.h" #include "llfloatermarketplacelistings.h" #include "llfloatermediasettings.h" @@ -180,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, @@ -193,7 +195,7 @@ public: { return true; // will fail silently } - + std::string fl_name = params[0].asString(); // External browsers explicitly ask user about opening links @@ -280,234 +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>); - - 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>); + 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("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 37f23f9cca..52128a09ab 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; @@ -173,20 +173,22 @@ extern BOOL gShaderProfileFrame; // Globals // -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuGL *gPopupMenuView = NULL; -LLMenuGL *gEditMenu = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; +LLUIListener sUIListener; + +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"); @@ -284,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 *); @@ -344,28 +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; -static LLUIListener sUIListener; - 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,122 +978,122 @@ 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; - } + 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) { return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; @@ -1102,45 +1102,45 @@ U64 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; } - else - { - LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; - return 0; - } + 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; + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); - if ( info_display != 0 ) - { - LLPipeline::toggleRenderDebug( info_display ); - } + LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; + + if ( info_display != 0 ) + { + LLPipeline::toggleRenderDebug( info_display ); + } - return true; - } + 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; + 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 ); - } + if ( info_display != 0 ) + { + new_value = LLPipeline::toggleRenderDebugControl( info_display ); + } - return new_value; - } + return new_value; + } }; @@ -1151,20 +1151,20 @@ class LLAdvancedCheckInfoDisplay : public view_listener_t class LLAdvancedToggleRandomizeFramerate : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gRandomizeFramerate = !(gRandomizeFramerate); - return true; - } + 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; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gRandomizeFramerate; + return new_value; + } }; /////////////////////////// @@ -1174,36 +1174,36 @@ class LLAdvancedCheckRandomizeFramerate : public view_listener_t class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gPeriodicSlowFrame = !(gPeriodicSlowFrame); - return true; - } + 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; - } + 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,20 +1606,20 @@ 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; + } }; @@ -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 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; + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; + + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - 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; - - LLSaleInfo sale_info; - BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); - if (!valid) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - S32 price = sale_info.getSalePrice(); + LLSaleInfo sale_info; + BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); + if (!valid) return; - 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 (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); - } + 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); + bool handleEvent(const LLSD& userdata) + { + bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); - if (hasPathfinding) - { - LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); - } + 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(); + + // Only enable detach if all faces of object are selected + if (!object || + !object->isAttachment() || + !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + return FALSE; + } - // 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; - } + // 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(); - } + 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,571 +8612,580 @@ 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 -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 handleEvent(const LLSD& userdata) +bool handle_env_setting_event(std::string event_name) +{ + if (event_name == "sunrise") { - 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 == "legacy noon") - { - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_LEGACY_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") - { - // reset probe data when reverting back to region sky setting - gPipeline.mReflectionMapManager.reset(); + 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 == "legacy noon") + { + LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_LEGACY_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") + { + // reset probe data when reverting back to region sky setting + gPipeline.mReflectionMapManager.reset(); - 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(); + 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; + 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) + { + handle_env_setting_event(userdata.asString()); + + 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 @@ -9200,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 6683c5f2e6..b43de3fe3f 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$ */ @@ -143,6 +143,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 * ); @@ -155,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> - {}; - - LLViewerMenuHolderGL(const Params& p); + struct Params : public LLInitParam::Block<Params, LLMenuHolderGL::Params> + {}; - virtual BOOL hideMenus(); + LLViewerMenuHolderGL(const Params& p); - void setParcelSelection(LLSafeHandle<LLParcelSelection> selection); - void setObjectSelection(LLSafeHandle<LLObjectSelection> selection); + virtual BOOL hideMenus(); + + 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 b746d167ba..a1dc7119ce 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,213 +746,219 @@ 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() +{ + 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(); - 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 @@ -960,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; @@ -1045,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, @@ -1073,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( @@ -1201,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 1acb701d50..d41aa23829 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,50 +66,52 @@ 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(); //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) 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; }; @@ -117,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()); @@ -130,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/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua new file mode 100644 index 0000000000..6ed1c10d5c --- /dev/null +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -0,0 +1,34 @@ +-- 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 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. + 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 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/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua new file mode 100644 index 0000000000..c1d74fe00a --- /dev/null +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -0,0 +1,24 @@ +leap = require 'leap' + +local function check_response(res) + if res.error then + error(res.error) + end + return res +end + +local LLDebugSettings = {} + +function LLDebugSettings.set(name, value) + 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})) +end + +function LLDebugSettings.get(name) + return check_response(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 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/Queue.lua b/indra/newview/scripts/lua/Queue.lua new file mode 100644 index 0000000000..5ab2a8a72c --- /dev/null +++ b/indra/newview/scripts/lua/Queue.lua @@ -0,0 +1,47 @@ +-- 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() + local obj = setmetatable({}, self) + self.__index = self + + obj._first = 0 + obj._last = -1 + obj._queue = {} + + return obj +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() + 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 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/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua new file mode 100644 index 0000000000..ad4fdecf43 --- /dev/null +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -0,0 +1,85 @@ +-- 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 dbg = require('printf') +local function dbg(...) end + +local WaitQueue = Queue:new() + +function WaitQueue:new() + local obj = Queue:new() + setmetatable(obj, 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 + -- 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 new file mode 100644 index 0000000000..616a797e95 --- /dev/null +++ b/indra/newview/scripts/lua/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/fiber.lua b/indra/newview/scripts/lua/fiber.lua new file mode 100644 index 0000000000..9057e6c890 --- /dev/null +++ b/indra/newview/scripts/lua/fiber.lua @@ -0,0 +1,338 @@ +-- 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 dbg = printf +local function dbg(...) 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 +-- 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. +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 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..ade91789f0 --- /dev/null +++ b/indra/newview/scripts/lua/leap.lua @@ -0,0 +1,446 @@ +-- 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 function dbg(...) end +-- local dbg = require('printf') + +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. +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'} +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: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, 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 ok then + return response + else + error(response) + end +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, waitfor = requestSetup(pump, data) + local ok, response, resumed_with + repeat + ok, response = pcall(waitfor.wait, waitfor) + if not ok then + break + 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) + end +end + +local function cleanup(message) + -- we're done: clean up all pending coroutines + for i, waitfor in pairs(pending) do + waitfor:close() + end + for i, waitfor in pairs(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, 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 + return unsolicited(pump, data) + end + -- have reqid; do we have a WaitForReqid? + local waitfor = pending[reqid] + if waitfor == nil then + return unsolicited(pump, data) + end + -- found the right WaitForReqid object, let it handle the event + 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) + for i, w in pairs(waitfors) do + if w == waitfor then + 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. + +-- --------------------------------- 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:new() + obj._registered = false + -- if no priority, then don't enable() - remember 0 is truthy + if priority then + obj:enable() + end + + return obj +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 + 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._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:new() + +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 .. ')') + setmetatable(obj, self) + self.__index = self + + return obj +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 diff --git a/indra/newview/scripts/lua/luafloater_demo.xml b/indra/newview/scripts/lua/luafloater_demo.xml new file mode 100644 index 0000000000..b2273d7718 --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_demo.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="300" + 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"/> + <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/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/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/scripts/lua/qtest.lua b/indra/newview/scripts/lua/qtest.lua new file mode 100644 index 0000000000..009446d0c3 --- /dev/null +++ b/indra/newview/scripts/lua/qtest.lua @@ -0,0 +1,146 @@ +-- Exercise the Queue, WaitQueue, ErrorQueue family + +Queue = require('Queue') +WaitQueue = require('WaitQueue') +ErrorQueue = require('ErrorQueue') +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() + +q1:Enqueue(17) + +assert(not q1:IsEmpty()) +assert(q2:IsEmpty()) +assert(q1:Dequeue() == 17) +assert(q1:Dequeue() == nil) +assert(q2:Dequeue() == nil) + +-- ----------------------------- test WaitQueue ------------------------------ +q1 = WaitQueue:new() +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(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(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. +resume(coa, 'a', q1) +-- consumer(b) will wake up to find the queue empty and closed. +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. + 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 + -- 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) + 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', table.concat(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. + 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(joinall(coros) == 2) + 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_LLFloaterAbout.lua b/indra/newview/scripts/lua/test_LLFloaterAbout.lua new file mode 100644 index 0000000000..6bbf61982d --- /dev/null +++ b/indra/newview/scripts/lua/test_LLFloaterAbout.lua @@ -0,0 +1,6 @@ +-- test LLFloaterAbout + +LLFloaterAbout = require('LLFloaterAbout') +inspect = require('inspect') + +print(inspect(LLFloaterAbout.getInfo())) diff --git a/indra/newview/scripts/lua/test_LLGesture.lua b/indra/newview/scripts/lua/test_LLGesture.lua new file mode 100644 index 0000000000..1cce674565 --- /dev/null +++ b/indra/newview/scripts/lua/test_LLGesture.lua @@ -0,0 +1,26 @@ +-- exercise LLGesture API + +LLGesture = require 'LLGesture' +inspect = require 'inspect' + + +-- 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.') 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..ab638dcdd1 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_demo.lua @@ -0,0 +1,77 @@ +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:new(-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_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_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua new file mode 100644 index 0000000000..3d9a9b0ad4 --- /dev/null +++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua @@ -0,0 +1,75 @@ +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:new(-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_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() diff --git a/indra/newview/scripts/lua/testmod.lua b/indra/newview/scripts/lua/testmod.lua new file mode 100644 index 0000000000..60f7f80db1 --- /dev/null +++ b/indra/newview/scripts/lua/testmod.lua @@ -0,0 +1,2 @@ +print('loaded scripts/lua/testmod.lua') +return function () return 'hello from scripts/lua/testmod.lua' end diff --git a/indra/newview/scripts/lua/util.lua b/indra/newview/scripts/lua/util.lua new file mode 100644 index 0000000000..a2191288f6 --- /dev/null +++ b/indra/newview/scripts/lua/util.lua @@ -0,0 +1,44 @@ +-- utility functions, in alpha order + +local util = {} + +-- 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/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..012ea6f254 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_minimize="false" + can_resize="true" + can_close="true" + bevel_style="in" + height="220" + layout="topleft" + name="LUA debug" + save_rect="true" + title="LUA DEBUG" + single_instance="true" + width="535"> + <text + type="string" + length="1" + follows="left|top" + font="SansSerif" + height="30" + layout="topleft" + left="10" + left_delta="10" + name="editor_path_label" + top="10" + 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" + follows="left|top|right" + font="SansSerif" + height="20" + layout="topleft" + left="10" + max_length_bytes="300" + name="lua_cmd" + select_on_focus="true" + top_delta="30" + width="435" /> + <button + follows="right|top" + 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="all" + max_length="65536" + width="515" + 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|right" + font="SansSerif" + height="20" + layout="topleft" + left_delta="65" + max_length_bytes="300" + name="script_path" + select_on_focus="true" + top_delta="-2" + width="320" /> + <button + follows="right|bottom" + height="25" + label="Browse..." + label_selected="Browse..." + layout="topleft" + left_pad="5" + name="browse_btn" + top_delta="-2" + width="70" /> + <button + follows="right|bottom" + height="25" + label="Run" + label_selected="Run" + layout="topleft" + left_pad="5" + name="run_btn" + width="50" /> +</floater> 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/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 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..645fee405d --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml @@ -0,0 +1,19 @@ +<?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> + <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> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 53f703e56d..5ae97b729e 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2537,6 +2537,27 @@ 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" diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp new file mode 100644 index 0000000000..cf1bf25b5c --- /dev/null +++ b/indra/newview/tests/llluamanager_test.cpp @@ -0,0 +1,468 @@ +/** + * @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 +#include <vector> +// external library headers +// other Linden headers +#include "../llcommon/tests/StringVec.h" +#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 "lua_function.h" +#include "lualistener.h" +#include "stringize.h" + +class LLTestApp : public LLApp +{ +public: + bool init() override { return true; } + bool cleanup() override { return true; } + 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 +*****************************************************************************/ +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"); + + 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, "): ") }; + // if count < 0, report Lua error message + ensure_equals(desc + result.asString(), 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; + LLStreamListener pump("testpump", + listener([&fromlua](const LLSD& data){ fromlua = data; })); + const std::string lua(stringize( + "data = ", construct, "\n" + "LL.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 + ": " + result.asString(), 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(), get_event_pumps(), get_event_next()"); + StringVec posts; + 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" + "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 + // concurrently with ours until we've had a chance to post() our + // reply. + auto future = LLLUAmanager::startScriptLine(L, lua); + StringVec expected{ + "entry", + "get_event_pumps()", + "", + "get_event_next()", + "message", + "exit" + }; + 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]); + 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) + { + LLEventMailDrop testpump("testpump"); + const std::string lua( + "-- test LLSD round trip\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; + auto future = LLLUAmanager::startScriptLine(L, 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 + // something to that reply pump. + 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. + auto [count, result] = future.get(); + ensure_equals(stringize("round_trip(", desc, "): ", result.asString()), count, 1); + ensure_equals(desc, result, 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; + }; + + template<> template<> + void object::test<4>() + { + 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) + { + 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 + // 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 whose mSend will map to Lua nil. + while (expect_array.size() > 0 && + send_array[expect_array.size() - 1].isUndefined()) + { + 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) + { + 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()) + { + 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); + } + + template<> template<> + void object::test<5>() + { + set_test_name("leap.request() from main thread"); + const std::string lua( + "-- 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" + ); + + 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); + 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" + "-- 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" + " 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" + " -- 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" + " local item = waitfor:wait()\n" + " while item do\n" + " debug('%s caught %s', waitfor.name, item)\n" + " item = waitfor:wait()\n" + " end\n" + " debug('%s done', waitfor.name)\n" + "end\n" + "\n" + "function requester(name)\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" + "-- 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" + "fiber.launch('requester(b)', requester, 'b')\n" + ); + + LLSD requests; + 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); + 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 + // 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"); + 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 we're done + replypump.post(LLSD()); + 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); + // 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("killed Lua script terminated normally", count, -1); + 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 diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f249bf470e..8123827f5a 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): @@ -166,6 +166,10 @@ class ViewerManifest(LLManifest): self.path("*/*/*/*.js") self.path("*/*/*.html") + 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 build_data_dict = {"Type":"viewer","Version":'.'.join(self.args['version']), @@ -260,14 +264,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 +495,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 +547,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 +586,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 +713,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 +772,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 +781,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 +912,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 +937,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") diff --git a/indra/test/debug.h b/indra/test/debug.h index 1579bb9c86..2f6a114761 100644 --- a/indra/test/debug.h +++ b/indra/test/debug.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-05-28 * @brief Debug output for unit test code - * + * * $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$ */ @@ -30,43 +30,56 @@ #define LL_DEBUG_H #include "print.h" +#include "stringize.h" +#include <exception> // std::uncaught_exceptions() /***************************************************************************** * Debugging stuff *****************************************************************************/ /** - * This class is intended to illuminate entry to a given block, exit from the - * same block and checkpoints along the way. It also provides a convenient - * place to turn std::cerr output on and off. - * - * If the environment variable LOGTEST is non-empty, each Debug instance will - * announce its construction and destruction, presumably at entry and exit to - * the block in which it's declared. Moreover, any arguments passed to its - * operator()() will be streamed to std::cerr, prefixed by the block - * description. + * Return true if the environment variable LOGTEST is non-empty. * * The variable LOGTEST is used because that's the environment variable * checked by test.cpp, our TUT main() program, to turn on LLError logging. It * is expected that Debug is solely for use in test programs. */ +inline +bool LOGTEST_enabled() +{ + auto LOGTEST{ getenv("LOGTEST") }; + // debug output enabled when LOGTEST is set AND non-empty + return LOGTEST && *LOGTEST; +} + +/** + * This class is intended to illuminate entry to a given block, exit from the + * same block and checkpoints along the way. It also provides a convenient + * place to turn std::cerr output on and off. + * + * If enabled, each Debug instance will announce its construction and + * destruction, presumably at entry and exit to the block in which it's + * declared. Moreover, any arguments passed to its operator()() will be + * streamed to std::cerr, prefixed by the block description. + */ class Debug { public: - Debug(const std::string& block): - mBlock(block), - mLOGTEST(getenv("LOGTEST")), - // debug output enabled when LOGTEST is set AND non-empty - mEnabled(mLOGTEST && *mLOGTEST) + template <typename... ARGS> + Debug(ARGS&&... args): + mBlock(stringize(std::forward<ARGS>(args)...)), + mEnabled(LOGTEST_enabled()) { (*this)("entry"); } // non-copyable Debug(const Debug&) = delete; + Debug& operator=(const Debug&) = delete; ~Debug() { - (*this)("exit"); + auto exceptional{ std::uncaught_exceptions()? "exceptional " : "" }; + (*this)(exceptional, "exit"); } template <typename... ARGS> @@ -80,7 +93,6 @@ public: private: const std::string mBlock; - const char* mLOGTEST; bool mEnabled; }; @@ -88,20 +100,19 @@ private: // of the Debug block. #define DEBUG Debug debug(LL_PRETTY_FUNCTION) -// These BEGIN/END macros are specifically for debugging output -- please -// don't assume you must use such for coroutines in general! They only help to -// make control flow (as well as exception exits) explicit. -#define BEGIN \ -{ \ - DEBUG; \ - try +/// If enabled, debug_expr(expression) gives you output concerning an inline +/// expression such as a class member initializer. +#define debug_expr(expr) debug_expr_(#expr, [&](){ return expr; }) -#define END \ - catch (...) \ - { \ - debug("*** exceptional "); \ - throw; \ - } \ +template <typename EXPR> +inline auto debug_expr_(const char* strexpr, EXPR&& lambda) +{ + if (! LOGTEST_enabled()) + return std::forward<EXPR>(lambda)(); + print("Before: ", strexpr); + auto result{ std::forward<EXPR>(lambda)() }; + print(strexpr, " -> ", result); + return result; } #endif /* ! defined(LL_DEBUG_H) */ diff --git a/indra/test/io.cpp b/indra/test/io.cpp index 412f9ca1d2..88c22e7508 100644 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -1,4 +1,4 @@ -/** +/** * @file io.cpp * @author Phoenix * @date 2005-10-02 @@ -7,21 +7,21 @@ * $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$ */ @@ -45,1135 +45,1157 @@ #include "llcommon.h" #include "lluuid.h" #include "llinstantmessage.h" +#include "stringize.h" namespace tut { - struct heap_buffer_data - { - heap_buffer_data() : mBuffer(NULL) {} - ~heap_buffer_data() { if(mBuffer) delete mBuffer; } - LLHeapBuffer* mBuffer; - }; - typedef test_group<heap_buffer_data> heap_buffer_test; - typedef heap_buffer_test::object heap_buffer_object; - tut::heap_buffer_test thb("heap_buffer"); - - template<> template<> - void heap_buffer_object::test<1>() - { - const S32 BUF_SIZE = 100; - mBuffer = new LLHeapBuffer(BUF_SIZE); - ensure_equals("empty buffer capacity", mBuffer->capacity(), BUF_SIZE); - const S32 SEGMENT_SIZE = 50; - LLSegment segment; - mBuffer->createSegment(0, SEGMENT_SIZE, segment); - ensure_equals("used buffer capacity", mBuffer->capacity(), BUF_SIZE); - } - - template<> template<> - void heap_buffer_object::test<2>() - { - const S32 BUF_SIZE = 10; - mBuffer = new LLHeapBuffer(BUF_SIZE); - LLSegment segment; - mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("segment is in buffer", mBuffer->containsSegment(segment)); - ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); - bool created; - created = mBuffer->createSegment(0, 0, segment); - ensure("Create zero size segment fails", !created); - created = mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("Create segment fails", !created); - } - - template<> template<> - void heap_buffer_object::test<3>() - { - const S32 BUF_SIZE = 10; - mBuffer = new LLHeapBuffer(BUF_SIZE); - LLSegment segment; - mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("segment is in buffer", mBuffer->containsSegment(segment)); - ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); - bool reclaimed = mBuffer->reclaimSegment(segment); - ensure("buffer reclaimed.", reclaimed); - ensure_equals("buffer available", mBuffer->bytesLeft(), BUF_SIZE); - bool created; - created = mBuffer->createSegment(0, 0, segment); - ensure("Create zero size segment fails", !created); - created = mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("Create another segment succeeds", created); - } - - template<> template<> - void heap_buffer_object::test<4>() - { - const S32 BUF_SIZE = 10; - const S32 SEGMENT_SIZE = 4; - mBuffer = new LLHeapBuffer(BUF_SIZE); - LLSegment seg1; - mBuffer->createSegment(0, SEGMENT_SIZE, seg1); - ensure("segment is in buffer", mBuffer->containsSegment(seg1)); - LLSegment seg2; - mBuffer->createSegment(0, SEGMENT_SIZE, seg2); - ensure("segment is in buffer", mBuffer->containsSegment(seg2)); - LLSegment seg3; - mBuffer->createSegment(0, SEGMENT_SIZE, seg3); - ensure("segment is in buffer", mBuffer->containsSegment(seg3)); - ensure_equals("segment is truncated", seg3.size(), 2); - LLSegment seg4; - bool created; - created = mBuffer->createSegment(0, SEGMENT_SIZE, seg4); - ensure("Create segment fails", !created); - bool reclaimed; - reclaimed = mBuffer->reclaimSegment(seg1); - ensure("buffer reclaim succeed.", reclaimed); - ensure_equals("no buffer available", mBuffer->bytesLeft(), 0); - reclaimed = mBuffer->reclaimSegment(seg2); - ensure("buffer reclaim succeed.", reclaimed); - ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), 0); - reclaimed = mBuffer->reclaimSegment(seg3); - ensure("buffer reclaim succeed.", reclaimed); - ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), BUF_SIZE); - created = mBuffer->createSegment(0, SEGMENT_SIZE, seg1); - ensure("segment is in buffer", mBuffer->containsSegment(seg1)); - ensure("Create segment succeds", created); - } + struct heap_buffer_data + { + heap_buffer_data() : mBuffer(NULL) {} + ~heap_buffer_data() { if(mBuffer) delete mBuffer; } + LLHeapBuffer* mBuffer; + }; + typedef test_group<heap_buffer_data> heap_buffer_test; + typedef heap_buffer_test::object heap_buffer_object; + tut::heap_buffer_test thb("heap_buffer"); + + template<> template<> + void heap_buffer_object::test<1>() + { + const S32 BUF_SIZE = 100; + mBuffer = new LLHeapBuffer(BUF_SIZE); + ensure_equals("empty buffer capacity", mBuffer->capacity(), BUF_SIZE); + const S32 SEGMENT_SIZE = 50; + LLSegment segment; + mBuffer->createSegment(0, SEGMENT_SIZE, segment); + ensure_equals("used buffer capacity", mBuffer->capacity(), BUF_SIZE); + } + + template<> template<> + void heap_buffer_object::test<2>() + { + const S32 BUF_SIZE = 10; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment segment; + mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("segment is in buffer", mBuffer->containsSegment(segment)); + ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); + bool created; + created = mBuffer->createSegment(0, 0, segment); + ensure("Create zero size segment fails", !created); + created = mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("Create segment fails", !created); + } + + template<> template<> + void heap_buffer_object::test<3>() + { + const S32 BUF_SIZE = 10; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment segment; + mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("segment is in buffer", mBuffer->containsSegment(segment)); + ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); + bool reclaimed = mBuffer->reclaimSegment(segment); + ensure("buffer reclaimed.", reclaimed); + ensure_equals("buffer available", mBuffer->bytesLeft(), BUF_SIZE); + bool created; + created = mBuffer->createSegment(0, 0, segment); + ensure("Create zero size segment fails", !created); + created = mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("Create another segment succeeds", created); + } + + template<> template<> + void heap_buffer_object::test<4>() + { + const S32 BUF_SIZE = 10; + const S32 SEGMENT_SIZE = 4; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment seg1; + mBuffer->createSegment(0, SEGMENT_SIZE, seg1); + ensure("segment is in buffer", mBuffer->containsSegment(seg1)); + LLSegment seg2; + mBuffer->createSegment(0, SEGMENT_SIZE, seg2); + ensure("segment is in buffer", mBuffer->containsSegment(seg2)); + LLSegment seg3; + mBuffer->createSegment(0, SEGMENT_SIZE, seg3); + ensure("segment is in buffer", mBuffer->containsSegment(seg3)); + ensure_equals("segment is truncated", seg3.size(), 2); + LLSegment seg4; + bool created; + created = mBuffer->createSegment(0, SEGMENT_SIZE, seg4); + ensure("Create segment fails", !created); + bool reclaimed; + reclaimed = mBuffer->reclaimSegment(seg1); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("no buffer available", mBuffer->bytesLeft(), 0); + reclaimed = mBuffer->reclaimSegment(seg2); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), 0); + reclaimed = mBuffer->reclaimSegment(seg3); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), BUF_SIZE); + created = mBuffer->createSegment(0, SEGMENT_SIZE, seg1); + ensure("segment is in buffer", mBuffer->containsSegment(seg1)); + ensure("Create segment succeds", created); + } } namespace tut { - struct buffer_data - { - LLBufferArray mBuffer; - }; - typedef test_group<buffer_data> buffer_test; - typedef buffer_test::object buffer_object; - tut::buffer_test tba("buffer_array"); - - template<> template<> - void buffer_object::test<1>() - { - const char HELLO_WORLD[] = "hello world"; - const S32 str_len = strlen(HELLO_WORLD); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("total append size", count, str_len); - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - U8* first = (*it).data(); - count = mBuffer.countAfter(ch.in(), first); - ensure_equals("offset append size", count, str_len - 1); - } - - template<> template<> - void buffer_object::test<2>() - { - const char HELLO_WORLD[] = "hello world"; - const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("total append size", count, 2 * str_len); - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - U8* first = (*it).data(); - count = mBuffer.countAfter(ch.in(), first); - ensure_equals("offset append size", count, (2 * str_len) - 1); - } - - template<> template<> - void buffer_object::test<3>() - { - const char ONE[] = "one"; - const char TWO[] = "two"; - std::string expected(ONE); - expected.append(TWO); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)ONE, 3); - mBuffer.append(ch.in(), (U8*)TWO, 3); - char buffer[255]; /* Flawfinder: ignore */ - S32 len = 6; - mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); - ensure_equals(len, 6); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("read", actual, expected); - } - - template<> template<> - void buffer_object::test<4>() - { - const char ONE[] = "one"; - const char TWO[] = "two"; - std::string expected(ONE); - expected.append(TWO); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)TWO, 3); - mBuffer.prepend(ch.in(), (U8*)ONE, 3); - char buffer[255]; /* Flawfinder: ignore */ - S32 len = 6; - mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); - ensure_equals(len, 6); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("read", actual, expected); - } - - template<> template<> - void buffer_object::test<5>() - { - const char ONE[] = "one"; - const char TWO[] = "two"; - std::string expected("netwo"); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)TWO, 3); - mBuffer.prepend(ch.in(), (U8*)ONE, 3); - char buffer[255]; /* Flawfinder: ignore */ - S32 len = 5; - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - U8* addr = (*it).data(); - mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len); - ensure_equals(len, 5); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("read", actual, expected); - } - - template<> template<> - void buffer_object::test<6>() - { - std::string request("The early bird catches the worm."); - std::string response("If you're a worm, sleep late."); - std::ostringstream expected; - expected << "ContentLength: " << response.length() << "\r\n\r\n" - << response; - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)request.c_str(), request.length()); - mBuffer.append(ch.out(), (U8*)response.c_str(), response.length()); - S32 count = mBuffer.countAfter(ch.out(), NULL); - std::ostringstream header; - header << "ContentLength: " << count << "\r\n\r\n"; - std::string head(header.str()); - mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length()); - char buffer[1024]; /* Flawfinder: ignore */ - S32 len = response.size() + head.length(); - ensure_equals("same length", len, (S32)expected.str().length()); - mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("threaded writes", actual, expected.str()); - } - - template<> template<> - void buffer_object::test<7>() - { - const S32 LINE_COUNT = 3; - std::string lines[LINE_COUNT] = - { - std::string("GET /index.htm HTTP/1.0\r\n"), - std::string("User-Agent: Wget/1.9.1\r\n"), - std::string("Host: localhost:8008\r\n") - }; - std::string text; - S32 i; - for(i = 0; i < LINE_COUNT; ++i) - { - text.append(lines[i]); - } - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)text.c_str(), text.length()); - const S32 BUFFER_LEN = 1024; - char buf[BUFFER_LEN]; - S32 len; - U8* last = NULL; - std::string last_line; - for(i = 0; i < LINE_COUNT; ++i) - { - len = BUFFER_LEN; - last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len); - char* newline = strchr((char*)buf, '\n'); - S32 offset = -((len - 1) - (newline - buf)); - ++newline; - *newline = '\0'; - last_line.assign(buf); - std::ostringstream message; - message << "line reads in line[" << i << "]"; - ensure_equals(message.str().c_str(), last_line, lines[i]); - last = mBuffer.seek(ch.in(), last, offset); - } - } - - template<> template<> - void buffer_object::test<8>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)"1", 1); - LLBufferArray buffer; - buffer.append(ch.in(), (U8*)"2", 1); - mBuffer.takeContents(buffer); - mBuffer.append(ch.in(), (U8*)"3", 1); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("buffer size", count, 3); - U8* temp = new U8[count]; - mBuffer.readAfter(ch.in(), NULL, temp, count); - ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); - delete[] temp; - } - - template<> template<> - void buffer_object::test<9>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)"1", 1); - S32 capacity = mBuffer.capacity(); - ensure("has capacity", capacity > 0); - U8* temp = new U8[capacity - 1]; - mBuffer.append(ch.in(), temp, capacity - 1); - capacity = mBuffer.capacity(); - ensure("has capacity when full", capacity > 0); - S32 used = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("used equals capacity", used, capacity); - - LLBufferArray::segment_iterator_t iter = mBuffer.beginSegment(); - while(iter != mBuffer.endSegment()) - { - mBuffer.eraseSegment(iter++); - } - - used = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("used is zero", used, 0); - S32 capacity2 = mBuffer.capacity(); - ensure_equals("capacity the same after erase", capacity2, capacity); - mBuffer.append(ch.in(), temp, capacity - 1); - capacity2 = mBuffer.capacity(); - ensure_equals("capacity the same after append", capacity2, capacity); - - delete[] temp; - } + struct buffer_data + { + LLBufferArray mBuffer; + }; + typedef test_group<buffer_data> buffer_test; + typedef buffer_test::object buffer_object; + tut::buffer_test tba("buffer_array"); + + template<> template<> + void buffer_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = strlen(HELLO_WORLD); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("total append size", count, str_len); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* first = (*it).data(); + count = mBuffer.countAfter(ch.in(), first); + ensure_equals("offset append size", count, str_len - 1); + } + + template<> template<> + void buffer_object::test<2>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("total append size", count, 2 * str_len); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* first = (*it).data(); + count = mBuffer.countAfter(ch.in(), first); + ensure_equals("offset append size", count, (2 * str_len) - 1); + } + + template<> template<> + void buffer_object::test<3>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected(ONE); + expected.append(TWO); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)ONE, 3); + mBuffer.append(ch.in(), (U8*)TWO, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 6; + mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); + ensure_equals(len, 6); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<4>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected(ONE); + expected.append(TWO); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)TWO, 3); + mBuffer.prepend(ch.in(), (U8*)ONE, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 6; + mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); + ensure_equals(len, 6); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<5>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected("netwo"); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)TWO, 3); + mBuffer.prepend(ch.in(), (U8*)ONE, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 5; + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* addr = (*it).data(); + mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len); + ensure_equals(len, 5); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<6>() + { + std::string request("The early bird catches the worm."); + std::string response("If you're a worm, sleep late."); + std::ostringstream expected; + expected << "ContentLength: " << response.length() << "\r\n\r\n" + << response; + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)request.c_str(), request.length()); + mBuffer.append(ch.out(), (U8*)response.c_str(), response.length()); + S32 count = mBuffer.countAfter(ch.out(), NULL); + std::ostringstream header; + header << "ContentLength: " << count << "\r\n\r\n"; + std::string head(header.str()); + mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length()); + char buffer[1024]; /* Flawfinder: ignore */ + S32 len = response.size() + head.length(); + ensure_equals("same length", len, (S32)expected.str().length()); + mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("threaded writes", actual, expected.str()); + } + + template<> template<> + void buffer_object::test<7>() + { + const S32 LINE_COUNT = 3; + std::string lines[LINE_COUNT] = + { + std::string("GET /index.htm HTTP/1.0\r\n"), + std::string("User-Agent: Wget/1.9.1\r\n"), + std::string("Host: localhost:8008\r\n") + }; + std::string text; + S32 i; + for(i = 0; i < LINE_COUNT; ++i) + { + text.append(lines[i]); + } + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)text.c_str(), text.length()); + const S32 BUFFER_LEN = 1024; + char buf[BUFFER_LEN]; + S32 len; + U8* last = NULL; + std::string last_line; + for(i = 0; i < LINE_COUNT; ++i) + { + len = BUFFER_LEN; + last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len); + char* newline = strchr((char*)buf, '\n'); + S32 offset = -((len - 1) - (newline - buf)); + ++newline; + *newline = '\0'; + last_line.assign(buf); + std::ostringstream message; + message << "line reads in line[" << i << "]"; + ensure_equals(message.str().c_str(), last_line, lines[i]); + last = mBuffer.seek(ch.in(), last, offset); + } + } + + template<> template<> + void buffer_object::test<8>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)"1", 1); + LLBufferArray buffer; + buffer.append(ch.in(), (U8*)"2", 1); + mBuffer.takeContents(buffer); + mBuffer.append(ch.in(), (U8*)"3", 1); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("buffer size", count, 3); + U8* temp = new U8[count]; + mBuffer.readAfter(ch.in(), NULL, temp, count); + ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); + delete[] temp; + } + + template<> template<> + void buffer_object::test<9>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)"1", 1); + S32 capacity = mBuffer.capacity(); + ensure("has capacity", capacity > 0); + U8* temp = new U8[capacity - 1]; + mBuffer.append(ch.in(), temp, capacity - 1); + capacity = mBuffer.capacity(); + ensure("has capacity when full", capacity > 0); + S32 used = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("used equals capacity", used, capacity); + + LLBufferArray::segment_iterator_t iter = mBuffer.beginSegment(); + while(iter != mBuffer.endSegment()) + { + mBuffer.eraseSegment(iter++); + } + + used = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("used is zero", used, 0); + S32 capacity2 = mBuffer.capacity(); + ensure_equals("capacity the same after erase", capacity2, capacity); + mBuffer.append(ch.in(), temp, capacity - 1); + capacity2 = mBuffer.capacity(); + ensure_equals("capacity the same after append", capacity2, capacity); + + delete[] temp; + } #if 0 - template<> template<> - void buffer_object::test<9>() - { - char buffer[1024]; /* Flawfinder: ignore */ - S32 size = sprintf(buffer, - "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", - 7, - 7, - "Hang Glider INFO", - "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a", - "0e346d8b-4433-4d66-a6b0-fd37083abc4c", - "0e346d8b-4433-4d66-a6b0-fd37083abc4c", - "00000000-0000-0000-0000-000000000000", - 0x7fffffff, - 0x7fffffff, - 0, - 0, - 0x7fffffff, - "69e0d357-2e7c-8990-a2bc-7f61c868e5a3", - "2004-06-04 16:09:17 note card", - 0, - 10, - 0) + 1; - - //const char* expected = "7|7|Hang Glider INFO|18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a|0e346d8b-4433-4d66-a6b0-fd37083abc4c|0e346d8b-4433-4d66-a6b0-fd37083abc4c|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|7fffffff|69e0d357-2e7c-8990-a2bc-7f61c868e5a3|2004-06-04 16:09:17 note card|0|10|0\0"; - - LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size); - - char post_buffer[1024]; - U32 post_size; - LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size); - ensure_equals("Buffer sizes",size,(S32)post_size); - ensure("Buffer content",!strcmp(buffer,post_buffer)); - } + template<> template<> + void buffer_object::test<9>() + { + char buffer[1024]; /* Flawfinder: ignore */ + S32 size = sprintf(buffer, + "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", + 7, + 7, + "Hang Glider INFO", + "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a", + "0e346d8b-4433-4d66-a6b0-fd37083abc4c", + "0e346d8b-4433-4d66-a6b0-fd37083abc4c", + "00000000-0000-0000-0000-000000000000", + 0x7fffffff, + 0x7fffffff, + 0, + 0, + 0x7fffffff, + "69e0d357-2e7c-8990-a2bc-7f61c868e5a3", + "2004-06-04 16:09:17 note card", + 0, + 10, + 0) + 1; + + //const char* expected = "7|7|Hang Glider INFO|18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a|0e346d8b-4433-4d66-a6b0-fd37083abc4c|0e346d8b-4433-4d66-a6b0-fd37083abc4c|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|7fffffff|69e0d357-2e7c-8990-a2bc-7f61c868e5a3|2004-06-04 16:09:17 note card|0|10|0\0"; + + LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size); + + char post_buffer[1024]; + U32 post_size; + LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size); + ensure_equals("Buffer sizes",size,(S32)post_size); + ensure("Buffer content",!strcmp(buffer,post_buffer)); + } #endif - /* - template<> template<> - void buffer_object::test<>() - { - } - */ + /* + template<> template<> + void buffer_object::test<>() + { + } + */ } namespace tut { - struct buffer_and_stream_data - { - LLBufferArray mBuffer; - }; - typedef test_group<buffer_and_stream_data> bas_test; - typedef bas_test::object bas_object; - tut::bas_test tbs("buffer_stream"); - - template<> template<> - void bas_object::test<1>() - { - const char HELLO_WORLD[] = "hello world"; - const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream str(ch, &mBuffer); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - std::string hello; - std::string world; - str >> hello >> world; - ensure_equals("first word", hello, std::string("hello")); - ensure_equals("second word", world, std::string("world")); - } - - template<> template<> - void bas_object::test<2>() - { - std::string part1("Eat my shor"); - std::string part2("ts ho"); - std::string part3("mer"); - std::string ignore("ignore me"); - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream str(ch, &mBuffer); - mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length()); - mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length()); - mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length()); - mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length()); - std::string eat; - std::string my; - std::string shorts; - std::string homer; - str >> eat >> my >> shorts >> homer; - ensure_equals("word1", eat, std::string("Eat")); - ensure_equals("word2", my, std::string("my")); - ensure_equals("word3", shorts, std::string("shorts")); - ensure_equals("word4", homer, std::string("homer")); - } - - template<> template<> - void bas_object::test<3>() - { - std::string part1("junk in "); - std::string part2("the trunk"); - const S32 CHANNEL = 0; - mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length()); - mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length()); - U8* last = 0; - const S32 BUF_LEN = 128; - char buf[BUF_LEN]; - S32 len = 11; - last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); - buf[len] = '\0'; - std::string actual(buf); - ensure_equals("first read", actual, std::string("junk in the")); - last = mBuffer.seek(CHANNEL, last, -6); - len = 12; - last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); - buf[len] = '\0'; - actual.assign(buf); - ensure_equals("seek and read", actual, std::string("in the trunk")); - } - - template<> template<> - void bas_object::test<4>() - { - std::string phrase("zippity do da!"); - const S32 CHANNEL = 0; - mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length()); - const S32 BUF_LEN = 128; - char buf[BUF_LEN]; - S32 len = 7; - U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len); - mBuffer.splitAfter(last); - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - LLBufferArray::segment_iterator_t end = mBuffer.endSegment(); - std::string first((char*)((*it).data()), (*it).size()); - ensure_equals("first part", first, std::string("zippity")); - ++it; - std::string second((char*)((*it).data()), (*it).size()); - ensure_equals("second part", second, std::string(" do da!")); - ++it; - ensure("iterators equal", (it == end)); - } - - template<> template<> - void bas_object::test<5>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream str(ch, &mBuffer); - std::string h1("hello"); - std::string h2(", how are you doing?"); - std::string expected(h1); - expected.append(h2); - str << h1 << h2; - str.flush(); - const S32 BUF_LEN = 128; - char buf[BUF_LEN]; - S32 actual_len = BUF_LEN; - S32 expected_len = h1.size() + h2.size(); - (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); - ensure_equals("streamed size", actual_len, expected_len); - buf[actual_len] = '\0'; - std::string actual(buf); - ensure_equals("streamed to buf", actual, expected); - } - - template<> template<> - void bas_object::test<6>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream bstr(ch, &mBuffer); - std::ostringstream ostr; - std::vector<LLUUID> ids; - LLUUID id; - for(int i = 0; i < 5; ++i) - { - id.generate(); - ids.push_back(id); - } - bstr << "SELECT concat(u.username, ' ', l.name) " - << "FROM user u, user_last_name l " - << "WHERE u.last_name_id = l.last_name_id" - << " AND u.agent_id IN ('"; - ostr << "SELECT concat(u.username, ' ', l.name) " - << "FROM user u, user_last_name l " - << "WHERE u.last_name_id = l.last_name_id" - << " AND u.agent_id IN ('"; - std::copy( - ids.begin(), - ids.end(), - std::ostream_iterator<LLUUID>(bstr, "','")); - std::copy( - ids.begin(), - ids.end(), - std::ostream_iterator<LLUUID>(ostr, "','")); - bstr.seekp(-2, std::ios::cur); - ostr.seekp(-2, std::ios::cur); - bstr << ") "; - ostr << ") "; - bstr.flush(); - const S32 BUF_LEN = 512; - char buf[BUF_LEN]; /* Flawfinder: ignore */ - S32 actual_len = BUF_LEN; - (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); - buf[actual_len] = '\0'; - std::string actual(buf); - std::string expected(ostr.str()); - ensure_equals("size of string in seek",actual.size(),expected.size()); - ensure_equals("seek in ostream", actual, expected); - } - - template<> template<> - void bas_object::test<7>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream bstr(ch, &mBuffer); - bstr << "1"; - bstr.flush(); - S32 count = mBuffer.countAfter(ch.out(), NULL); - ensure_equals("buffer size 1", count, 1); - LLBufferArray buffer; - buffer.append(ch.out(), (U8*)"2", 1); - mBuffer.takeContents(buffer); - count = mBuffer.countAfter(ch.out(), NULL); - ensure_equals("buffer size 2", count, 2); - bstr << "3"; - bstr.flush(); - count = mBuffer.countAfter(ch.out(), NULL); - ensure_equals("buffer size 3", count, 3); - U8* temp = new U8[count]; - mBuffer.readAfter(ch.out(), NULL, temp, count); - ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); - delete[] temp; - } - - template<> template<> - void bas_object::test<8>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream ostr(ch, &mBuffer); - typedef std::vector<U8> buf_t; - typedef std::vector<buf_t> actual_t; - actual_t actual; - buf_t source; - bool need_comma = false; - ostr << "["; - S32 total_size = 1; - for(S32 i = 2000; i < 2003; ++i) - { - if(need_comma) - { - ostr << ","; - ++total_size; - } - need_comma = true; - srand(69 + i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 1000; - std::generate_n( - std::back_insert_iterator<buf_t>(source), - size, - rand); - actual.push_back(source); - ostr << "b(" << size << ")\""; - total_size += 8; - ostr.write((const char*)(&source[0]), size); - total_size += size; - source.clear(); - ostr << "\""; - ++total_size; - } - ostr << "]"; - ++total_size; - ostr.flush(); - - // now that we have a bunch of data on a stream, parse it all. - ch = mBuffer.nextChannel(); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("size of buffer", count, total_size); - LLBufferStream istr(ch, &mBuffer); - LLSD data; - count = LLSDSerialize::fromNotation(data, istr, total_size); - ensure("sd parsed", data.isDefined()); - - for(S32 j = 0; j < 3; ++j) - { - std::ostringstream name; - LLSD child(data[j]); - name << "found buffer " << j; - ensure(name.str(), child.isDefined()); - source = child.asBinary(); - name.str(""); - name << "buffer " << j << " size"; - ensure_equals(name.str().c_str(), source.size(), actual[j].size()); - name.str(""); - name << "buffer " << j << " contents"; - ensure( - name.str(), - (0 == memcmp(&source[0], &actual[j][0], source.size()))); - } - } - - template<> template<> - void bas_object::test<9>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream ostr(ch, &mBuffer); - typedef std::vector<U8> buf_t; - buf_t source; - bool need_comma = false; - ostr << "{"; - S32 total_size = 1; - for(S32 i = 1000; i < 3000; ++i) - { - if(need_comma) - { - ostr << ","; - ++total_size; - } - need_comma = true; - ostr << "'" << i << "':"; - total_size += 7; - srand(69 + i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 1000; - std::generate_n( - std::back_insert_iterator<buf_t>(source), - size, - rand); - ostr << "b(" << size << ")\""; - total_size += 8; - ostr.write((const char*)(&source[0]), size); - total_size += size; - source.clear(); - ostr << "\""; - ++total_size; - } - ostr << "}"; - ++total_size; - ostr.flush(); - - // now that we have a bunch of data on a stream, parse it all. - ch = mBuffer.nextChannel(); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("size of buffer", count, total_size); - LLBufferStream istr(ch, &mBuffer); - LLSD data; - count = LLSDSerialize::fromNotation(data, istr, total_size); - ensure("sd parsed", data.isDefined()); - } - - template<> template<> - void bas_object::test<10>() - { + struct buffer_and_stream_data + { + LLBufferArray mBuffer; + }; + typedef test_group<buffer_and_stream_data> bas_test; + typedef bas_test::object bas_object; + tut::bas_test tbs("buffer_stream"); + + template<> template<> + void bas_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + std::string hello; + std::string world; + str >> hello >> world; + ensure_equals("first word", hello, std::string("hello")); + ensure_equals("second word", world, std::string("world")); + } + + template<> template<> + void bas_object::test<2>() + { + std::string part1("Eat my shor"); + std::string part2("ts ho"); + std::string part3("mer"); + std::string ignore("ignore me"); + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length()); + mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length()); + mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length()); + mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length()); + std::string eat; + std::string my; + std::string shorts; + std::string homer; + str >> eat >> my >> shorts >> homer; + ensure_equals("word1", eat, std::string("Eat")); + ensure_equals("word2", my, std::string("my")); + ensure_equals("word3", shorts, std::string("shorts")); + ensure_equals("word4", homer, std::string("homer")); + } + + template<> template<> + void bas_object::test<3>() + { + std::string part1("junk in "); + std::string part2("the trunk"); + const S32 CHANNEL = 0; + mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length()); + mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length()); + U8* last = 0; + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 len = 11; + last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); + buf[len] = '\0'; + std::string actual(buf); + ensure_equals("first read", actual, std::string("junk in the")); + last = mBuffer.seek(CHANNEL, last, -6); + len = 12; + last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); + buf[len] = '\0'; + actual.assign(buf); + ensure_equals("seek and read", actual, std::string("in the trunk")); + } + + template<> template<> + void bas_object::test<4>() + { + std::string phrase("zippity do da!"); + const S32 CHANNEL = 0; + mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length()); + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 len = 7; + U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len); + mBuffer.splitAfter(last); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + LLBufferArray::segment_iterator_t end = mBuffer.endSegment(); + std::string first((char*)((*it).data()), (*it).size()); + ensure_equals("first part", first, std::string("zippity")); + ++it; + std::string second((char*)((*it).data()), (*it).size()); + ensure_equals("second part", second, std::string(" do da!")); + ++it; + ensure("iterators equal", (it == end)); + } + + template<> template<> + void bas_object::test<5>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + std::string h1("hello"); + std::string h2(", how are you doing?"); + std::string expected(h1); + expected.append(h2); + str << h1 << h2; + str.flush(); + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 actual_len = BUF_LEN; + S32 expected_len = h1.size() + h2.size(); + (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); + ensure_equals("streamed size", actual_len, expected_len); + buf[actual_len] = '\0'; + std::string actual(buf); + ensure_equals("streamed to buf", actual, expected); + } + + template<> template<> + void bas_object::test<6>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream bstr(ch, &mBuffer); + std::ostringstream ostr; + std::vector<LLUUID> ids; + LLUUID id; + for(int i = 0; i < 5; ++i) + { + id.generate(); + ids.push_back(id); + } + bstr << "SELECT concat(u.username, ' ', l.name) " + << "FROM user u, user_last_name l " + << "WHERE u.last_name_id = l.last_name_id" + << " AND u.agent_id IN ('"; + ostr << "SELECT concat(u.username, ' ', l.name) " + << "FROM user u, user_last_name l " + << "WHERE u.last_name_id = l.last_name_id" + << " AND u.agent_id IN ('"; + std::copy( + ids.begin(), + ids.end(), + std::ostream_iterator<LLUUID>(bstr, "','")); + std::copy( + ids.begin(), + ids.end(), + std::ostream_iterator<LLUUID>(ostr, "','")); + bstr.seekp(-2, std::ios::cur); + ostr.seekp(-2, std::ios::cur); + bstr << ") "; + ostr << ") "; + bstr.flush(); + const S32 BUF_LEN = 512; + char buf[BUF_LEN]; /* Flawfinder: ignore */ + S32 actual_len = BUF_LEN; + (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); + buf[actual_len] = '\0'; + std::string actual(buf); + std::string expected(ostr.str()); + ensure_equals("size of string in seek",actual.size(),expected.size()); + ensure_equals("seek in ostream", actual, expected); + } + + template<> template<> + void bas_object::test<7>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream bstr(ch, &mBuffer); + bstr << "1"; + bstr.flush(); + S32 count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 1", count, 1); + LLBufferArray buffer; + buffer.append(ch.out(), (U8*)"2", 1); + mBuffer.takeContents(buffer); + count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 2", count, 2); + bstr << "3"; + bstr.flush(); + count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 3", count, 3); + U8* temp = new U8[count]; + mBuffer.readAfter(ch.out(), NULL, temp, count); + ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); + delete[] temp; + } + + template<> template<> + void bas_object::test<8>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream ostr(ch, &mBuffer); + typedef std::vector<U8> buf_t; + typedef std::vector<buf_t> actual_t; + actual_t actual; + buf_t source; + bool need_comma = false; + ostr << "["; + S32 total_size = 1; + for(S32 i = 2000; i < 2003; ++i) + { + if(need_comma) + { + ostr << ","; + ++total_size; + } + need_comma = true; + srand(69 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 1000; + std::generate_n( + std::back_insert_iterator<buf_t>(source), + size, + rand); + actual.push_back(source); + ostr << "b(" << size << ")\""; + total_size += 8; + ostr.write((const char*)(&source[0]), size); + total_size += size; + source.clear(); + ostr << "\""; + ++total_size; + } + ostr << "]"; + ++total_size; + ostr.flush(); + + // now that we have a bunch of data on a stream, parse it all. + ch = mBuffer.nextChannel(); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("size of buffer", count, total_size); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + count = LLSDSerialize::fromNotation(data, istr, total_size); + ensure("sd parsed", data.isDefined()); + + for(S32 j = 0; j < 3; ++j) + { + std::ostringstream name; + LLSD child(data[j]); + name << "found buffer " << j; + ensure(name.str(), child.isDefined()); + source = child.asBinary(); + name.str(""); + name << "buffer " << j << " size"; + ensure_equals(name.str().c_str(), source.size(), actual[j].size()); + name.str(""); + name << "buffer " << j << " contents"; + ensure( + name.str(), + (0 == memcmp(&source[0], &actual[j][0], source.size()))); + } + } + + template<> template<> + void bas_object::test<9>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream ostr(ch, &mBuffer); + typedef std::vector<U8> buf_t; + buf_t source; + bool need_comma = false; + ostr << "{"; + S32 total_size = 1; + for(S32 i = 1000; i < 3000; ++i) + { + if(need_comma) + { + ostr << ","; + ++total_size; + } + need_comma = true; + ostr << "'" << i << "':"; + total_size += 7; + srand(69 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 1000; + std::generate_n( + std::back_insert_iterator<buf_t>(source), + size, + rand); + ostr << "b(" << size << ")\""; + total_size += 8; + ostr.write((const char*)(&source[0]), size); + total_size += size; + source.clear(); + ostr << "\""; + ++total_size; + } + ostr << "}"; + ++total_size; + ostr.flush(); + + // now that we have a bunch of data on a stream, parse it all. + ch = mBuffer.nextChannel(); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("size of buffer", count, total_size); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + count = LLSDSerialize::fromNotation(data, istr, total_size); + ensure("sd parsed", data.isDefined()); + } + + template<> template<> + void bas_object::test<10>() + { //#if LL_WINDOWS && _MSC_VER >= 1400 // skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); //#endif - const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {" - "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, " - "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', " - "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', " - "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', " - "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', " - "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " - "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " - "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97']," - "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M'," - "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}]," - "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', " - "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', " - "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', " - "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', " - "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', " - "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', " - "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', " - "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', " - "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', " - "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', " - "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9']," - "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0]," - "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}"; - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM)); /* Flawfinder: ignore */ - ch = mBuffer.nextChannel(); - LLBufferStream istr(ch, &mBuffer); - LLSD data; - S32 count = LLSDSerialize::fromNotation( - data, - istr, - mBuffer.count(ch.in())); - ensure("parsed something", (count > 0)); - ensure("sd parsed", data.isDefined()); - ensure_equals("sd type", data.type(), LLSD::TypeMap); - ensure("has method", data.has("method")); - ensure("has parameter", data.has("parameter")); - LLSD parameter = data["parameter"]; - ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray); - LLSD agent_params = parameter[2]; - std::string s_value; - s_value = agent_params["last_name"].asString(); - ensure_equals("last name", s_value, std::string("Linden")); - s_value = agent_params["first_name"].asString(); - ensure_equals("first name", s_value, std::string("Kelly")); - s_value = agent_params["agent_access"].asString(); - ensure_equals("agent access", s_value, std::string("M")); - s_value = agent_params["group_name"].asString(); - ensure_equals("group name", s_value, std::string("test!")); - s_value = agent_params["group_title"].asString(); - ensure_equals("group title", s_value, std::string("-> !BLING! <-")); - - LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c"); - LLUUID id = agent_params["agent_id"]; - ensure_equals("agent id", id, agent_id); - LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1"); - id = agent_params["session_id"]; - ensure_equals("session id", id, session_id); - LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652"); - id = agent_params["group_id"]; - ensure_equals("group id", id, group_id); - - S32 i_val = agent_params["limited_to_estate"]; - ensure_equals("limited to estate", i_val, 1); - i_val = agent_params["circuit_code"]; - ensure_equals("circuit code", i_val, 124); - } - - - template<> template<> - void bas_object::test<11>() - { - std::string val = "{!'foo'@:#'bar'}"; - std::istringstream istr; - istr.str(val); - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parser error return value", count, -1); - ensure("data undefined", sd.isUndefined()); - } - - template<> template<> - void bas_object::test<12>() - { + const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {" + "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, " + "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', " + "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', " + "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', " + "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', " + "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " + "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " + "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97']," + "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M'," + "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}]," + "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', " + "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', " + "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', " + "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', " + "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', " + "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', " + "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', " + "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', " + "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', " + "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', " + "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9']," + "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0]," + "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}"; + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM)); /* Flawfinder: ignore */ + ch = mBuffer.nextChannel(); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + S32 count = LLSDSerialize::fromNotation( + data, + istr, + mBuffer.count(ch.in())); + ensure("parsed something", (count > 0)); + ensure("sd parsed", data.isDefined()); + ensure_equals("sd type", data.type(), LLSD::TypeMap); + ensure("has method", data.has("method")); + ensure("has parameter", data.has("parameter")); + LLSD parameter = data["parameter"]; + ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray); + LLSD agent_params = parameter[2]; + std::string s_value; + s_value = agent_params["last_name"].asString(); + ensure_equals("last name", s_value, std::string("Linden")); + s_value = agent_params["first_name"].asString(); + ensure_equals("first name", s_value, std::string("Kelly")); + s_value = agent_params["agent_access"].asString(); + ensure_equals("agent access", s_value, std::string("M")); + s_value = agent_params["group_name"].asString(); + ensure_equals("group name", s_value, std::string("test!")); + s_value = agent_params["group_title"].asString(); + ensure_equals("group title", s_value, std::string("-> !BLING! <-")); + + LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c"); + LLUUID id = agent_params["agent_id"]; + ensure_equals("agent id", id, agent_id); + LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1"); + id = agent_params["session_id"]; + ensure_equals("session id", id, session_id); + LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652"); + id = agent_params["group_id"]; + ensure_equals("group id", id, group_id); + + S32 i_val = agent_params["limited_to_estate"]; + ensure_equals("limited to estate", i_val, 1); + i_val = agent_params["circuit_code"]; + ensure_equals("circuit code", i_val, 124); + } + + + template<> template<> + void bas_object::test<11>() + { + std::string val = "{!'foo'@:#'bar'}"; + std::istringstream istr; + istr.str(val); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parser error return value", count, -1); + ensure("data undefined", sd.isUndefined()); + } + + template<> template<> + void bas_object::test<12>() + { //#if LL_WINDOWS && _MSC_VER >= 1400 // skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); //#endif - std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}"; - std::istringstream istr; - istr.str(val); - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parser error return value", count, -1); - ensure("data undefined", sd.isUndefined()); - } + std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}"; + std::istringstream istr; + istr.str(val); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parser error return value", count, -1); + ensure("data undefined", sd.isUndefined()); + } /* - template<> template<> - void bas_object::test<13>() - { - } - template<> template<> - void bas_object::test<14>() - { - } - template<> template<> - void bas_object::test<15>() - { - } + template<> template<> + void bas_object::test<13>() + { + } + template<> template<> + void bas_object::test<14>() + { + } + template<> template<> + void bas_object::test<15>() + { + } */ } namespace tut { - class PumpAndChainTestData - { - protected: - apr_pool_t* mPool; - LLPumpIO* mPump; - LLPumpIO::chain_t mChain; - - public: - PumpAndChainTestData() - { - apr_pool_create(&mPool, NULL); - mPump = new LLPumpIO(mPool); - } - - ~PumpAndChainTestData() - { - mChain.clear(); - delete mPump; - apr_pool_destroy(mPool); - } - }; - typedef test_group<PumpAndChainTestData> PumpAndChainTestGroup; - typedef PumpAndChainTestGroup::object PumpAndChainTestObject; - PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain"); - - template<> template<> - void PumpAndChainTestObject::test<1>() - { - LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); - - mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); - mChain.push_back(LLIOPipe::ptr_t(extractor)); - - LLTimer timer; - timer.setTimerExpirySec(100.0f); - - mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); - while(!extractor->done() && !timer.hasExpired()) - { - mPump->pump(); - mPump->callback(); - } - - ensure("reading string finished", extractor->done()); - ensure_equals("string was empty", extractor->string(), ""); - } + class PumpAndChainTestData + { + protected: + apr_pool_t* mPool; + LLPumpIO* mPump; + LLPumpIO::chain_t mChain; + + public: + PumpAndChainTestData() + { + apr_pool_create(&mPool, NULL); + mPump = new LLPumpIO(mPool); + } + + ~PumpAndChainTestData() + { + mChain.clear(); + delete mPump; + apr_pool_destroy(mPool); + } + }; + typedef test_group<PumpAndChainTestData> PumpAndChainTestGroup; + typedef PumpAndChainTestGroup::object PumpAndChainTestObject; + PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain"); + + template<> template<> + void PumpAndChainTestObject::test<1>() + { + LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); + + mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); + mChain.push_back(LLIOPipe::ptr_t(extractor)); + + LLTimer timer; + timer.setTimerExpirySec(100.0f); + + mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); + while(!extractor->done() && !timer.hasExpired()) + { + mPump->pump(); + mPump->callback(); + } + + ensure("reading string finished", extractor->done()); + ensure_equals("string was empty", extractor->string(), ""); + } } /* namespace tut { - struct double_construct - { - public: - double_construct() - { - LL_INFOS() << "constructed" << LL_ENDL; - } - ~double_construct() - { - LL_INFOS() << "destroyed" << LL_ENDL; - } - }; - typedef test_group<double_construct> double_construct_test_group; - typedef double_construct_test_group::object dc_test_object; - double_construct_test_group dctest("double construct"); - template<> template<> - void dc_test_object::test<1>() - { - ensure("test 1", true); - } + struct double_construct + { + public: + double_construct() + { + LL_INFOS() << "constructed" << LL_ENDL; + } + ~double_construct() + { + LL_INFOS() << "destroyed" << LL_ENDL; + } + }; + typedef test_group<double_construct> double_construct_test_group; + typedef double_construct_test_group::object dc_test_object; + double_construct_test_group dctest("double construct"); + template<> template<> + void dc_test_object::test<1>() + { + ensure("test 1", true); + } } */ namespace tut { - /** - * @brief we want to test the pipes & pumps under bad conditions. - */ - struct pipe_and_pump_fitness - { - public: - enum - { - SERVER_LISTEN_PORT = 13050 - }; - - pipe_and_pump_fitness() - { - LLFrameTimer::updateFrameTime(); - apr_pool_create(&mPool, NULL); - mPump = new LLPumpIO(mPool); - mSocket = LLSocket::create( - mPool, - LLSocket::STREAM_TCP, - SERVER_LISTEN_PORT, - "127.0.0.1"); - } - - ~pipe_and_pump_fitness() - { - mSocket.reset(); - delete mPump; - apr_pool_destroy(mPool); - } - - protected: - apr_pool_t* mPool; - LLPumpIO* mPump; - LLSocket::ptr_t mSocket; - }; - typedef test_group<pipe_and_pump_fitness> fitness_test_group; - typedef fitness_test_group::object fitness_test_object; - fitness_test_group fitness("pipe and pump fitness"); - - template<> template<> - void fitness_test_object::test<1>() - { - LL_DEBUGS() << "fitness_test_object::test<1>()" << LL_ENDL; - - // Set up the server - //LL_DEBUGS() << "fitness_test_object::test<1> - setting up server." - // << LL_ENDL; - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory<LLPipeStringInjector> emitter_t; - emitter_t* emitter = new emitter_t( - new LLPipeStringInjector("suckers never play me")); - std::shared_ptr<LLChainIOFactory> factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - //LL_DEBUGS() << "fitness_test_object::test<1> - initializing server." - // << LL_ENDL; - pump_loop(mPump, 0.1f); - - // Set up the client - //LL_DEBUGS() << "fitness_test_object::test<1> - connecting client." - // << LL_ENDL; - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, 1.0f); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, 2.0f); - ensure("Did not take too long", (elapsed < 3.0f)); - } - - template<> template<> - void fitness_test_object::test<2>() - { - LL_DEBUGS() << "fitness_test_object::test<2>()" << LL_ENDL; - - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory<LLIOFuzz> emitter_t; - emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); - std::shared_ptr<LLChainIOFactory> factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f); - ensure("Did not take too long", (elapsed < 3.0f)); - } - - template<> template<> - void fitness_test_object::test<3>() - { - LL_DEBUGS() << "fitness_test_object::test<3>()" << LL_ENDL; - - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory<LLIOFuzz> emitter_t; - emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); - std::shared_ptr<LLChainIOFactory> factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f); - ensure("Did not take too long", (elapsed < 4.0f)); - } - - template<> template<> - void fitness_test_object::test<4>() - { - LL_DEBUGS() << "fitness_test_object::test<4>()" << LL_ENDL; - - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory<LLIOFuzz> emitter_t; - emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); - std::shared_ptr<LLChainIOFactory> factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 1.80f); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f); - ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS)); - } - - template<> template<> - void fitness_test_object::test<5>() - { - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory<LLIOSleeper> sleeper_t; - sleeper_t* sleeper = new sleeper_t(new LLIOSleeper); - std::shared_ptr<LLChainIOFactory> factory(sleeper); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(1.0); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - U32 count = mPump->runningChains(); - ensure_equals("server chain onboard", count, 1); - LL_DEBUGS() << "** Server is up." << LL_ENDL; - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - pump_loop(mPump,0.1f); - count = mPump->runningChains(); - ensure_equals("server chain onboard", count, 2); - LL_DEBUGS() << "** Client is connected." << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, 0.2f); - chain.clear(); - - // pump for a bit and make sure all 3 chains are running - pump_loop(mPump,0.1f); - count = mPump->runningChains(); - // ensure_equals("client chain onboard", count, 3); commented out because it fails frequently - appears to be timing sensitive - LL_DEBUGS() << "** request should have been sent." << LL_ENDL; - - // pump for long enough the the client socket closes, and the - // server socket should not be closed yet. - pump_loop(mPump,0.2f); - count = mPump->runningChains(); - ensure_equals("client chain timed out ", count, 2); - LL_DEBUGS() << "** client chain should be closed." << LL_ENDL; - - // At this point, the socket should be closed by the timeout - pump_loop(mPump,1.0f); - count = mPump->runningChains(); - ensure_equals("accepted socked close", count, 1); - LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL; - } + /** + * @brief we want to test the pipes & pumps under bad conditions. + */ + struct pipe_and_pump_fitness + { + public: + enum + { + SERVER_LISTEN_PORT = 13050 + }; + + pipe_and_pump_fitness() + { + LLFrameTimer::updateFrameTime(); + apr_pool_create(&mPool, NULL); + mPump = new LLPumpIO(mPool); + mSocket = LLSocket::create( + mPool, + LLSocket::STREAM_TCP, + SERVER_LISTEN_PORT, + "127.0.0.1"); + } + + ~pipe_and_pump_fitness() + { + mSocket.reset(); + delete mPump; + apr_pool_destroy(mPool); + } + + protected: + apr_pool_t* mPool; + LLPumpIO* mPump; + LLSocket::ptr_t mSocket; + }; + typedef test_group<pipe_and_pump_fitness> fitness_test_group; + typedef fitness_test_group::object fitness_test_object; + fitness_test_group fitness("pipe and pump fitness"); + + template<> template<> + void fitness_test_object::test<1>() + { + LL_DEBUGS() << "fitness_test_object::test<1>()" << LL_ENDL; + + // Set up the server + //LL_DEBUGS() << "fitness_test_object::test<1> - setting up server." + // << LL_ENDL; + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLPipeStringInjector> emitter_t; + emitter_t* emitter = new emitter_t( + new LLPipeStringInjector("suckers never play me")); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + //LL_DEBUGS() << "fitness_test_object::test<1> - initializing server." + // << LL_ENDL; + pump_loop(mPump, 0.1f); + + // Set up the client + //LL_DEBUGS() << "fitness_test_object::test<1> - connecting client." + // << LL_ENDL; + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, 1.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, 2.0f); + ensure("Did not take too long", (elapsed < 3.0f)); + } + + template<> template<> + void fitness_test_object::test<2>() + { + LL_DEBUGS() << "fitness_test_object::test<2>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOFuzz> emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f); + ensure("Did not take too long", (elapsed < 3.0f)); + } + + template<> template<> + void fitness_test_object::test<3>() + { + LL_DEBUGS() << "fitness_test_object::test<3>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOFuzz> emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f); + ensure("Did not take too long", (elapsed < 4.0f)); + } + + template<> template<> + void fitness_test_object::test<4>() + { + LL_DEBUGS() << "fitness_test_object::test<4>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOFuzz> emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr<LLChainIOFactory> factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 1.80f); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f); + ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS)); + } + + template<> template<> + void fitness_test_object::test<5>() + { + skip("Test is strongly timing dependent, " + "and on slow CI machines it fails way too often."); + const int retries = 100; + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory<LLIOSleeper> sleeper_t; + sleeper_t* sleeper = new sleeper_t(new LLIOSleeper); + std::shared_ptr<LLChainIOFactory> factory(sleeper); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(1.0); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + // We need to tickle the pump a little to set up the listen() + for (int retry = 0; mPump->runningChains() < 1 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + U32 count = mPump->runningChains(); + ensure_equals("server chain 1 onboard", count, 1); + LL_DEBUGS() << "** Server is up." << LL_ENDL; + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + for (int retry = 0; mPump->runningChains() < 2 && retry < retries; ++retry) + { + pump_loop(mPump,0.1f); + } + count = mPump->runningChains(); + ensure_equals("server chain 2 onboard", count, 2); + LL_DEBUGS() << "** Client is connected." << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, 0.2f); + chain.clear(); + + // pump for a bit and make sure all 3 chains are running + for (int retry = 0; mPump->runningChains() < 3 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + count = mPump->runningChains(); + ensure_equals("client chain onboard", count, 3); + LL_DEBUGS() << "** request should have been sent." << LL_ENDL; + + // pump for long enough the the client socket closes, and the + // server socket should not be closed yet. + for (int retry = 0; mPump->runningChains() == 3 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + // We used to test for count == 2 here, but on a slow test machine it + // can happen that not just one but two chains close before we reach + // this point. + count = mPump->runningChains(); + ensure(stringize("client chain timed out: count ", count), count < 3); + LL_DEBUGS() << "** client chain should be closed." << LL_ENDL; + + // At this point, the socket should be closed by the timeout + for (int retry = 0; mPump->runningChains() > 1 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + count = mPump->runningChains(); + ensure_equals("accepted socked close", count, 1); + LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL; + } } /* diff --git a/indra/test/lltut.h b/indra/test/lltut.h index e56b4e8d1c..4ce450057c 100644 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -1,4 +1,4 @@ -/** +/** * @file lltut.h * @author Phoenix * @date 2005-09-26 @@ -7,21 +7,21 @@ * $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$ */ @@ -31,6 +31,8 @@ #include "is_approx_equal_fraction.h" // instead of llmath.h #include <cstring> +#include <string> +#include <vector> class LLDate; class LLSD; @@ -38,35 +40,35 @@ class LLURI; namespace tut { - void ensure_equals(const std::string& msg, - const LLDate& actual, const LLDate& expected); + void ensure_equals(const std::string& msg, + const LLDate& actual, const LLDate& expected); - void ensure_equals(const std::string& msg, - const LLURI& actual, const LLURI& expected); + void ensure_equals(const std::string& msg, + const LLURI& actual, const LLURI& expected); - // std::vector<U8> is the current definition of LLSD::Binary. Because - // we're only forward-declaring LLSD in this header file, we can't - // directly reference that nested type. If the build complains that - // there's no definition for this declaration, it could be that - // LLSD::Binary has changed, and that this declaration must be adjusted to - // match. - void ensure_equals(const std::string& msg, - const std::vector<U8>& actual, const std::vector<U8>& expected); + // std::vector<U8> is the current definition of LLSD::Binary. Because + // we're only forward-declaring LLSD in this header file, we can't + // directly reference that nested type. If the build complains that + // there's no definition for this declaration, it could be that + // LLSD::Binary has changed, and that this declaration must be adjusted to + // match. + void ensure_equals(const std::string& msg, + const std::vector<U8>& actual, const std::vector<U8>& expected); - void ensure_equals(const std::string& msg, - const LLSD& actual, const LLSD& expected); + void ensure_equals(const std::string& msg, + const LLSD& actual, const LLSD& expected); - void ensure_starts_with(const std::string& msg, - const std::string& actual, const std::string& expectedStart); + void ensure_starts_with(const std::string& msg, + const std::string& actual, const std::string& expectedStart); - void ensure_ends_with(const std::string& msg, - const std::string& actual, const std::string& expectedEnd); + void ensure_ends_with(const std::string& msg, + const std::string& actual, const std::string& expectedEnd); - void ensure_contains(const std::string& msg, - const std::string& actual, const std::string& expectedSubString); + void ensure_contains(const std::string& msg, + const std::string& actual, const std::string& expectedSubString); - void ensure_does_not_contain(const std::string& msg, - const std::string& actual, const std::string& expectedSubString); + void ensure_does_not_contain(const std::string& msg, + const std::string& actual, const std::string& expectedSubString); } // This is an odd place to #include an important contributor -- but the usual @@ -87,73 +89,73 @@ namespace tut // The functions BELOW this point actually consume tut.hpp functionality. namespace tut { - inline void ensure_approximately_equals(const char* msg, F64 actual, F64 expected, U32 frac_bits) - { - if(!is_approx_equal_fraction(actual, expected, frac_bits)) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_approximately_equals(const char* msg, F32 actual, F32 expected, U32 frac_bits) - { - if(!is_approx_equal_fraction(actual, expected, frac_bits)) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_approximately_equals(F32 actual, F32 expected, U32 frac_bits) - { - ensure_approximately_equals(NULL, actual, expected, frac_bits); - } - - inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta) - { - if (fabs(actual-expected)>delta) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len) - { - if((expected_len != actual_len) || - (std::memcmp(actual, expected, actual_len) != 0)) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal"; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_memory_matches(const void* actual, U32 actual_len, const void* expected,U32 expected_len) - { - ensure_memory_matches(NULL, actual, actual_len, expected, expected_len); - } - - template <class T,class Q> - void ensure_not_equals(const char* msg,const Q& actual,const T& expected) - { - if( expected == actual ) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "both equal " << expected; - throw tut::failure(ss.str().c_str()); - } - } - - template <class T,class Q> - void ensure_not_equals(const Q& actual,const T& expected) - { - ensure_not_equals(NULL, actual, expected); - } + inline void ensure_approximately_equals(const char* msg, F64 actual, F64 expected, U32 frac_bits) + { + if(!is_approx_equal_fraction(actual, expected, frac_bits)) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_approximately_equals(const char* msg, F32 actual, F32 expected, U32 frac_bits) + { + if(!is_approx_equal_fraction(actual, expected, frac_bits)) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_approximately_equals(F32 actual, F32 expected, U32 frac_bits) + { + ensure_approximately_equals(NULL, actual, expected, frac_bits); + } + + inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta) + { + if (fabs(actual-expected)>delta) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len) + { + if((expected_len != actual_len) || + (std::memcmp(actual, expected, actual_len) != 0)) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal"; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_memory_matches(const void* actual, U32 actual_len, const void* expected,U32 expected_len) + { + ensure_memory_matches(NULL, actual, actual_len, expected, expected_len); + } + + template <class T,class Q> + void ensure_not_equals(const char* msg,const Q& actual,const T& expected) + { + if( expected == actual ) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "both equal " << expected; + throw tut::failure(ss.str().c_str()); + } + } + + template <class T,class Q> + void ensure_not_equals(const Q& actual,const T& expected) + { + ensure_not_equals(NULL, actual, expected); + } } #endif // LL_LLTUT_H diff --git a/indra/test/print.h b/indra/test/print.h index 7577698cc8..749603907e 100644 --- a/indra/test/print.h +++ b/indra/test/print.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2020-01-02 * @brief print() function for debugging - * + * * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Copyright (c) 2020, Linden Research, Inc. * $/LicenseInfo$ @@ -23,7 +23,9 @@ struct NONL_t {}; inline void print() { +#ifdef LL_TEST std::cerr << std::endl; +#endif } // print(NONL) is a no-op @@ -35,8 +37,10 @@ void print(NONL_t) template <typename T, typename... ARGS> void print(T&& first, ARGS&&... rest) { +#ifdef LL_TEST std::cerr << first; print(std::forward<ARGS>(rest)...); +#endif } #endif /* ! defined(LL_PRINT_H) */ |