From 01dd9929e21228e4e6e04d9e3f7c310ffdc834db Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 28 Jan 2011 16:00:57 -0800 Subject: STORM-937 : Makes all python paths use consistent syntax --- indra/newview/generate_breakpad_symbols.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py index 4fd04d780e..018871d9d3 100644 --- a/indra/newview/generate_breakpad_symbols.py +++ b/indra/newview/generate_breakpad_symbols.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # @file generate_breakpad_symbols.py # @author Brad Kittenbrink # @brief Simple tool for generating google_breakpad symbol information -- cgit v1.3 From 2bafe0dc8a2eb1d99516a4af96acc93c3541a1cd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 28 Jan 2011 20:18:10 -0500 Subject: Extend LLEventAPI to directly call other functions & methods. Until now, LLEventAPI has only been able to register functions specifically accepting(const LLSD&). Typically you add a wrapper method to your LLEventAPI subclass, register that, have it extract desired params from the incoming LLSD and then call the actual function of interest. With help from Alain, added new LLEventAPI::add() methods capable of registering functions/methods with arbitrary parameter signatures. The code uses boost::fusion magic to implicitly match incoming LLSD arguments to the function's formal parameter list, bypassing the need for an explicit helper method. New add() methods caused an ambiguity with a previous convenience overload. Removed that overload and fixed the one existing usage. Replaced LLEventDispatcher::get() with try_call() -- it's no longer easy to return a Callable for caller to call directly. But the one known use of that feature simply used it to avoid fatal LL_ERRS on unknown function-name string, hence the try_call() approach actually addresses that case more directly. Added indra/common/lleventdispatcher_test.cpp to exercise new functionality. --- indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/lleventdispatcher.cpp | 535 ++++++++++++++++++++++-- indra/llcommon/lleventdispatcher.h | 374 +++++++++++++++-- indra/llcommon/tests/lleventdispatcher_test.cpp | 436 +++++++++++++++++++ indra/newview/lllogininstance.cpp | 16 +- 5 files changed, 1296 insertions(+), 66 deletions(-) create mode 100644 indra/llcommon/tests/lleventdispatcher_test.cpp (limited to 'indra/newview') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 9342a22d46..dc9f93df3b 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -313,6 +313,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}") LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}") # *TODO - reenable these once tcmalloc libs no longer break the build. #ADD_BUILD_TEST(llallocator llcommon) diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp index d6e820d793..2ab006a173 100644 --- a/indra/llcommon/lleventdispatcher.cpp +++ b/indra/llcommon/lleventdispatcher.cpp @@ -41,6 +41,326 @@ #include "llevents.h" #include "llerror.h" #include "llsdutil.h" +#include "stringize.h" +#include // std::auto_ptr + +/***************************************************************************** +* LLSDArgsSource +*****************************************************************************/ +/** + * Store an LLSD array, producing its elements one at a time. Die with LL_ERRS + * if the consumer requests more elements than the array contains. + */ +class LL_COMMON_API LLSDArgsSource +{ +public: + LLSDArgsSource(const std::string function, const LLSD& args); + ~LLSDArgsSource(); + + LLSD next(); + + void done() const; + +private: + std::string _function; + LLSD _args; + LLSD::Integer _index; +}; + +LLSDArgsSource::LLSDArgsSource(const std::string function, const LLSD& args): + _function(function), + _args(args), + _index(0) +{ + if (! (_args.isUndefined() || _args.isArray())) + { + LL_ERRS("LLSDArgsSource") << _function << " needs an args array instead of " + << _args << LL_ENDL; + } +} + +LLSDArgsSource::~LLSDArgsSource() +{ + done(); +} + +LLSD LLSDArgsSource::next() +{ + if (_index >= _args.size()) + { + LL_ERRS("LLSDArgsSource") << _function << " requires more arguments than the " + << _args.size() << " provided: " << _args << LL_ENDL; + } + return _args[_index++]; +} + +void LLSDArgsSource::done() const +{ + if (_index < _args.size()) + { + LL_WARNS("LLSDArgsSource") << _function << " only consumed " << _index + << " of the " << _args.size() << " arguments provided: " + << _args << LL_ENDL; + } +} + +/***************************************************************************** +* LLSDArgsMapper +*****************************************************************************/ +/** + * From a formal parameters description and a map of arguments, construct an + * arguments array. + * + * That is, given: + * - an LLSD array of length n containing parameter-name strings, + * corresponding to the arguments of a function of interest + * - an LLSD collection specifying default parameter values, either: + * - an LLSD array of length m <= n, matching the rightmost m params, or + * - an LLSD map explicitly stating default name=value pairs + * - an LLSD map of parameter names and actual values for a particular + * function call + * construct an LLSD array of actual argument values for this function call. + * + * The parameter-names array and the defaults collection describe the function + * being called. The map might vary with every call, providing argument values + * for the described parameters. + * + * The array of parameter names must match the number of parameters expected + * by the function of interest. + * + * If you pass a map of default parameter values, it provides default values + * as you might expect. It is an error to specify a default value for a name + * not listed in the parameters array. + * + * If you pass an array of default parameter values, it is mapped to the + * rightmost m of the n parameter names. It is an error if the default-values + * array is longer than the parameter-names array. Consider the following + * parameter names: ["a", "b", "c", "d"]. + * + * - An empty array of default values (or an isUndefined() value) asserts that + * every one of the above parameter names is required. + * - An array of four default values [1, 2, 3, 4] asserts that every one of + * the above parameters is optional. If the current parameter map is empty, + * they will be passed to the function as [1, 2, 3, 4]. + * - An array of two default values [11, 12] asserts that parameters "a" and + * "b" are required, while "c" and "d" are optional, having default values + * "c"=11 and "d"=12. + * + * The arguments array is constructed as follows: + * + * - Arguments-map keys not found in the parameter-names array are ignored. + * - Entries from the map provide values for an improper subset of the + * parameters named in the parameter-names array. This results in a + * tentative values array with "holes." (size of map) + (number of holes) = + * (size of names array) + * - Holes are filled with the default values. + * - Any remaining holes constitute an error. + */ +class LL_COMMON_API LLSDArgsMapper +{ +public: + /// Accept description of function: function name, param names, param + /// default values + LLSDArgsMapper(const std::string& function, const LLSD& names, const LLSD& defaults); + + /// Given arguments map, return LLSD::Array of parameter values, or LL_ERRS. + LLSD map(const LLSD& argsmap) const; + +private: + static std::string formatlist(const LLSD&); + + // The function-name string is purely descriptive. We want error messages + // to be able to indicate which function's LLSDArgsMapper has the problem. + std::string _function; + // Store the names array pretty much as given. + LLSD _names; + // Though we're handed an array of name strings, it's more useful to us to + // store it as a map from name string to position index. Of course that's + // easy to generate from the incoming names array, but why do it more than + // once? + typedef std::map IndexMap; + IndexMap _indexes; + // Generated array of default values, aligned with the array of param names. + LLSD _defaults; + // Indicate whether we have a default value for each param. + typedef std::vector FilledVector; + FilledVector _has_dft; +}; + +LLSDArgsMapper::LLSDArgsMapper(const std::string& function, + const LLSD& names, const LLSD& defaults): + _function(function), + _names(names), + _has_dft(names.size()) +{ + if (! (_names.isUndefined() || _names.isArray())) + { + LL_ERRS("LLSDArgsMapper") << function << " names must be an array, not " << names << LL_ENDL; + } + LLSD::Integer nparams(_names.size()); + // From _names generate _indexes. + for (LLSD::Integer ni = 0, nend = _names.size(); ni < nend; ++ni) + { + _indexes[_names[ni]] = ni; + } + + // Presize _defaults() array so we don't have to resize it more than once. + // All entries are initialized to LLSD(); but since _has_dft is still all + // 0, they're all "holes" for now. + if (nparams) + { + _defaults[nparams - 1] = LLSD(); + } + + if (defaults.isUndefined() || defaults.isArray()) + { + LLSD::Integer ndefaults = defaults.size(); + // defaults is a (possibly empty) array. Right-align it with names. + if (ndefaults > nparams) + { + LL_ERRS("LLSDArgsMapper") << function << " names array " << names + << " shorter than defaults array " << defaults << LL_ENDL; + } + + // Offset by which we slide defaults array right to right-align with + // _names array + LLSD::Integer offset = nparams - ndefaults; + // Fill rightmost _defaults entries from defaults, and mark them as + // filled + for (LLSD::Integer i = 0, iend = ndefaults; i < iend; ++i) + { + _defaults[i + offset] = defaults[i]; + _has_dft[i + offset] = 1; + } + } + else if (defaults.isMap()) + { + // defaults is a map. Use it to populate the _defaults array. + LLSD bogus; + for (LLSD::map_const_iterator mi(defaults.beginMap()), mend(defaults.endMap()); + mi != mend; ++mi) + { + IndexMap::const_iterator ixit(_indexes.find(mi->first)); + if (ixit == _indexes.end()) + { + bogus.append(mi->first); + continue; + } + + LLSD::Integer pos = ixit->second; + // Store default value at that position in the _defaults array. + _defaults[pos] = mi->second; + // Don't forget to record the fact that we've filled this + // position. + _has_dft[pos] = 1; + } + if (bogus.size()) + { + LL_ERRS("LLSDArgsMapper") << function << " defaults specified for nonexistent params " + << formatlist(bogus) << LL_ENDL; + } + } + else + { + LL_ERRS("LLSDArgsMapper") << function << " defaults must be a map or an array, not " + << defaults << LL_ENDL; + } +} + +LLSD LLSDArgsMapper::map(const LLSD& argsmap) const +{ + if (! (argsmap.isUndefined() || argsmap.isMap())) + { + LL_ERRS("LLSDArgsMapper") << _function << " map() needs a map, not " << argsmap << LL_ENDL; + } + // Initialize the args array. Indexing a non-const LLSD array grows it + // to appropriate size, but we don't want to resize this one on each + // new operation. Just make it as big as we need before we start + // stuffing values into it. + LLSD args(LLSD::emptyArray()); + if (_defaults.size() == 0) + { + // If this function requires no arguments, fast exit. (Don't try to + // assign to args[-1].) + return args; + } + args[_defaults.size() - 1] = LLSD(); + + // Get a vector of chars to indicate holes. It's tempting to just scan + // for LLSD::isUndefined() values after filling the args array from + // the map, but it's plausible for caller to explicitly pass + // isUndefined() as the value of some parameter name. That's legal + // since isUndefined() has well-defined conversions (default value) + // for LLSD data types. So use a whole separate array for detecting + // holes. (Avoid std::vector which is known to be odd -- can we + // iterate?) + FilledVector filled(args.size()); + // Walk the map. + for (LLSD::map_const_iterator mi(argsmap.beginMap()), mend(argsmap.endMap()); + mi != mend; ++mi) + { + // mi->first is a parameter-name string, with mi->second its + // value. Look up the name's position index in _indexes. + IndexMap::const_iterator ixit(_indexes.find(mi->first)); + if (ixit == _indexes.end()) + { + // Allow for a map containing more params than were passed in + // our names array. Caller typically receives a map containing + // the function name, cruft such as reqid, etc. Ignore keys + // not defined in _indexes. + LL_DEBUGS("LLSDArgsMapper") << _function << " ignoring " + << mi->first << "=" << mi->second << LL_ENDL; + continue; + } + LLSD::Integer pos = ixit->second; + // Store the value at that position in the args array. + args[pos] = mi->second; + // Don't forget to record the fact that we've filled this + // position. + filled[pos] = 1; + } + // Fill any remaining holes from _defaults. + LLSD unfilled(LLSD::emptyArray()); + for (LLSD::Integer i = 0, iend = args.size(); i < iend; ++i) + { + if (! filled[i]) + { + // If there's no default value for this parameter, that's an + // error. + if (! _has_dft[i]) + { + unfilled.append(_names[i]); + } + else + { + args[i] = _defaults[i]; + } + } + } + // If any required args -- args without defaults -- were left unfilled + // by argsmap, that's a problem. + if (unfilled.size()) + { + LL_ERRS("LLSDArgsMapper") << _function << " missing required arguments " + << formatlist(unfilled) << " from " << argsmap << LL_ENDL; + } + + // done + return args; +} + +std::string LLSDArgsMapper::formatlist(const LLSD& list) +{ + std::ostringstream out; + const char* delim = ""; + for (LLSD::array_const_iterator li(list.beginArray()), lend(list.endArray()); + li != lend; ++li) + { + out << delim << li->asString(); + delim = ", "; + } + return out.str(); +} LLEventDispatcher::LLEventDispatcher(const std::string& desc, const std::string& key): mDesc(desc), @@ -52,12 +372,178 @@ LLEventDispatcher::~LLEventDispatcher() { } +/** + * DispatchEntry subclass used for callables accepting(const LLSD&) + */ +struct LLEventDispatcher::LLSDDispatchEntry: public LLEventDispatcher::DispatchEntry +{ + LLSDDispatchEntry(const std::string& desc, const Callable& func, const LLSD& required): + DispatchEntry(desc), + mFunc(func), + mRequired(required) + {} + + Callable mFunc; + LLSD mRequired; + + virtual void call(const std::string& desc, const LLSD& event) const + { + // Validate the syntax of the event itself. + std::string mismatch(llsd_matches(mRequired, event)); + if (! mismatch.empty()) + { + LL_ERRS("LLEventDispatcher") << desc << ": bad request: " << mismatch << LL_ENDL; + } + // Event syntax looks good, go for it! + mFunc(event); + } + + virtual LLSD addMetadata(LLSD meta) const + { + meta["required"] = mRequired; + return meta; + } +}; + +/** + * DispatchEntry subclass for passing LLSD to functions accepting + * arbitrary argument types (convertible via LLSDParam) + */ +struct LLEventDispatcher::ParamsDispatchEntry: public LLEventDispatcher::DispatchEntry +{ + ParamsDispatchEntry(const std::string& desc, const invoker_function& func): + DispatchEntry(desc), + mInvoker(func) + {} + + invoker_function mInvoker; + + virtual void call(const std::string& desc, const LLSD& event) const + { + LLSDArgsSource src(desc, event); + mInvoker(boost::bind(&LLSDArgsSource::next, boost::ref(src))); + } +}; + +/** + * DispatchEntry subclass for dispatching LLSD::Array to functions accepting + * arbitrary argument types (convertible via LLSDParam) + */ +struct LLEventDispatcher::ArrayParamsDispatchEntry: public LLEventDispatcher::ParamsDispatchEntry +{ + ArrayParamsDispatchEntry(const std::string& desc, const invoker_function& func, + LLSD::Integer arity): + ParamsDispatchEntry(desc, func), + mArity(arity) + {} + + LLSD::Integer mArity; + + virtual LLSD addMetadata(LLSD meta) const + { + LLSD array(LLSD::emptyArray()); + // Resize to number of arguments required + array[mArity - 1] = LLSD(); + llassert_always(array.size() == mArity); + meta["required"] = array; + return meta; + } +}; + +/** + * DispatchEntry subclass for dispatching LLSD::Map to functions accepting + * arbitrary argument types (convertible via LLSDParam) + */ +struct LLEventDispatcher::MapParamsDispatchEntry: public LLEventDispatcher::ParamsDispatchEntry +{ + MapParamsDispatchEntry(const std::string& name, const std::string& desc, + const invoker_function& func, + const LLSD& params, const LLSD& defaults): + ParamsDispatchEntry(desc, func), + mMapper(name, params, defaults), + mRequired(LLSD::emptyMap()) + { + // Build the set of all param keys, then delete the ones that are + // optional. What's left are the ones that are required. + for (LLSD::array_const_iterator pi(params.beginArray()), pend(params.endArray()); + pi != pend; ++pi) + { + mRequired[pi->asString()] = LLSD(); + } + + if (defaults.isArray() || defaults.isUndefined()) + { + // Right-align the params and defaults arrays. + LLSD::Integer offset = params.size() - defaults.size(); + // Now the name of every defaults[i] is at params[i + offset]. + for (LLSD::Integer i(0), iend(defaults.size()); i < iend; ++i) + { + // Erase this optional param from mRequired. + mRequired.erase(params[i + offset].asString()); + // Instead, make an entry in mOptional with the default + // param's name and value. + mOptional[params[i + offset].asString()] = defaults[i]; + } + } + else if (defaults.isMap()) + { + // if defaults is already a map, then it's already in the form we + // intend to deliver in metadata + mOptional = defaults; + // Just delete from mRequired every key appearing in mOptional. + for (LLSD::map_const_iterator mi(mOptional.beginMap()), mend(mOptional.endMap()); + mi != mend; ++mi) + { + mRequired.erase(mi->first); + } + } + } + + LLSDArgsMapper mMapper; + LLSD mRequired; + LLSD mOptional; + + virtual void call(const std::string& desc, const LLSD& event) const + { + // Just convert from LLSD::Map to LLSD::Array using mMapper, then pass + // to base-class call() method. + ParamsDispatchEntry::call(desc, mMapper.map(event)); + } + + virtual LLSD addMetadata(LLSD meta) const + { + meta["required"] = mRequired; + meta["optional"] = mOptional; + return meta; + } +}; + +void LLEventDispatcher::addArrayParamsDispatchEntry(const std::string& name, + const std::string& desc, + const invoker_function& invoker, + LLSD::Integer arity) +{ + // Peculiar to me that boost::ptr_map() accepts std::auto_ptr but not dumb ptr + mDispatch.insert(name, std::auto_ptr( + new ArrayParamsDispatchEntry(desc, invoker, arity))); +} + +void LLEventDispatcher::addMapParamsDispatchEntry(const std::string& name, + const std::string& desc, + const invoker_function& invoker, + const LLSD& params, + const LLSD& defaults) +{ + mDispatch.insert(name, std::auto_ptr( + new MapParamsDispatchEntry(name, desc, invoker, params, defaults))); +} + /// Register a callable by name void LLEventDispatcher::add(const std::string& name, const std::string& desc, const Callable& callable, const LLSD& required) { - mDispatch.insert(DispatchMap::value_type(name, - DispatchMap::mapped_type(callable, desc, required))); + mDispatch.insert(name, std::auto_ptr( + new LLSDDispatchEntry(desc, callable, required))); } void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const @@ -83,7 +569,7 @@ bool LLEventDispatcher::remove(const std::string& name) /// such callable exists, die with LL_ERRS. void LLEventDispatcher::operator()(const std::string& name, const LLSD& event) const { - if (! attemptCall(name, event)) + if (! try_call(name, event)) { LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): '" << name << "' not found" << LL_ENDL; @@ -98,44 +584,29 @@ void LLEventDispatcher::operator()(const LLSD& event) const // This could/should be implemented in terms of the two-arg overload. // However -- we can produce a more informative error message. std::string name(event[mKey]); - if (! attemptCall(name, event)) + if (! try_call(name, event)) { LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): bad " << mKey << " value '" << name << "'" << LL_ENDL; } } -bool LLEventDispatcher::attemptCall(const std::string& name, const LLSD& event) const +bool LLEventDispatcher::try_call(const LLSD& event) const { - DispatchMap::const_iterator found = mDispatch.find(name); - if (found == mDispatch.end()) - { - // The reason we only return false, leaving it up to our caller to die - // with LL_ERRS, is that different callers have different amounts of - // available information. - return false; - } - // Found the name, so it's plausible to even attempt the call. But first, - // validate the syntax of the event itself. - std::string mismatch(llsd_matches(found->second.mRequired, event)); - if (! mismatch.empty()) - { - LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ") calling '" << name - << "': bad request: " << mismatch << LL_ENDL; - } - // Event syntax looks good, go for it! - (found->second.mFunc)(event); - return true; // tell caller we were able to call + return try_call(event[mKey], event); } -LLEventDispatcher::Callable LLEventDispatcher::get(const std::string& name) const +bool LLEventDispatcher::try_call(const std::string& name, const LLSD& event) const { DispatchMap::const_iterator found = mDispatch.find(name); if (found == mDispatch.end()) { - return Callable(); + return false; } - return found->second.mFunc; + // Found the name, so it's plausible to even attempt the call. + found->second->call(STRINGIZE("LLEventDispatcher(" << mDesc << ") calling '" << name << "'"), + event); + return true; // tell caller we were able to call } LLSD LLEventDispatcher::getMetadata(const std::string& name) const @@ -147,9 +618,8 @@ LLSD LLEventDispatcher::getMetadata(const std::string& name) const } LLSD meta; meta["name"] = name; - meta["desc"] = found->second.mDesc; - meta["required"] = found->second.mRequired; - return meta; + meta["desc"] = found->second->mDesc; + return found->second->addMetadata(meta); } LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key): @@ -164,3 +634,8 @@ bool LLDispatchListener::process(const LLSD& event) (*this)(event); return false; } + +LLEventDispatcher::DispatchEntry::DispatchEntry(const std::string& desc): + mDesc(desc) +{} + diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index dfffd59eb6..ce0fc7b585 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -27,18 +27,56 @@ * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ + * + * The invoker machinery that constructs a boost::fusion argument list for use + * with boost::fusion::invoke() is derived from + * http://www.boost.org/doc/libs/1_45_0/libs/function_types/example/interpreter.hpp + * whose license information is copied below: + * + * "(C) Copyright Tobias Schwinger + * + * Use modification and distribution are subject to the boost Software License, + * Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)." */ #if ! defined(LL_LLEVENTDISPATCHER_H) #define LL_LLEVENTDISPATCHER_H +// nil is too generic a term to be allowed to be a global macro. In +// particular, boost::fusion defines a 'class nil' (properly encapsulated in a +// namespace) that a global 'nil' macro breaks badly. +#if defined(nil) +// Capture the value of the macro 'nil', hoping int is an appropriate type. +static const int nil_(nil); +// Now forget the macro. +#undef nil +// Finally, reintroduce 'nil' as a properly-scoped alias for the previously- +// defined const 'nil_'. Make it static since otherwise it produces duplicate- +// symbol link errors later. +static const int& nil(nil_); +#endif + #include -#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "llevents.h" +#include "llsdutil.h" class LLSD; @@ -54,12 +92,18 @@ public: LLEventDispatcher(const std::string& desc, const std::string& key); virtual ~LLEventDispatcher(); - /// Accept any C++ callable, typically a boost::bind() expression + /// @name Register functions accepting(const LLSD&) + //@{ + + /// Accept any C++ callable with the right signature, typically a + /// boost::bind() expression typedef boost::function Callable; /** - * Register a @a callable by @a name. The optional @a required parameter - * is used to validate the structure of each incoming event (see + * Register a @a callable by @a name. The passed @a callable accepts a + * single LLSD value and uses it in any way desired, e.g. extract + * parameters and call some other function. The optional @a required + * parameter is used to validate the structure of each incoming event (see * llsd_matches()). */ void add(const std::string& name, @@ -69,8 +113,9 @@ public: /** * Special case: a subclass of this class can pass an unbound member - * function pointer without explicitly specifying the - * boost::bind() expression. + * function pointer (of an LLEventDispatcher subclass) without explicitly + * specifying the boost::bind() expression. The passed @a method + * accepts a single LLSD value, presumably containing other parameters. */ template void add(const std::string& name, @@ -81,7 +126,8 @@ public: addMethod(name, desc, method, required); } - /// Overload for both const and non-const methods + /// Overload for both const and non-const methods. The passed @a method + /// accepts a single LLSD value, presumably containing other parameters. template void add(const std::string& name, const std::string& desc, @@ -91,8 +137,10 @@ public: addMethod(name, desc, method, required); } +/*==========================================================================*| /// Convenience: for LLEventDispatcher, not every callable needs a - /// documentation string. + /// documentation string. The passed @a callable accepts a single LLSD + /// value, presumably containing other parameters. template void add(const std::string& name, CALLABLE callable, @@ -100,6 +148,92 @@ public: { add(name, "", callable, required); } +|*==========================================================================*/ + + //@} + + /// @name Register functions with arbitrary param lists + //@{ + + /** + * Register a free function with arbitrary parameters. (This also works + * for static class methods.) + * + * When calling this name, pass an LLSD::Array. Each entry in turn will be + * converted to the corresponding parameter type using LLSDParam. + */ + template + typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin + >::type add(const std::string& name, + const std::string& desc, + Function f); + + /** + * Register a nonstatic class method with arbitrary parameters. + * + * To cover cases such as a method on an LLSingleton we don't yet want to + * instantiate, instead of directly storing an instance pointer, accept a + * nullary callable returning a pointer/reference to the desired class + * instance. If you already have an instance in hand, + * boost::lambda::var(instance) or boost::lambda::constant(instance_ptr) + * produce suitable callables. + * + * When calling this name, pass an LLSD::Array. Each entry in turn will be + * converted to the corresponding parameter type using LLSDParam. + */ + template + typename boost::enable_if< boost::function_types::is_member_function_pointer + >::type add(const std::string& name, + const std::string& desc, + Method f, + const InstanceGetter& getter); + + /** + * Register a free function with arbitrary parameters. (This also works + * for static class methods.) + * + * Pass an LLSD::Array of parameter names, and optionally another + * LLSD::Array of default parameter values, a la LLSDArgsMapper. + * + * When calling this name, pass an LLSD::Map. We will internally generate + * an LLSD::Array using LLSDArgsMapper and then convert each entry in turn + * to the corresponding parameter type using LLSDParam. + */ + template + typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin + >::type add(const std::string& name, + const std::string& desc, + Function f, + const LLSD& params, + const LLSD& defaults=LLSD()); + + /** + * Register a nonstatic class method with arbitrary parameters. + * + * To cover cases such as a method on an LLSingleton we don't yet want to + * instantiate, instead of directly storing an instance pointer, accept a + * nullary callable returning a pointer/reference to the desired class + * instance. If you already have an instance in hand, + * boost::lambda::var(instance) or boost::lambda::constant(instance_ptr) + * produce suitable callables. + * + * Pass an LLSD::Array of parameter names, and optionally another + * LLSD::Array of default parameter values, a la LLSDArgsMapper. + * + * When calling this name, pass an LLSD::Map. We will internally generate + * an LLSD::Array using LLSDArgsMapper and then convert each entry in turn + * to the corresponding parameter type using LLSDParam. + */ + template + typename boost::enable_if< boost::function_types::is_member_function_pointer + >::type add(const std::string& name, + const std::string& desc, + Method f, + const InstanceGetter& getter, + const LLSD& params, + const LLSD& defaults=LLSD()); + + //@} /// Unregister a callable bool remove(const std::string& name); @@ -109,12 +243,25 @@ public: /// the @a required prototype specified at add() time, die with LL_ERRS. void operator()(const std::string& name, const LLSD& event) const; + /// Call a registered callable with an explicitly-specified name and + /// return true. If no such callable exists, return + /// false. If the @a event fails to match the @a required + /// prototype specified at add() time, die with LL_ERRS. + bool try_call(const std::string& name, const LLSD& event) const; + /// Extract the @a key value from the incoming @a event, and call the /// callable whose name is specified by that map @a key. If no such /// callable exists, die with LL_ERRS. If the @a event fails to match the /// @a required prototype specified at add() time, die with LL_ERRS. void operator()(const LLSD& event) const; + /// Extract the @a key value from the incoming @a event, call the callable + /// whose name is specified by that map @a key and return true. + /// If no such callable exists, return false. If the @a event + /// fails to match the @a required prototype specified at add() time, die + /// with LL_ERRS. + bool try_call(const LLSD& event) const; + /// @name Iterate over defined names //@{ typedef std::pair NameDesc; @@ -122,37 +269,44 @@ public: private: struct DispatchEntry { - DispatchEntry(const Callable& func, const std::string& desc, const LLSD& required): - mFunc(func), - mDesc(desc), - mRequired(required) - {} - Callable mFunc; + DispatchEntry(const std::string& desc); + std::string mDesc; - LLSD mRequired; + + virtual void call(const std::string& desc, const LLSD& event) const = 0; + virtual LLSD addMetadata(LLSD) const = 0; }; - typedef std::map DispatchMap; + typedef boost::ptr_map DispatchMap; public: /// We want the flexibility to redefine what data we store per name, /// therefore our public interface doesn't expose DispatchMap iterators, /// or DispatchMap itself, or DispatchEntry. Instead we explicitly /// transform each DispatchMap item to NameDesc on dereferencing. - typedef boost::transform_iterator const_iterator; + typedef boost::transform_iterator const_iterator; const_iterator begin() const { - return boost::make_transform_iterator(mDispatch.begin(), makeNameDesc); + // Originally we used DispatchMap::const_iterator, which Just Worked + // when DispatchMap was a std::map. Now that it's a boost::ptr_map, + // using DispatchMap::const_iterator doesn't work so well: it + // dereferences to a pair, whereas + // DispatchMap::value_type is just pair. Trying to pass a + // dereferenced iterator to the value_type didn't work because the + // compiler won't let you convert from const T* to plain T*. Changing + // our const_iterator definition above to be based on non-const + // DispatchMap::iterator works better, but of course we have to cast + // away the constness of mDispatch to use non-const iterator. (Sigh.) + return boost::make_transform_iterator(const_cast(mDispatch).begin(), + makeNameDesc); } const_iterator end() const { - return boost::make_transform_iterator(mDispatch.end(), makeNameDesc); + // see begin() comments + return boost::make_transform_iterator(const_cast(mDispatch).end(), + makeNameDesc); } //@} - /// Fetch the Callable for the specified name. If no such name was - /// registered, return an empty() Callable. - Callable get(const std::string& name) const; - /// Get information about a specific Callable LLSD getMetadata(const std::string& name) const; @@ -175,18 +329,184 @@ private: } } void addFail(const std::string& name, const std::string& classname) const; - /// try to dispatch, return @c true if success - bool attemptCall(const std::string& name, const LLSD& event) const; std::string mDesc, mKey; DispatchMap mDispatch; - static NameDesc makeNameDesc(const DispatchMap::value_type& item) + static NameDesc makeNameDesc(DispatchMap::value_type item) { - return NameDesc(item.first, item.second.mDesc); + return NameDesc(item.first, item.second->mDesc); } + + struct LLSDDispatchEntry; + struct ParamsDispatchEntry; + struct ArrayParamsDispatchEntry; + struct MapParamsDispatchEntry; + + // Step 2 of parameter analysis. Instantiating invoker + // implicitly sets its From and To parameters to the (compile time) begin + // and end iterators over that function's parameter types. + template< typename Function + , class From = typename boost::mpl::begin< boost::function_types::parameter_types >::type + , class To = typename boost::mpl::end< boost::function_types::parameter_types >::type + > + struct invoker; + + // deliver LLSD arguments one at a time + typedef boost::function args_source; + // obtain args from an args_source to build param list and call target + // function + typedef boost::function invoker_function; + + template + invoker_function make_invoker(Function f); + template + invoker_function make_invoker(Method f, const InstanceGetter& getter); + void addArrayParamsDispatchEntry(const std::string& name, + const std::string& desc, + const invoker_function& invoker, + LLSD::Integer arity); + void addMapParamsDispatchEntry(const std::string& name, + const std::string& desc, + const invoker_function& invoker, + const LLSD& params, + const LLSD& defaults); }; +/***************************************************************************** +* LLEventDispatcher template implementation details +*****************************************************************************/ +// Step 3 of parameter analysis, the recursive case. +template +struct LLEventDispatcher::invoker +{ + template + struct remove_cv_ref + : boost::remove_cv< typename boost::remove_reference::type > + { }; + + // apply() accepts an arbitrary boost::fusion sequence as args. It + // examines the next parameter type in the parameter-types sequence + // bounded by From and To, obtains the next LLSD object from the passed + // args_source and constructs an LLSDParam of appropriate type to try + // to convert the value. It then recurs with the next parameter-types + // iterator, passing the args sequence thus far. + template + static inline + void apply(Function func, const args_source& argsrc, Args const & args) + { + typedef typename boost::mpl::deref::type arg_type; + typedef typename boost::mpl::next::type next_iter_type; + typedef typename remove_cv_ref::type plain_arg_type; + + invoker::apply + ( func, argsrc, boost::fusion::push_back(args, LLSDParam(argsrc()))); + } + + // Special treatment for instance (first) parameter of a non-static member + // function. Accept the instance-getter callable, calling that to produce + // the first args value. Since we know we're at the top of the recursion + // chain, we need not also require a partial args sequence from our caller. + template + static inline + void method_apply(Function func, const args_source& argsrc, const InstanceGetter& getter) + { + typedef typename boost::mpl::next::type next_iter_type; + + // Instead of grabbing the first item from argsrc and making an + // LLSDParam of it, call getter() and pass that as the instance param. + invoker::apply + ( func, argsrc, boost::fusion::push_back(boost::fusion::nil(), boost::ref(getter()))); + } +}; + +// Step 4 of parameter analysis, the leaf case. When the general +// invoker logic has advanced From until it matches To, +// the compiler will pick this template specialization. +template +struct LLEventDispatcher::invoker +{ + // the argument list is complete, now call the function + template + static inline + void apply(Function func, const args_source&, Args const & args) + { + boost::fusion::invoke(func, args); + } +}; + +template +typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin >::type +LLEventDispatcher::add(const std::string& name, const std::string& desc, Function f) +{ + // Construct an invoker_function, a callable accepting const args_source&. + // Add to DispatchMap an ArrayParamsDispatchEntry that will handle the + // caller's LLSD::Array. + addArrayParamsDispatchEntry(name, desc, make_invoker(f), + boost::function_types::function_arity::value); +} + +template +typename boost::enable_if< boost::function_types::is_member_function_pointer >::type +LLEventDispatcher::add(const std::string& name, const std::string& desc, Method f, + const InstanceGetter& getter) +{ + // Subtract 1 from the compile-time arity because the getter takes care of + // the first parameter. We only need (arity - 1) additional arguments. + addArrayParamsDispatchEntry(name, desc, make_invoker(f, getter), + boost::function_types::function_arity::value - 1); +} + +template +typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin >::type +LLEventDispatcher::add(const std::string& name, const std::string& desc, Function f, + const LLSD& params, const LLSD& defaults) +{ + // See comments for previous is_nonmember_callable_builtin add(). + addMapParamsDispatchEntry(name, desc, make_invoker(f), params, defaults); +} + +template +typename boost::enable_if< boost::function_types::is_member_function_pointer >::type +LLEventDispatcher::add(const std::string& name, const std::string& desc, Method f, + const InstanceGetter& getter, + const LLSD& params, const LLSD& defaults) +{ + addMapParamsDispatchEntry(name, desc, make_invoker(f, getter), params, defaults); +} + +template +LLEventDispatcher::invoker_function +LLEventDispatcher::make_invoker(Function f) +{ + // Step 1 of parameter analysis, the top of the recursion. Passing a + // suitable f (see add()'s enable_if condition) to this method causes it + // to infer the function type; specifying that function type to invoker<> + // causes it to fill in the begin/end MPL iterators over the function's + // list of parameter types. + // While normally invoker::apply() could infer its template type from the + // boost::fusion::nil parameter value, here we must be explicit since + // we're boost::bind()ing it rather than calling it directly. + return boost::bind(&invoker::template apply, + f, + _1, + boost::fusion::nil()); +} + +template +LLEventDispatcher::invoker_function +LLEventDispatcher::make_invoker(Method f, const InstanceGetter& getter) +{ + // Use invoker::method_apply() to treat the instance (first) arg specially. + return boost::bind(&invoker::template method_apply, + f, + _1, + getter); +} + +/***************************************************************************** +* LLDispatchListener +*****************************************************************************/ /** * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class * that contains (or derives from) LLDispatchListener need only specify the diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp new file mode 100644 index 0000000000..a1d7cf9ead --- /dev/null +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -0,0 +1,436 @@ +/** + * @file lleventdispatcher_test.cpp + * @author Nat Goodspeed + * @date 2011-01-20 + * @brief Test for lleventdispatcher. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Copyright (c) 2011, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lleventdispatcher.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "llsd.h" +#include "llsdutil.h" +#include "stringize.h" +#include "tests/wrapllerrs.h" + +// http://www.boost.org/doc/libs/1_45_0/libs/function_types/example/interpreter.hpp +// downloaded 2011-01-20 by NRG and adapted with example usage +// (C) Copyright Tobias Schwinger +// +// Use modification and distribution are subject to the boost Software License, +// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt). + +//------------------------------------------------------------------------------ +// +// This example implements a simple batch-style dispatcher that is capable of +// calling functions previously registered with it. The parameter types of the +// functions are used to control the parsing of the input. +// +// Implementation description +// ========================== +// +// When a function is registered, an 'invoker' template is instantiated with +// the function's type. The 'invoker' fetches a value from the 'arg_source' +// for each parameter of the function into a tuple and finally invokes the the +// function with these values as arguments. The invoker's entrypoint, which +// is a function of the callable builtin that describes the function to call and +// a reference to the 'arg_source', is partially bound to the registered +// function and put into a map so it can be found by name during parsing. + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +using boost::lambda::constant; +using boost::lambda::constant_ref; +using boost::lambda::var; + +/***************************************************************************** +* Output control +*****************************************************************************/ +#ifdef DEBUG_ON +using std::cout; +#else +static std::ostringstream cout; +#endif + +/***************************************************************************** +* Example data, functions, classes +*****************************************************************************/ +// sensing globals +static std::string gs; +static float gf; +static int gi; +static LLSD gl; + +void clear() +{ + gs.clear(); + gf = 0; + gi = 0; + gl = LLSD(); +} + +void abc(const std::string& message) +{ + cout << "abc('" << message << "')\n"; + gs = message; +} + +void def(float value, std::string desc) +{ + cout << "def(" << value << ", '" << desc << "')\n"; + gf = value; + gs = desc; +} + +void ghi(const std::string& foo, int bar) +{ + cout << "ghi('" << foo << "', " << bar << ")\n"; + gs = foo; + gi = bar; +} + +void jkl(const char* message) +{ + cout << "jkl('" << message << "')\n"; + gs = message; +} + +void somefunc(const LLSD& value) +{ + cout << "somefunc(" << value << ")\n"; + gl = value; +} + +class Dummy +{ +public: + Dummy(): _id("Dummy") {} + + void mno(const std::string& message) + { + cout << _id << "::mno('" << message << "')\n"; + s = message; + } + + void pqr(float value, std::string desc) + { + cout << _id << "::pqr(" << value << ", '" << desc << "')\n"; + f = value; + s = desc; + } + + void stu(const std::string& foo, int bar) + { + cout << _id << "::stu('" << foo << "', " << bar << ")\n"; + s = foo; + i = bar; + } + + void vwx(const char* message) + { + cout << _id << "::vwx('" << message << "')\n"; + s = message; + } + + static void yz1(const std::string& message) + { + cout << "Dummy::yz1('" << message << "')\n"; + // can't access sensing members... + gs = message; + } + + // sensing members + std::string s; + float f; + int i; + +private: + std::string _id; +}; + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct lleventdispatcher_data + { + WrapLL_ERRS redirect; + LLEventDispatcher work; + Dummy dummy; + + lleventdispatcher_data(): + work("test dispatcher", "op") + { + // This object is reconstructed for every test method. But + // clear global variables every time too. + ::clear(); + + work.add("abc", "abc", abc, LLSDArray("message")); + work.add("def", "def", def); + work.add("ghi", "ghi", ghi); + work.add("jkl", "jkl", jkl); + work.add("yz1", "yz1", &Dummy::yz1); + work.add("mno", "mno", &Dummy::mno, var(dummy), + LLSDArray("message"), LLSDArray("default message")); + work.add("mnoptr", "mno", &Dummy::mno, constant(&dummy)); + work.add("pqr", "pqr", &Dummy::pqr, var(dummy), + LLSDArray("value")("desc")); + work.add("stu", "stu", &Dummy::stu, var(dummy), + LLSDArray("foo")("bar"), LLSDArray(-1)); + work.add("vwx", "vwx", &Dummy::vwx, var(dummy), + LLSDArray("message")); + } + + void ensure_has(const std::string& outer, const std::string& inner) + { + ensure(STRINGIZE("'" << outer << "' does not contain '" << inner << "'").c_str(), + outer.find(inner) != std::string::npos); + } + + void call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag) + { + std::string threw; + try + { + work(func, args); + } + catch (const std::runtime_error& e) + { + cout << "*** " << e.what() << '\n'; + threw = e.what(); + } + ensure_has(threw, exc_frag); + } + }; + typedef test_group lleventdispatcher_group; + typedef lleventdispatcher_group::object object; + lleventdispatcher_group lleventdispatchergrp("lleventdispatcher"); + + template<> template<> + void object::test<1>() + { + LLSD hello("Hello test!"); +// cout << std::string(hello) << "\n"; + clear(); + jkl(LLSDParam(hello)); + ensure_equals(gs, hello.asString()); + } + + template<> template<> + void object::test<2>() + { + somefunc("abc"); + ensure_equals(gl.asString(), "abc"); + + somefunc(17); + ensure_equals(gl.asInteger(), 17); + + somefunc(3.14); + // 7 bits is 128, just enough to express two decimal places. + ensure_approximately_equals(gl.asReal(), 3.14, 7); + + somefunc(LLSD().with(0, "abc").with(1, 17).with(2, 3.14)); + ensure(gl.isArray()); + ensure_equals(gl.size(), 4); // !!! bug in LLSD::with(Integer, const LLSD&) !!! + ensure_equals(gl[1].asInteger(), 17); + + somefunc(LLSD().with("alpha", "abc").with("random", 17).with("pi", 3.14)); + ensure(gl.isMap()); + ensure_equals(gl.size(), 3); + ensure_equals(gl["random"].asInteger(), 17); + + somefunc(LLSDArray("abc")(17)(3.14)); + ensure(gl.isArray()); + ensure_equals(gl.size(), 3); + ensure_equals(gl[0].asString(), "abc"); + + somefunc(LLSDMap("alpha", "abc")("random", 17)("pi", 3.14)); + ensure(gl.isMap()); + ensure_equals(gl.size(), 3); + ensure_equals(gl["alpha"].asString(), "abc"); + } + + template<> template<> + void object::test<3>() + { + call_exc("gofish", LLSDArray(1), "not found"); + } + + template<> template<> + void object::test<4>() + { + call_exc("abc", LLSD(), "missing required"); + } + + template<> template<> + void object::test<5>() + { + work("abc", LLSDMap("message", "something")); + ensure_equals(gs, "something"); + } + + template<> template<> + void object::test<6>() + { + work("abc", LLSDMap("message", "something")("plus", "more")); + ensure_equals(gs, "something"); + } + + template<> template<> + void object::test<7>() + { + call_exc("def", LLSDMap("value", 20)("desc", "questions"), "needs an args array"); + } + + template<> template<> + void object::test<8>() + { + work("def", LLSDArray(20)("questions")); + ensure_equals(gf, 20); + ensure_equals(gs, "questions"); + } + + template<> template<> + void object::test<9>() + { + work("def", LLSDArray(3.14)("pies")); + ensure_approximately_equals(gf, 3.14, 7); + ensure_equals(gs, "pies"); + } + + template<> template<> + void object::test<10>() + { + work("ghi", LLSDArray("answer")(17)); + ensure_equals(gs, "answer"); + ensure_equals(gi, 17); + } + + template<> template<> + void object::test<11>() + { + work("ghi", LLSDArray("answer")(3.14)); + ensure_equals(gs, "answer"); + ensure_equals(gi, 3); + } + + template<> template<> + void object::test<12>() + { + work("jkl", LLSDArray("sample message")); + ensure_equals(gs, "sample message"); + } + + template<> template<> + void object::test<13>() + { + work("yz1", LLSDArray("w00t")); + ensure_equals(gs, "w00t"); + } + + template<> template<> + void object::test<14>() + { + std::string msg("nonstatic member function"); + work("mno", LLSDMap("message", msg)); + ensure_equals(dummy.s, msg); + } + + template<> template<> + void object::test<15>() + { + std::string msg("nonstatic member function reached by ptr"); + work("mnoptr", LLSDArray(msg)); + ensure_equals(dummy.s, msg); + } + + template<> template<> + void object::test<16>() + { + work("mno", LLSD()); + ensure_equals(dummy.s, "default message"); + } + + template<> template<> + void object::test<17>() + { + work("pqr", LLSDMap("value", 3.14)("desc", "pies")); + ensure_approximately_equals(dummy.f, 3.14, 7); + ensure_equals(dummy.s, "pies"); + } + + template<> template<> + void object::test<18>() + { + call_exc("pqr", LLSD(), "missing required"); + } + + template<> template<> + void object::test<19>() + { + call_exc("pqr", LLSDMap("value", 3.14), "missing required"); + } + + template<> template<> + void object::test<20>() + { + call_exc("pqr", LLSDMap("desc", "pies"), "missing required"); + } + + template<> template<> + void object::test<21>() + { + work("stu", LLSDMap("bar", 3.14)("foo", "pies")); + ensure_equals(dummy.s, "pies"); + ensure_equals(dummy.i, 3); + } + + template<> template<> + void object::test<22>() + { + call_exc("stu", LLSD(), "missing required"); + } + + template<> template<> + void object::test<23>() + { + call_exc("stu", LLSDMap("bar", 3.14), "missing required"); + } + + template<> template<> + void object::test<24>() + { + work("stu", LLSDMap("foo", "pies")); + ensure_equals(dummy.s, "pies"); + ensure_equals(dummy.i, -1); + } + + template<> template<> + void object::test<25>() + { + std::string msg("nonstatic method(const char*)"); + work("vwx", LLSDMap("message", msg)); + ensure_equals(dummy.s, msg); + } +} // namespace tut diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 33e051bfab..abcd8588dc 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -480,10 +480,12 @@ LLLoginInstance::LLLoginInstance() : { mLoginModule->getEventPump().listen("lllogininstance", boost::bind(&LLLoginInstance::handleLoginEvent, this, _1)); - mDispatcher.add("fail.login", boost::bind(&LLLoginInstance::handleLoginFailure, this, _1)); - mDispatcher.add("connect", boost::bind(&LLLoginInstance::handleLoginSuccess, this, _1)); - mDispatcher.add("disconnect", boost::bind(&LLLoginInstance::handleDisconnect, this, _1)); - mDispatcher.add("indeterminate", boost::bind(&LLLoginInstance::handleIndeterminate, this, _1)); + // This internal use of LLEventDispatcher doesn't really need + // per-function descriptions. + mDispatcher.add("fail.login", "", boost::bind(&LLLoginInstance::handleLoginFailure, this, _1)); + mDispatcher.add("connect", "", boost::bind(&LLLoginInstance::handleLoginSuccess, this, _1)); + mDispatcher.add("disconnect", "", boost::bind(&LLLoginInstance::handleDisconnect, this, _1)); + mDispatcher.add("indeterminate", "", boost::bind(&LLLoginInstance::handleIndeterminate, this, _1)); } LLLoginInstance::~LLLoginInstance() @@ -625,11 +627,7 @@ bool LLLoginInstance::handleLoginEvent(const LLSD& event) // Call the method registered in constructor, if any, for more specific // handling - LLEventDispatcher::Callable method(mDispatcher.get(event["change"])); - if (! method.empty()) - { - method(event); - } + mDispatcher.try_call(event); return false; } -- cgit v1.3 From 896bc12a2b9564a770e3eef584c9ec234f39bb3b Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 9 Feb 2011 15:23:07 -0800 Subject: STORM-937 : Fix python scripts shebang line and license header for consistency --- indra/cmake/run_build_test.py | 2 +- indra/copy_win_scripts/start-client.py | 26 ++++++++++- indra/develop.py | 53 ++++++++++----------- indra/lib/python/indra/util/llperformance.py | 26 ++++++++++- .../python/indra/util/simperf_host_xml_parser.py | 2 +- .../python/indra/util/simperf_oprof_interface.py | 2 +- .../python/indra/util/simperf_proc_interface.py | 2 +- indra/lib/python/indra/util/test_win32_manifest.py | 51 ++++++++++---------- indra/llmessage/tests/test_llsdmessage_peer.py | 2 +- indra/llmessage/tests/testrunner.py | 2 +- indra/newview/generate_breakpad_symbols.py | 54 +++++++++++----------- indra/newview/tests/test_llxmlrpc_peer.py | 2 +- indra/newview/viewer_manifest.py | 54 +++++++++++----------- indra/test/test_llmanifest.py | 2 +- scripts/build_version.py | 49 ++++++++++++++------ scripts/install.py | 2 +- scripts/md5check.py | 43 ++++++++--------- scripts/setup-path.py | 2 +- scripts/template_verifier.py | 2 +- scripts/update_version_files.py | 32 +++++++++++-- 20 files changed, 252 insertions(+), 158 deletions(-) (limited to 'indra/newview') diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py index 37aa75e364..320a9be8ab 100644 --- a/indra/cmake/run_build_test.py +++ b/indra/cmake/run_build_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file run_build_test.py @author Nat Goodspeed diff --git a/indra/copy_win_scripts/start-client.py b/indra/copy_win_scripts/start-client.py index 2a96503f01..5699f5273f 100644 --- a/indra/copy_win_scripts/start-client.py +++ b/indra/copy_win_scripts/start-client.py @@ -1,4 +1,28 @@ -#!/usr/bin/python +#!/usr/bin/env python +"""\ +@file start-client.py + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import sys, getopt import os import llstart diff --git a/indra/develop.py b/indra/develop.py index d43cf3aadc..d9a66352f3 100755 --- a/indra/develop.py +++ b/indra/develop.py @@ -1,29 +1,30 @@ -#!/usr/bin/python -# -# @file develop.py -# @authors Bryan O'Sullivan, Mark Palange, Aaron Brashears -# @brief Fire and forget script to appropriately configure cmake for SL. -# -# $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$ +#!/usr/bin/env python +"""\ +@file develop.py +@authors Bryan O'Sullivan, Mark Palange, Aaron Brashears +@brief Fire and forget script to appropriately configure cmake for SL. + +$LicenseInfo:firstyear=2007&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2007-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import errno diff --git a/indra/lib/python/indra/util/llperformance.py b/indra/lib/python/indra/util/llperformance.py index 7c52730b5e..57dd64de3f 100755 --- a/indra/lib/python/indra/util/llperformance.py +++ b/indra/lib/python/indra/util/llperformance.py @@ -1,4 +1,28 @@ -#!/usr/bin/python +#!/usr/bin/env python +"""\ +@file llperformance.py + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" # ------------------------------------------------ # Sim metrics utility functions. diff --git a/indra/lib/python/indra/util/simperf_host_xml_parser.py b/indra/lib/python/indra/util/simperf_host_xml_parser.py index 7801d9fa66..672c1050c2 100755 --- a/indra/lib/python/indra/util/simperf_host_xml_parser.py +++ b/indra/lib/python/indra/util/simperf_host_xml_parser.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file simperf_host_xml_parser.py @brief Digest collector's XML dump and convert to simple dict/list structure diff --git a/indra/lib/python/indra/util/simperf_oprof_interface.py b/indra/lib/python/indra/util/simperf_oprof_interface.py index e3d55d7922..547d2f9980 100755 --- a/indra/lib/python/indra/util/simperf_oprof_interface.py +++ b/indra/lib/python/indra/util/simperf_oprof_interface.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file simperf_oprof_interface.py @brief Manage OProfile data collection on a host diff --git a/indra/lib/python/indra/util/simperf_proc_interface.py b/indra/lib/python/indra/util/simperf_proc_interface.py index da6304a274..de061f68cc 100755 --- a/indra/lib/python/indra/util/simperf_proc_interface.py +++ b/indra/lib/python/indra/util/simperf_proc_interface.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file simperf_proc_interface.py @brief Utility to extract log messages from *..llsd files containing performance statistics. diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py index d4e6115a5a..0532cb0065 100644 --- a/indra/lib/python/indra/util/test_win32_manifest.py +++ b/indra/lib/python/indra/util/test_win32_manifest.py @@ -1,28 +1,29 @@ -#!/usr/bin/python -# @file test_win32_manifest.py -# @brief Test an assembly binding version and uniqueness in a windows dll or exe. -# -# $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$ - +#!/usr/bin/env python +"""\ +@file test_win32_manifest.py +@brief Test an assembly binding version and uniqueness in a windows dll or exe. + +$LicenseInfo:firstyear=2009&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2009-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import sys, os import tempfile from xml.dom.minidom import parse diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index 7eb198bb34..580ee7f8b4 100644 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file test_llsdmessage_peer.py @author Nat Goodspeed diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py index 4d58ef7130..b70ce91ee7 100644 --- a/indra/llmessage/tests/testrunner.py +++ b/indra/llmessage/tests/testrunner.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file testrunner.py @author Nat Goodspeed diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py index 018871d9d3..5ebec1563e 100644 --- a/indra/newview/generate_breakpad_symbols.py +++ b/indra/newview/generate_breakpad_symbols.py @@ -1,29 +1,31 @@ -#!/usr/bin/python -# @file generate_breakpad_symbols.py -# @author Brad Kittenbrink -# @brief Simple tool for generating google_breakpad symbol information -# for the crash reporter. -# -# $LicenseInfo:firstyear=2010&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$ +#!/usr/bin/env python +"""\ +@file generate_breakpad_symbols.py +@author Brad Kittenbrink +@brief Simple tool for generating google_breakpad symbol information + for the crash reporter. + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import collections diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py index aeebb0cfd1..1c7204a6b6 100644 --- a/indra/newview/tests/test_llxmlrpc_peer.py +++ b/indra/newview/tests/test_llxmlrpc_peer.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file test_llxmlrpc_peer.py @author Nat Goodspeed diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 338c62b9fb..1722c84d34 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1,29 +1,31 @@ -#!/usr/bin/python -# @file viewer_manifest.py -# @author Ryan Williams -# @brief Description of all installer viewer files, and methods for packaging -# them into installers for all supported platforms. -# -# $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$ +#!/usr/bin/env python +"""\ +@file viewer_manifest.py +@author Ryan Williams +@brief Description of all installer viewer files, and methods for packaging + them into installers for all supported platforms. + +$LicenseInfo:firstyear=2006&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2006-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import sys import os.path import re diff --git a/indra/test/test_llmanifest.py b/indra/test/test_llmanifest.py index 89c36f95dd..a97abbc6ee 100644 --- a/indra/test/test_llmanifest.py +++ b/indra/test/test_llmanifest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ @file test_llmanifest.py @author Ryan Williams diff --git a/scripts/build_version.py b/scripts/build_version.py index 46536b1468..203d76fe9e 100755 --- a/scripts/build_version.py +++ b/scripts/build_version.py @@ -1,16 +1,39 @@ -#!/usr/bin/python -# -# Print the build information embedded in a header file. -# -# Expects to be invoked from the command line with a file name and a -# list of directories to search. The file name will be one of the -# following: -# -# llversionserver.h -# llversionviewer.h -# -# The directory list that follows will include indra/llcommon, where -# these files live. +#!/usr/bin/env python +"""\ +@file build_version.py +@brief Print the build information embedded in a header file. + + Expects to be invoked from the command line with a file name and a + list of directories to search. The file name will be one of the + following: + + llversionserver.h + llversionviewer.h + + The directory list that follows will include indra/llcommon, where + these files live. + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import errno, os, re diff --git a/scripts/install.py b/scripts/install.py index 9dd77864f4..d3bdf52283 100755 --- a/scripts/install.py +++ b/scripts/install.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file install.py @author Phoenix diff --git a/scripts/md5check.py b/scripts/md5check.py index 951fe0105c..1a54a2844c 100755 --- a/scripts/md5check.py +++ b/scripts/md5check.py @@ -1,32 +1,27 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file md5check.py @brief Replacement for message template compatibility verifier. -$LicenseInfo:firstyear=20i10&license=viewergpl$ -Copyright (c) 2010, Linden Research, Inc. - +$LicenseInfo:firstyear=2010&license=viewerlgpl$ Second Life Viewer Source Code -The source code in this file ("Source Code") is provided by Linden Lab -to you under the terms of the GNU General Public License, version 2.0 -("GPL"), unless you have obtained a separate licensing agreement -("Other License"), formally executed by you and Linden Lab. Terms of -the GPL can be found in doc/GPL-license.txt in this distribution, or -online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - -There are special exceptions to the terms and conditions of the GPL as -it is applied to this Source Code. View the full text of the exception -in the file doc/FLOSS-exception.txt in this software distribution, or -online at -http://secondlifegrid.net/programs/open_source/licensing/flossexception - -By copying, modifying or distributing this software, you acknowledge -that you have read and understood your obligations described above, -and agree to abide by those obligations. - -ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -COMPLETENESS OR PERFORMANCE. +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA $/LicenseInfo$ """ diff --git a/scripts/setup-path.py b/scripts/setup-path.py index 55e0f1a85f..ce83d815bf 100644 --- a/scripts/setup-path.py +++ b/scripts/setup-path.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file setup-path.py @brief Get the python library directory in the path, so we don't have diff --git a/scripts/template_verifier.py b/scripts/template_verifier.py index ddb050fbbb..7f3fed88a9 100644 --- a/scripts/template_verifier.py +++ b/scripts/template_verifier.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """\ @file template_verifier.py @brief Message template compatibility verifier. diff --git a/scripts/update_version_files.py b/scripts/update_version_files.py index da60fd105a..c2fa8a8d31 100755 --- a/scripts/update_version_files.py +++ b/scripts/update_version_files.py @@ -1,8 +1,30 @@ -#!/usr/bin/python -# -# Update all of the various files in the repository to a new version number, -# instead of having to figure it out by hand -# +#!/usr/bin/env python +"""\ +@file update_version_files.py +@brief Update all of the various files in the repository to a new version number, +instead of having to figure it out by hand + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import sys import os.path -- cgit v1.3 From f13884e528c327dbbc638b72322e08b544d0f6c0 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 15 Feb 2011 14:12:58 -0700 Subject: partial fix for SH-895/STORM-336: memory leaking. fixed vertex buffer caused leaking. --- indra/llrender/llvertexbuffer.cpp | 101 ++++++++++++++++++++++++++++++-- indra/llrender/llvertexbuffer.h | 15 +++-- indra/newview/app_settings/settings.xml | 11 ++++ indra/newview/llviewercontrol.cpp | 10 ++++ indra/newview/llviewerwindow.cpp | 2 +- indra/newview/pipeline.cpp | 20 ++++++- indra/newview/pipeline.h | 1 + 7 files changed, 148 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 02160b09c4..660dc14d02 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -47,6 +47,7 @@ U32 LLVertexBuffer::sSetCount = 0; S32 LLVertexBuffer::sCount = 0; S32 LLVertexBuffer::sGLCount = 0; S32 LLVertexBuffer::sMappedCount = 0; +BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ; BOOL LLVertexBuffer::sEnableVBOs = TRUE; U32 LLVertexBuffer::sGLRenderBuffer = 0; U32 LLVertexBuffer::sGLRenderIndices = 0; @@ -212,6 +213,11 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi { llassert(mRequestedNumVerts >= 0); + if(mDirty) + { + postUpdate() ; + } + if (start >= (U32) mRequestedNumVerts || end >= (U32) mRequestedNumVerts) { @@ -251,6 +257,12 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { llassert(mRequestedNumIndices >= 0); + + if(mDirty) + { + postUpdate() ; + } + if (indices_offset >= (U32) mRequestedNumIndices || indices_offset + count > (U32) mRequestedNumIndices) { @@ -282,6 +294,12 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(mRequestedNumVerts >= 0); + + if(mDirty) + { + postUpdate() ; + } + if (first >= (U32) mRequestedNumVerts || first + count > (U32) mRequestedNumVerts) { @@ -305,9 +323,10 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const } //static -void LLVertexBuffer::initClass(bool use_vbo) +void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) { sEnableVBOs = use_vbo; + sDisableVBOMapping = no_vbo_mapping ; LLGLNamePool::registerPool(&sDynamicVBOPool); LLGLNamePool::registerPool(&sDynamicIBOPool); LLGLNamePool::registerPool(&sStreamVBOPool); @@ -369,7 +388,8 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mFilthy(FALSE), mEmpty(TRUE), mResized(FALSE), - mDynamicSize(FALSE) + mDynamicSize(FALSE), + mDirty(FALSE) { LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR); if (!sEnableVBOs) @@ -567,6 +587,8 @@ void LLVertexBuffer::destroyGLBuffer() { if (useVBOs()) { + freeClientBuffer() ; + if (mMappedData || mMappedIndexData) { llerrs << "Vertex buffer destroyed while mapped!" << llendl; @@ -594,11 +616,13 @@ void LLVertexBuffer::destroyGLIndices() { if (useVBOs()) { + freeClientBuffer() ; + if (mMappedData || mMappedIndexData) { llerrs << "Vertex buffer destroyed while mapped." << llendl; } - releaseIndices(); + releaseIndices(); } else { @@ -799,6 +823,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) if (mResized && useVBOs()) { + freeClientBuffer() ; setBuffer(0); } } @@ -822,6 +847,60 @@ BOOL LLVertexBuffer::useVBOs() const } //---------------------------------------------------------------------------- +void LLVertexBuffer::freeClientBuffer() +{ + if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) + { + delete[] mMappedData ; + delete[] mMappedIndexData ; + mMappedData = NULL ; + mMappedIndexData = NULL ; + } +} + +void LLVertexBuffer::preUpdate() +{ + if(!useVBOs() || !sDisableVBOMapping) + { + return ; + } + + if(!mMappedData) + { + U32 size = getSize() ; + mMappedData = new U8[size]; + memset(mMappedData, 0, size); + } + + if(!mMappedIndexData) + { + U32 size = getIndicesSize(); + mMappedIndexData = new U8[size]; + memset(mMappedIndexData, 0, size); + } + + mDirty = TRUE ; +} + +void LLVertexBuffer::postUpdate() const +{ + if(!useVBOs() || !sDisableVBOMapping) + { + return ; + } + + llassert_always(mMappedData && mMappedIndexData) ; + + //release the existing buffers + glBufferDataARB(GL_ARRAY_BUFFER_ARB, 0, NULL, mUsage); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, NULL, mUsage); + + //update to the new buffers + glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), mMappedData, mUsage); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), mMappedIndexData, mUsage); + + mDirty = FALSE ; +} // Map for data access U8* LLVertexBuffer::mapBuffer(S32 access) @@ -836,6 +915,12 @@ U8* LLVertexBuffer::mapBuffer(S32 access) llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl; } + if(useVBOs() && sDisableVBOMapping) + { + preUpdate() ; + return mMappedData ; + } + if (!mLocked && useVBOs()) { { @@ -906,7 +991,11 @@ void LLVertexBuffer::unmapBuffer() LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); if (mMappedData || mMappedIndexData) { - if (useVBOs() && mLocked) + if(sDisableVBOMapping && useVBOs()) + { + return ; + } + else if (useVBOs() && mLocked) { stop_glerror(); glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); @@ -1152,13 +1241,13 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } - if (mGLBuffer) + if (mGLBuffer && !sDisableVBOMapping) { stop_glerror(); glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage); stop_glerror(); } - if (mGLIndices) + if (mGLIndices && !sDisableVBOMapping) { stop_glerror(); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 94fa790957..18d50c87bb 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -80,7 +80,7 @@ public: static BOOL sUseStreamDraw; - static void initClass(bool use_vbo); + static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); static void clientCopy(F64 max_time = 0.005); //copy data from client to GL @@ -152,6 +152,11 @@ public: void allocateBuffer(S32 nverts, S32 nindices, bool create); virtual void resizeBuffer(S32 newnverts, S32 newnindices); + void preUpdate() ; + void postUpdate() const ; + void freeClientBuffer() ; + void dirty() {mDirty = TRUE;} + // Only call each getVertexPointer, etc, once before calling unmapBuffer() // call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer() // example: @@ -216,6 +221,7 @@ protected: S32 mOffsets[TYPE_MAX]; BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) + mutable BOOL mDirty ; class DirtyRegion { @@ -240,13 +246,14 @@ public: static std::vector sDeleteList; typedef std::list buffer_list_t; + static BOOL sDisableVBOMapping; //disable glMapBufferARB static BOOL sEnableVBOs; + static BOOL sVBOActive; + static BOOL sIBOActive; static S32 sTypeOffsets[TYPE_MAX]; static U32 sGLMode[LLRender::NUM_MODES]; static U32 sGLRenderBuffer; - static U32 sGLRenderIndices; - static BOOL sVBOActive; - static BOOL sIBOActive; + static U32 sGLRenderIndices; static U32 sLastMask; static U32 sAllocatedBytes; static U32 sBindCount; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6630d8f400..58abd4c091 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8451,6 +8451,17 @@ Value 1 + RenderVBOMappingDisable + + Comment + Disable VBO glMapBufferARB + Persist + 1 + Type + Boolean + Value + 0 + RenderUseStreamVBO Comment diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 8c5a52c187..3c53e54203 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -309,6 +309,15 @@ static bool handleRenderUseVBOChanged(const LLSD& newvalue) return true; } +static bool handleRenderUseVBOMappingChanged(const LLSD& newvalue) +{ + if (gPipeline.isInit()) + { + gPipeline.setDisableVBOMapping(newvalue.asBoolean()); + } + return true; +} + static bool handleWLSkyDetailChanged(const LLSD&) { if (gSky.mVOWLSkyp.notNull()) @@ -589,6 +598,7 @@ void settings_setup_listeners() gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _2)); + gSavedSettings.getControl("RenderVBOMappingDisable")->getSignal()->connect(boost::bind(&handleRenderUseVBOMappingChanged, _2)); gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2)); gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 274dbe2cc8..0028ced6c8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1477,7 +1477,7 @@ LLViewerWindow::LLViewerWindow( { gSavedSettings.setBOOL("RenderVBOEnable", FALSE); } - LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable")); + LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); if (LLFeatureManager::getInstance()->isSafe() || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 39bc354250..13e537fae5 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -5313,7 +5313,25 @@ void LLPipeline::setUseVBO(BOOL use_vbo) } resetVertexBuffers(); - LLVertexBuffer::initClass(use_vbo); + LLVertexBuffer::initClass(use_vbo, gSavedSettings.getBOOL("RenderVBOMappingDisable")); + } +} + +void LLPipeline::setDisableVBOMapping(BOOL no_vbo_mapping) +{ + if (LLVertexBuffer::sEnableVBOs && no_vbo_mapping != LLVertexBuffer::sDisableVBOMapping) + { + if (no_vbo_mapping) + { + llinfos << "Disabling VBO glMapBufferARB." << llendl; + } + else + { + llinfos << "Enabling VBO glMapBufferARB." << llendl; + } + + resetVertexBuffers(); + LLVertexBuffer::initClass(true, no_vbo_mapping); } } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index cef3d87f36..e99b0d71e3 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -111,6 +111,7 @@ public: void resetVertexBuffers(LLDrawable* drawable); void setUseVBO(BOOL use_vbo); + void setDisableVBOMapping(BOOL no_vbo_mapping); void generateImpostor(LLVOAvatar* avatar); void bindScreenToTexture(); void renderBloom(BOOL for_snapshot, F32 zoom_factor = 1.f, int subfield = 0); -- cgit v1.3 From 5946d84eef30caeae6dee63767fabdcf81613984 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 16 Feb 2011 12:49:35 -0500 Subject: SWAT-484, SWAT-485: add LLSideTrayListener, a new LLEventAPI. Expand XUI-visible LLUICtrl::CommitCallbackRegistry operations to include "SideTray.Toggle" and "SideTray.Collapse". Give LLSideTrayListener friend access to LLSideTray so it can query the attached and detached tabs. Introduce tab_cast template to deal with the unavailability of the LLSideTrayTab class outside of llsidetray.cpp. --- indra/newview/CMakeLists.txt | 2 + indra/newview/llsidetray.cpp | 11 +++ indra/newview/llsidetray.h | 10 +++ indra/newview/llsidetraylistener.cpp | 167 +++++++++++++++++++++++++++++++++++ indra/newview/llsidetraylistener.h | 36 ++++++++ 5 files changed, 226 insertions(+) create mode 100644 indra/newview/llsidetraylistener.cpp create mode 100644 indra/newview/llsidetraylistener.h (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index af6beacdfa..11bebf04ef 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -412,6 +412,7 @@ set(viewer_SOURCE_FILES llsidepaneliteminfo.cpp llsidepaneltaskinfo.cpp llsidetray.cpp + llsidetraylistener.cpp llsidetraypanelcontainer.cpp llsky.cpp llslurl.cpp @@ -947,6 +948,7 @@ set(viewer_HEADER_FILES llsidepaneliteminfo.h llsidepaneltaskinfo.h llsidetray.h + llsidetraylistener.h llsidetraypanelcontainer.h llsky.h llslurl.h diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index eb537c7d7b..85efebabfe 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -53,6 +53,8 @@ #include "llsidepanelappearance.h" +#include "llsidetraylistener.h" + //#include "llscrollcontainer.h" using namespace std; @@ -71,6 +73,8 @@ static const std::string TAB_PANEL_CAPTION_TITLE_BOX = "sidetray_tab_title"; LLSideTray* LLSideTray::sInstance = 0; +static LLSideTrayListener sSideTrayListener(LLSideTray::getInstance); + // static LLSideTray* LLSideTray::getInstance() { @@ -417,6 +421,11 @@ LLSideTrayTab* LLSideTrayTab::createInstance () return tab; } +// Now that we know the definition of LLSideTrayTab, we can implement +// tab_cast. +template <> +LLPanel* tab_cast(LLSideTrayTab* tab) { return tab; } + ////////////////////////////////////////////////////////////////////////////// // LLSideTrayButton // Side Tray tab button with "tear off" handling. @@ -530,6 +539,8 @@ LLSideTray::LLSideTray(const Params& params) // register handler function to process data from the xml. // panel_name should be specified via "parameter" attribute. commit.add("SideTray.ShowPanel", boost::bind(&LLSideTray::showPanel, this, _2, LLUUID::null)); + commit.add("SideTray.Toggle", boost::bind(&LLSideTray::onToggleCollapse, this)); + commit.add("SideTray.Collapse", boost::bind(&LLSideTray::collapseSideBar, this)); LLTransientFloaterMgr::getInstance()->addControlView(this); LLView* side_bar_tabs = gViewerWindow->getRootView()->getChildView("side_bar_tabs"); if (side_bar_tabs != NULL) diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h index 184d78845f..c4d3c2626c 100644 --- a/indra/newview/llsidetray.h +++ b/indra/newview/llsidetray.h @@ -33,6 +33,13 @@ class LLAccordionCtrl; class LLSideTrayTab; +// Deal with LLSideTrayTab being opaque. Generic do-nothing cast... +template +T tab_cast(LLSideTrayTab* tab) { return tab; } +// specialized for implementation in presence of LLSideTrayTab definition +template <> +LLPanel* tab_cast(LLSideTrayTab* tab); + // added inheritance from LLDestroyClass to enable Side Tray perform necessary actions // while disconnecting viewer in LLAppViewer::disconnectViewer(). // LLDestroyClassList::instance().fireCallbacks() calls destroyClass method. See EXT-245. @@ -217,6 +224,9 @@ private: } private: + // Since we provide no public way to query mTabs and mDetachedTabs, give + // LLSideTrayListener friend access. + friend class LLSideTrayListener; LLPanel* mButtonsPanel; typedef std::map button_map_t; button_map_t mTabButtons; diff --git a/indra/newview/llsidetraylistener.cpp b/indra/newview/llsidetraylistener.cpp new file mode 100644 index 0000000000..185bf1d6a7 --- /dev/null +++ b/indra/newview/llsidetraylistener.cpp @@ -0,0 +1,167 @@ +/** + * @file llsidetraylistener.cpp + * @author Nat Goodspeed + * @date 2011-02-15 + * @brief Implementation for llsidetraylistener. + * + * $LicenseInfo:firstyear=2011&license=lgpl$ + * Copyright (c) 2011, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "llviewerprecompiledheaders.h" +// associated header +#include "llsidetraylistener.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llsidetray.h" +#include "llsdutil.h" + +LLSideTrayListener::LLSideTrayListener(const Getter& getter): + LLEventAPI("LLSideTray", + "Operations on side tray (e.g. query state, query tabs)"), + mGetter(getter) +{ + add("getCollapsed", "Send on [\"reply\"] an [\"open\"] Boolean", + &LLSideTrayListener::getCollapsed, LLSDMap("reply", LLSD())); + add("getTabs", + "Send on [\"reply\"] a map of tab names and info about them", + &LLSideTrayListener::getTabs, LLSDMap("reply", LLSD())); + add("getPanels", + "Send on [\"reply\"] data about panels available with SideTray.ShowPanel", + &LLSideTrayListener::getPanels, LLSDMap("reply", LLSD())); +} + +void LLSideTrayListener::getCollapsed(const LLSD& event) const +{ + LLReqID reqID(event); + LLSD reply(reqID.makeResponse()); + reply["open"] = ! mGetter()->getCollapsed(); + LLEventPumps::instance().obtain(event["reply"]).post(reply); +} + +void LLSideTrayListener::getTabs(const LLSD& event) const +{ + LLReqID reqID(event); + LLSD reply(reqID.makeResponse()); + + LLSideTray* tray = mGetter(); + LLSD::Integer ord(0); + for (LLSideTray::child_list_const_iter_t chi(tray->beginChild()), chend(tray->endChild()); + chi != chend; ++chi, ++ord) + { + LLView* child = *chi; + // How much info is important? Toss in as much as seems reasonable for + // each tab. But to me, at least for the moment, the most important + // item is the tab name. + LLSD info; + // I like the idea of returning a map keyed by tab name. But as + // compared to an array of maps, that loses sequence information. + // Address that by indicating the original order in each map entry. + info["ord"] = ord; + info["visible"] = bool(child->getVisible()); + info["enabled"] = bool(child->getEnabled()); + info["available"] = child->isAvailable(); + reply[child->getName()] = info; + } + + LLEventPumps::instance().obtain(event["reply"]).post(reply); +} + +static LLSD getTabInfo(LLPanel* tab) +{ + LLSD panels; + for (LLPanel::tree_iterator_t ti(tab->beginTreeDFS()), tend(tab->endTreeDFS()); + ti != tend; ++ti) + { + // *ti is actually an LLView*, which had better not be NULL + LLView* view(*ti); + if (! view) + { + LL_ERRS("LLSideTrayListener") << "LLSideTrayTab '" << tab->getName() + << "' has a NULL child LLView*" << LL_ENDL; + } + + // The logic we use to decide what "panel" names to return is heavily + // based on LLSideTray::showPanel(): the function that actually + // implements the "SideTray.ShowPanel" operation. showPanel(), in + // turn, depends on LLSideTray::openChildPanel(): when + // openChildPanel() returns non-NULL, showPanel() stops searching + // attached and detached LLSideTrayTab tabs. + + // For each LLSideTrayTab, openChildPanel() first calls + // findChildView(panel_name, true). In other words, panel_name need + // not be a direct LLSideTrayTab child, it's sought recursively. + // That's why we use (begin|end)TreeDFS() in this loop. + + // But this tree_iterator_t loop will actually traverse every widget + // in every panel. Returning all those names will not help our caller: + // passing most such names to openChildPanel() would not do what we + // want. Even though the code suggests that passing ANY valid + // side-panel widget name to openChildPanel() will open the tab + // containing that widget, results could get confusing since followup + // (onOpen()) logic wouldn't be invoked, and showPanel() wouldn't stop + // searching because openChildPanel() would return NULL. + + // We must filter these LLView items, using logic that (sigh!) mirrors + // openChildPanel()'s own. + + // openChildPanel() returns a non-NULL LLPanel* when either: + // - the LLView is a direct child of an LLSideTrayPanelContainer + // - the LLView is itself an LLPanel. + // But as LLSideTrayPanelContainer can directly contain LLView items + // that are NOT themselves LLPanels (e.g. "sidebar_me" contains an + // LLButton called "Jump Right Arrow"), we'd better focus only on + // LLSideTrayPanelContainer children that are themselves LLPanel + // items. Which means that the second test completely subsumes the + // first. + LLPanel* panel(dynamic_cast(view)); + if (panel) + { + // Maybe it's overkill to construct an LLSD::Map for each panel, but + // the possibility remains that we might want to deliver more info + // about each panel than just its name. + panels.append(LLSDMap("name", panel->getName())); + } + } + + return LLSDMap("panels", panels); +} + +void LLSideTrayListener::getPanels(const LLSD& event) const +{ + LLReqID reqID(event); + LLSD reply(reqID.makeResponse()); + + LLSideTray* tray = mGetter(); + // Iterate through the attached tabs. + LLSD::Integer ord(0); + for (LLSideTray::child_vector_t::const_iterator + ati(tray->mTabs.begin()), atend(tray->mTabs.end()); + ati != atend; ++ati) + { + // We don't have access to LLSideTrayTab: the class definition is + // hidden in llsidetray.cpp. But as LLSideTrayTab isa LLPanel, use the + // LLPanel API. Unfortunately, without the LLSideTrayTab definition, + // the compiler doesn't even know this LLSideTrayTab* is an LLPanel*. + // Persuade it. + LLPanel* tab(tab_cast(*ati)); + reply[tab->getName()] = getTabInfo(tab).with("attached", true).with("ord", ord); + } + + // Now iterate over the detached tabs. These can also be opened via + // SideTray.ShowPanel. + ord = 0; + for (LLSideTray::child_vector_t::const_iterator + dti(tray->mDetachedTabs.begin()), dtend(tray->mDetachedTabs.end()); + dti != dtend; ++dti) + { + LLPanel* tab(tab_cast(*dti)); + reply[tab->getName()] = getTabInfo(tab).with("attached", false).with("ord", ord); + } + + LLEventPumps::instance().obtain(event["reply"]).post(reply); +} diff --git a/indra/newview/llsidetraylistener.h b/indra/newview/llsidetraylistener.h new file mode 100644 index 0000000000..0dd2067433 --- /dev/null +++ b/indra/newview/llsidetraylistener.h @@ -0,0 +1,36 @@ +/** + * @file llsidetraylistener.h + * @author Nat Goodspeed + * @date 2011-02-15 + * @brief + * + * $LicenseInfo:firstyear=2011&license=lgpl$ + * Copyright (c) 2011, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLSIDETRAYLISTENER_H) +#define LL_LLSIDETRAYLISTENER_H + +#include "lleventapi.h" +#include + +class LLSideTray; +class LLSD; + +class LLSideTrayListener: public LLEventAPI +{ + typedef boost::function Getter; + +public: + LLSideTrayListener(const Getter& getter); + +private: + void getCollapsed(const LLSD& event) const; + void getTabs(const LLSD& event) const; + void getPanels(const LLSD& event) const; + + Getter mGetter; +}; + +#endif /* ! defined(LL_LLSIDETRAYLISTENER_H) */ -- cgit v1.3 From 4ef02bc1b6cf5e044d2cf57725eac1a4ccd7580d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 18 Feb 2011 10:56:26 -0500 Subject: Introduce and use new sendReply() function for LLEventAPI methods. Each LLEventAPI method that generates a reply needs to extract the name of the reply LLEventPump from the request, typically from a ["reply"] key, copy the ["reqid"] value from request to reply, locate the reply LLEventPump and send the enriched reply object. Encapsulate in sendReply() function before we proliferate doing all that by hand too many more times. --- indra/llcommon/llevents.cpp | 13 +++++++++++++ indra/llcommon/llevents.h | 14 ++++++++++++++ indra/llui/llfloaterreglistener.cpp | 12 ++++-------- indra/newview/llsidetraylistener.cpp | 15 +++++---------- indra/newview/llviewerwindowlistener.cpp | 5 +---- 5 files changed, 37 insertions(+), 22 deletions(-) (limited to 'indra/newview') diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 97e2bdeb57..ff03506e84 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -588,3 +588,16 @@ void LLReqID::stamp(LLSD& response) const } response["reqid"] = mReqid; } + +bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey) +{ + // 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); +} diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 2491cf1371..65b0fef354 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -691,6 +691,20 @@ private: LLSD mReqid; }; +/** + * Conventionally send a reply to a request event. + * + * @a reply is the LLSD reply event to send + * @a request is the corresponding LLSD request event + * @a replyKey is the key in the @a request event, conventionally ["reply"], + * whose value is the name of the LLEventPump on which to send the reply. + * + * 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, + const std::string& replyKey="reply"); + /** * Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We * provide virtual @c accept_xxx() methods, customization points allowing a diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index ec2ac6834e..7525b8cab3 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -76,9 +76,7 @@ LLFloaterRegListener::LLFloaterRegListener(): void LLFloaterRegListener::getBuildMap(const LLSD& event) const { - // Honor the "reqid" convention by echoing event["reqid"] in our reply packet. - LLReqID reqID(event); - LLSD reply(reqID.makeResponse()); + LLSD reply; // Build an LLSD map that mirrors sBuildMap. Since we have no good way to // represent a C++ callable in LLSD, the only part of BuildData we can // store is the filename. For each LLSD map entry, it would be more @@ -91,7 +89,7 @@ void LLFloaterRegListener::getBuildMap(const LLSD& event) const reply[mi->first] = mi->second.mFile; } // Send the reply to the LLEventPump named in event["reply"]. - LLEventPumps::instance().obtain(event["reply"]).post(reply); + sendReply(reply, event); } void LLFloaterRegListener::showInstance(const LLSD& event) const @@ -111,10 +109,8 @@ void LLFloaterRegListener::toggleInstance(const LLSD& event) const void LLFloaterRegListener::instanceVisible(const LLSD& event) const { - LLReqID reqID(event); - LLSD reply(reqID.makeResponse()); - reply["visible"] = LLFloaterReg::instanceVisible(event["name"], event["key"]); - LLEventPumps::instance().obtain(event["reply"]).post(reply); + sendReply(LLSDMap("visible", LLFloaterReg::instanceVisible(event["name"], event["key"])), + event); } void LLFloaterRegListener::clickButton(const LLSD& event) const diff --git a/indra/newview/llsidetraylistener.cpp b/indra/newview/llsidetraylistener.cpp index 185bf1d6a7..6db13e517d 100644 --- a/indra/newview/llsidetraylistener.cpp +++ b/indra/newview/llsidetraylistener.cpp @@ -37,16 +37,12 @@ LLSideTrayListener::LLSideTrayListener(const Getter& getter): void LLSideTrayListener::getCollapsed(const LLSD& event) const { - LLReqID reqID(event); - LLSD reply(reqID.makeResponse()); - reply["open"] = ! mGetter()->getCollapsed(); - LLEventPumps::instance().obtain(event["reply"]).post(reply); + sendReply(LLSDMap("open", ! mGetter()->getCollapsed()), event); } void LLSideTrayListener::getTabs(const LLSD& event) const { - LLReqID reqID(event); - LLSD reply(reqID.makeResponse()); + LLSD reply; LLSideTray* tray = mGetter(); LLSD::Integer ord(0); @@ -68,7 +64,7 @@ void LLSideTrayListener::getTabs(const LLSD& event) const reply[child->getName()] = info; } - LLEventPumps::instance().obtain(event["reply"]).post(reply); + sendReply(reply, event); } static LLSD getTabInfo(LLPanel* tab) @@ -133,8 +129,7 @@ static LLSD getTabInfo(LLPanel* tab) void LLSideTrayListener::getPanels(const LLSD& event) const { - LLReqID reqID(event); - LLSD reply(reqID.makeResponse()); + LLSD reply; LLSideTray* tray = mGetter(); // Iterate through the attached tabs. @@ -163,5 +158,5 @@ void LLSideTrayListener::getPanels(const LLSD& event) const reply[tab->getName()] = getTabInfo(tab).with("attached", false).with("ord", ord); } - LLEventPumps::instance().obtain(event["reply"]).post(reply); + sendReply(reply, event); } diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp index 0b52948680..1fe5fc9800 100644 --- a/indra/newview/llviewerwindowlistener.cpp +++ b/indra/newview/llviewerwindowlistener.cpp @@ -65,7 +65,6 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow): void LLViewerWindowListener::saveSnapshot(const LLSD& event) const { - LLReqID reqid(event); typedef std::map TypeMap; TypeMap types; #define tp(name) types[#name] = LLViewerWindow::SNAPSHOT_TYPE_##name @@ -98,9 +97,7 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const type = found->second; } bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, rebuild, type); - LLSD response(reqid.makeResponse()); - response["ok"] = ok; - LLEventPumps::instance().obtain(event["reply"]).post(response); + sendReply(LLSDMap("ok", ok), event); } void LLViewerWindowListener::requestReshape(LLSD const & event_data) const -- cgit v1.3 From 0e39a7881e29fe58761403424941b78f82042ac1 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 18 Feb 2011 11:31:18 -0800 Subject: Initial stub for getValue() and path walker --- indra/newview/lluilistener.cpp | 31 +++++++++++++++++++++++++++++++ indra/newview/lluilistener.h | 1 + 2 files changed, 32 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 4d6eac4958..dafca0abf2 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -47,6 +47,12 @@ LLUIListener::LLUIListener(): "as if from a user gesture on a menu -- or a button click.", &LLUIListener::call, LLSD().with("function", LLSD())); + + add("getValue", + "For the UI control identified by the path in [\"path\"], return the control's\n" + "current value as [\"value\"] reply.", + &LLUIListener::getValue, + LLSD().with("path", LLSD())); } void LLUIListener::call(const LLSD& event) const @@ -71,3 +77,28 @@ void LLUIListener::call(const LLSD& event) const (*func)(NULL, event["parameter"]); } } + +const LLUICtrl* resolve_path(const LLUICtrl* base, const std::string path) +{ + // *TODO: walk the path + return NULL; +} + +void LLUIListener::getValue(const LLSD&event) const +{ + LLSD reply; + + const LLUICtrl* root = NULL; // *TODO: look this up + const LLUICtrl* ctrl = resolve_path(root, event["path"].asString()); + + if (ctrl) + { + reply["value"] = ctrl->getValue(); + } + else + { + // *TODO: ??? return something indicating failure to resolve + } + + sendReply(reply, event, "reply"); +} diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h index e7847f01e8..08724024dc 100644 --- a/indra/newview/lluilistener.h +++ b/indra/newview/lluilistener.h @@ -41,6 +41,7 @@ public: private: void call(const LLSD& event) const; + void getValue(const LLSD&event) const; }; #endif /* ! defined(LL_LLUILISTENER_H) */ -- cgit v1.3 From f6970e6ad1f0576ec194fdc8d369030f1e31aeab Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 18 Feb 2011 13:04:41 -0800 Subject: Implemented path resolution. Should be able to test this now. --- indra/newview/lluilistener.cpp | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index dafca0abf2..22d3b8b219 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -34,9 +34,11 @@ // std headers // external library headers // other Linden headers +#include "llviewerwindow.h" // to get root view #include "lluictrl.h" #include "llerror.h" + LLUIListener::LLUIListener(): LLEventAPI("UI", "LLUICtrl::CommitCallbackRegistry listener.\n" @@ -78,9 +80,38 @@ void LLUIListener::call(const LLSD& event) const } } -const LLUICtrl* resolve_path(const LLUICtrl* base, const std::string path) +const LLView* resolve_path(const LLView* context, const std::string path) { - // *TODO: walk the path + std::vector parts; + const std::string delims("/"); + LLStringUtilBase::getTokens(path, parts, delims); + + bool recurse = false; + for (std::vector::iterator it = parts.begin(); + it != parts.end() && context; it++) + { + std::string part = *it; + + if (part.length() == 0) + { + // Allow "foo//bar" meaning "descendant named bar" + recurse = true; + } + else + { + const LLView* found = context->findChildView(part, recurse); + if (!found) + { + return NULL; + } + else + { + context = found; + } + recurse = false; + } + } + return NULL; } @@ -88,9 +119,10 @@ void LLUIListener::getValue(const LLSD&event) const { LLSD reply; - const LLUICtrl* root = NULL; // *TODO: look this up - const LLUICtrl* ctrl = resolve_path(root, event["path"].asString()); - + const LLView* root = (LLView*)(gViewerWindow->getRootView()); + const LLView* view = resolve_path(root, event["path"].asString()); + const LLUICtrl* ctrl(dynamic_cast(view)); + if (ctrl) { reply["value"] = ctrl->getValue(); -- cgit v1.3 From 18bf5f09b22a2c36ccf543104b1115a7b0b9db71 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 18 Feb 2011 17:49:01 -0500 Subject: Add LLAgent operations to set/query avatar orientation. --- indra/newview/llagentlistener.cpp | 36 ++++++++++++++++++++++++++++++++++++ indra/newview/llagentlistener.h | 2 ++ 2 files changed, 38 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index d520debc31..c453fe91f4 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -37,6 +37,8 @@ #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llsdutil.h" +#include "llsdutil_math.h" LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -53,6 +55,15 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("requestStand", "Ask to stand up", &LLAgentListener::requestStand); + add("resetAxes", + "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])", + &LLAgentListener::resetAxes); + add("getAxes", + "Send information about the agent's orientation on [\"reply\"]:\n" + "[\"euler\"]: map of {roll, pitch, yaw}\n" + "[\"quat\"]: array of [x, y, z, w] quaternion values", + &LLAgentListener::getAxes, + LLSDMap("reply", LLSD())); } void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -104,3 +115,28 @@ void LLAgentListener::requestStand(LLSD const & event_data) const mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } +void LLAgentListener::resetAxes(const LLSD& event) const +{ + if (event.has("lookat")) + { + mAgent.resetAxes(ll_vector3_from_sd(event["lookat"])); + } + else + { + // no "lookat", default call + mAgent.resetAxes(); + } +} + +void LLAgentListener::getAxes(const LLSD& event) const +{ + LLQuaternion quat(mAgent.getQuat()); + F32 roll, pitch, yaw; + quat.getEulerAngles(&roll, &pitch, &yaw); + // The official query API for LLQuaternion's [x, y, z, w] values is its + // public member mQ... + sendReply(LLSDMap + ("quat", llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ))) + ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)), + event); +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 9b585152f4..0aa58d0b16 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -44,6 +44,8 @@ private: void requestTeleport(LLSD const & event_data) const; void requestSit(LLSD const & event_data) const; void requestStand(LLSD const & event_data) const; + void resetAxes(const LLSD& event) const; + void getAxes(const LLSD& event) const; private: LLAgent & mAgent; -- cgit v1.3 From 774405e92bec6bdfa9e2be28e04b4b47fd71615e Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 18 Feb 2011 23:16:38 +0000 Subject: Cleanup of headless client (was: DisableRendering mode) * Now called 'HeadlessClient' instead of 'DisableRendering' * Removed most cases where we skipped certain behaviors in the client when in this mode. This gets us closer to a 'true' client, for testing purposes. --- indra/llrender/llgl.cpp | 88 ++++++++++++++------- indra/llrender/llgl.h | 2 +- indra/llrender/llimagegl.cpp | 8 +- indra/llwindow/llwindowheadless.cpp | 1 + indra/newview/app_settings/settings.xml | 4 +- indra/newview/llagent.cpp | 11 --- indra/newview/llagentcamera.cpp | 29 ++++--- indra/newview/llappviewer.cpp | 118 +++++++++++++--------------- indra/newview/llfloaterbump.cpp | 2 - indra/newview/llhudeffectlookat.cpp | 5 -- indra/newview/llhudmanager.cpp | 7 -- indra/newview/llimview.cpp | 9 --- indra/newview/llselectmgr.cpp | 18 ++--- indra/newview/llstartup.cpp | 132 +++++++++++++------------------- indra/newview/llsurface.cpp | 5 -- indra/newview/lltexturestats.cpp | 2 +- indra/newview/llviewerdisplay.cpp | 6 +- indra/newview/llviewermessage.cpp | 30 +++----- indra/newview/llviewerobject.cpp | 11 --- indra/newview/llviewerobjectlist.cpp | 26 +++---- indra/newview/llviewerparcelmgr.cpp | 5 -- indra/newview/llviewerregion.cpp | 35 +++------ indra/newview/llviewerstats.cpp | 2 +- indra/newview/llviewertexture.cpp | 100 ++++++++++++------------ indra/newview/llviewertexturelist.cpp | 15 +--- indra/newview/llviewerwindow.cpp | 56 +++++--------- indra/newview/llvoavatar.cpp | 55 +------------ indra/newview/llvoavatarself.cpp | 4 - indra/newview/llworld.cpp | 10 +-- indra/newview/pipeline.cpp | 4 - 30 files changed, 305 insertions(+), 495 deletions(-) (limited to 'indra/newview') diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 6ea63809f8..c86c89fa9b 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -57,9 +57,12 @@ BOOL gDebugSession = FALSE; BOOL gDebugGL = FALSE; BOOL gClothRipple = FALSE; -BOOL gNoRender = FALSE; +BOOL gHeadlessClient = FALSE; BOOL gGLActive = FALSE; +static const std::string HEADLESS_VENDOR_STRING("Linden Lab"); +static const std::string HEADLESS_RENDERER_STRING("Headless"); +static const std::string HEADLESS_VERSION_STRING("1.0"); std::ofstream gFailLog; @@ -538,9 +541,19 @@ void LLGLManager::setToDebugGPU() void LLGLManager::getGLInfo(LLSD& info) { - info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); - info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER)); - info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION)); + if (gHeadlessClient) + { + info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING; + info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING; + info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING; + return; + } + else + { + info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); + info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER)); + info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION)); + } #if !LL_MESA_HEADLESS std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts); @@ -556,14 +569,22 @@ void LLGLManager::getGLInfo(LLSD& info) std::string LLGLManager::getGLInfoString() { std::string info_str; - std::string all_exts, line; - info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n"); - info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n"); - info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); + if (gHeadlessClient) + { + info_str += std::string("GL_VENDOR ") + HEADLESS_VENDOR_STRING + std::string("\n"); + info_str += std::string("GL_RENDERER ") + HEADLESS_RENDERER_STRING + std::string("\n"); + info_str += std::string("GL_VERSION ") + HEADLESS_VERSION_STRING + std::string("\n"); + } + else + { + info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n"); + info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n"); + info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); + } #if !LL_MESA_HEADLESS - all_exts = (const char *)gGLHExts.mSysExts; + std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); LLStringUtil::replaceChar(all_exts, ' ', '\n'); info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n"); #endif @@ -573,15 +594,21 @@ std::string LLGLManager::getGLInfoString() void LLGLManager::printGLInfoString() { - std::string info_str; - std::string all_exts, line; - - LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL; - LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL; - LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL; + if (gHeadlessClient) + { + LL_INFOS("RenderInit") << "GL_VENDOR: " << HEADLESS_VENDOR_STRING << LL_ENDL; + LL_INFOS("RenderInit") << "GL_RENDERER: " << HEADLESS_RENDERER_STRING << LL_ENDL; + LL_INFOS("RenderInit") << "GL_VERSION: " << HEADLESS_VERSION_STRING << LL_ENDL; + } + else + { + LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL; + } #if !LL_MESA_HEADLESS - all_exts = std::string(gGLHExts.mSysExts); + std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); LLStringUtil::replaceChar(all_exts, ' ', '\n'); LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL; #endif @@ -590,7 +617,14 @@ void LLGLManager::printGLInfoString() std::string LLGLManager::getRawGLString() { std::string gl_string; - gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER)); + if (gHeadlessClient) + { + gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING; + } + else + { + gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER)); + } return gl_string; } @@ -614,47 +648,47 @@ void LLGLManager::initExtensions() mHasMultitexture = TRUE; # else mHasMultitexture = FALSE; -# endif +# endif // GL_ARB_multitexture # ifdef GL_ARB_texture_env_combine mHasARBEnvCombine = TRUE; # else mHasARBEnvCombine = FALSE; -# endif +# endif // GL_ARB_texture_env_combine # ifdef GL_ARB_texture_compression mHasCompressedTextures = TRUE; # else mHasCompressedTextures = FALSE; -# endif +# endif // GL_ARB_texture_compression # ifdef GL_ARB_vertex_buffer_object mHasVertexBufferObject = TRUE; # else mHasVertexBufferObject = FALSE; -# endif +# endif // GL_ARB_vertex_buffer_object # ifdef GL_EXT_framebuffer_object mHasFramebufferObject = TRUE; # else mHasFramebufferObject = FALSE; -# endif +# endif // GL_EXT_framebuffer_object # ifdef GL_EXT_framebuffer_multisample mHasFramebufferMultisample = TRUE; # else mHasFramebufferMultisample = FALSE; -# endif +# endif // GL_EXT_framebuffer_multisample # ifdef GL_ARB_draw_buffers mHasDrawBuffers = TRUE; #else mHasDrawBuffers = FALSE; -# endif +# endif // GL_ARB_draw_buffers # if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp) mHasDepthClamp = TRUE; #else mHasDepthClamp = FALSE; -#endif +#endif // defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp) # if GL_EXT_blend_func_separate mHasBlendFuncSeparate = TRUE; #else mHasBlendFuncSeparate = FALSE; -# endif +# endif // GL_EXT_blend_func_separate mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -1145,7 +1179,7 @@ void assert_glerror() } } - if (!gNoRender && gDebugGL) + if (gDebugGL) { do_assert_glerror(); } diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 85fab7a0f8..684fd50883 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -415,7 +415,7 @@ void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ); extern BOOL gClothRipple; -extern BOOL gNoRender; +extern BOOL gHeadlessClient; extern BOOL gGLActive; #endif // LL_LLGL_H diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index e8e98211f1..d4ffd6f88e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -967,12 +967,14 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 } if (mTexName == 0) { - llwarns << "Setting subimage on image without GL texture" << llendl; + // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 + //llwarns << "Setting subimage on image without GL texture" << llendl; return FALSE; } if (datap == NULL) { - llwarns << "Setting subimage on image with NULL datap" << llendl; + // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 + //llwarns << "Setting subimage on image with NULL datap" << llendl; return FALSE; } @@ -1100,6 +1102,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt //the texture is assiciate with some image by calling glTexImage outside LLImageGL BOOL LLImageGL::createGLTexture() { + if (gHeadlessClient) return FALSE; if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; @@ -1128,6 +1131,7 @@ BOOL LLImageGL::createGLTexture() BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) { + if (gHeadlessClient) return FALSE; if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index 35398f1c09..2e811ab23f 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -28,6 +28,7 @@ #include "indra_constants.h" #include "llwindowheadless.h" +#include "llgl.h" // // LLWindowHeadless diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ced46c7294..603fddbccd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2612,10 +2612,10 @@ Value 0 - DisableRendering + HeadlessClient Comment - Disable GL rendering and GUI (load testing) + Run in headless mode by disabling GL rendering, keyboard, etc Persist 1 Type diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 7d908df5ce..7d491a7774 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1119,12 +1119,6 @@ void LLAgent::resetControlFlags() //----------------------------------------------------------------------------- void LLAgent::setAFK() { - // Drones can't go AFK - if (gNoRender) - { - return; - } - if (!gAgent.getRegion()) { // Don't set AFK if we're not talking to a region yet. @@ -1684,11 +1678,6 @@ void LLAgent::clearRenderState(U8 clearstate) //----------------------------------------------------------------------------- U8 LLAgent::getRenderState() { - if (gNoRender || gKeyboard == NULL) - { - return 0; - } - // *FIX: don't do stuff in a getter! This is infinite loop city! if ((mTypingTimer.getElapsedTimeF32() > TYPING_TIMEOUT_SECS) && (mRenderState & AGENT_STATE_TYPING)) diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index f01d5ff1f5..6c5c3bcdab 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -282,25 +282,22 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) gAgent.stopAutoPilot(TRUE); } - if (!gNoRender) - { - LLSelectMgr::getInstance()->unhighlightAll(); + LLSelectMgr::getInstance()->unhighlightAll(); - // By popular request, keep land selection while walking around. JC - // LLViewerParcelMgr::getInstance()->deselectLand(); + // By popular request, keep land selection while walking around. JC + // LLViewerParcelMgr::getInstance()->deselectLand(); - // force deselect when walking and attachment is selected - // this is so people don't wig out when their avatar moves without animating - if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) - { - LLSelectMgr::getInstance()->deselectAll(); - } + // force deselect when walking and attachment is selected + // this is so people don't wig out when their avatar moves without animating + if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) + { + LLSelectMgr::getInstance()->deselectAll(); + } - if (gMenuHolder != NULL) - { - // Hide all popup menus - gMenuHolder->hideMenus(); - } + if (gMenuHolder != NULL) + { + // Hide all popup menus + gMenuHolder->hideMenus(); } if (change_camera && !gSavedSettings.getBOOL("FreezeTime")) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6a9dfaf21b..25bdaed0c9 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -881,7 +881,7 @@ bool LLAppViewer::init() } // If we don't have the right GL requirements, exit. - if (!gGLManager.mHasRequirements && !gNoRender) + if (!gGLManager.mHasRequirements) { // can't use an alert here since we're exiting and // all hell breaks lose. @@ -1171,7 +1171,8 @@ bool LLAppViewer::mainLoop() } // Render scene. - if (!LLApp::isExiting()) + // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 + if (!LLApp::isExiting() && !gHeadlessClient) { pingMainloopTimeout("Main:Display"); gGLActive = TRUE; @@ -1199,8 +1200,7 @@ bool LLAppViewer::mainLoop() } // yield cooperatively when not running as foreground window - if ( gNoRender - || (gViewerWindow && !gViewerWindow->mWindow->getVisible()) + if ( (gViewerWindow && !gViewerWindow->mWindow->getVisible()) || !gFocusMgr.getAppHasFocus()) { // Sleep if we're not rendering, or the window is minimized. @@ -2640,7 +2640,8 @@ bool LLAppViewer::initWindow() LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; // store setting in a global for easy access and modification - gNoRender = gSavedSettings.getBOOL("DisableRendering"); + gHeadlessClient = gSavedSettings.getBOOL("DisableRendering") + || gSavedSettings.getBOOL("HeadlessClient"); // always start windowed BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); @@ -2676,28 +2677,25 @@ bool LLAppViewer::initWindow() gViewerWindow->mWindow->maximize(); } - if (!gNoRender) + // + // Initialize GL stuff + // + + if (mForceGraphicsDetail) { - // - // Initialize GL stuff - // + LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false); + } + + // Set this flag in case we crash while initializing GL + gSavedSettings.setBOOL("RenderInitError", TRUE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - if (mForceGraphicsDetail) - { - LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false); - } - - // Set this flag in case we crash while initializing GL - gSavedSettings.setBOOL("RenderInitError", TRUE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - - gPipeline.init(); - stop_glerror(); - gViewerWindow->initGLDefaults(); + gPipeline.init(); + 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) @@ -2739,12 +2737,9 @@ void LLAppViewer::cleanupSavedSettings() gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); - if (!gNoRender) + if (gDebugView) { - if (gDebugView) - { - gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); - } + gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); } // save window position if not maximized @@ -3711,7 +3706,7 @@ void LLAppViewer::badNetworkHandler() // is destroyed. void LLAppViewer::saveFinalSnapshot() { - if (!mSavedFinalSnapshot && !gNoRender) + if (!mSavedFinalSnapshot) { gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); @@ -4115,34 +4110,31 @@ void LLAppViewer::idle() // // Update weather effects // - if (!gNoRender) - { - LLWorld::getInstance()->updateClouds(gFrameDTClamped); - gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets + LLWorld::getInstance()->updateClouds(gFrameDTClamped); + gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets - // Update wind vector - LLVector3 wind_position_region; - static LLVector3 average_wind; + // 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); + 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(); - F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region); - - gSky.setCloudDensityAtAgent(cloud_density); - gSky.setWind(average_wind); - //LLVOWater::setWind(average_wind); - } - else - { - gWindVec.setVec(0.0f, 0.0f, 0.0f); - } + // Compute average wind and use to drive motion of water + + average_wind = regionp->mWind.getAverage(); + F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region); + + gSky.setCloudDensityAtAgent(cloud_density); + gSky.setWind(average_wind); + //LLVOWater::setWind(average_wind); + } + else + { + gWindVec.setVec(0.0f, 0.0f, 0.0f); } ////////////////////////////////////// @@ -4151,13 +4143,10 @@ void LLAppViewer::idle() // Here, particles are updated and drawables are moved. // - if (!gNoRender) - { - LLFastTimer t(FTM_WORLD_UPDATE); - gPipeline.updateMove(); + LLFastTimer t(FTM_WORLD_UPDATE); + gPipeline.updateMove(); - LLWorld::getInstance()->updateParticles(); - } + LLWorld::getInstance()->updateParticles(); if (LLViewerJoystick::getInstance()->getOverrideCamera()) { @@ -4523,12 +4512,9 @@ void LLAppViewer::disconnectViewer() gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); // Un-minimize all windows so they don't get saved minimized - if (!gNoRender) + if (gFloaterView) { - if (gFloaterView) - { - gFloaterView->restoreAll(); - } + gFloaterView->restoreAll(); } if (LLSelectMgr::getInstance()) diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 61cf4dad93..eeb81085bb 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -38,13 +38,11 @@ ///---------------------------------------------------------------------------- /// Class LLFloaterBump ///---------------------------------------------------------------------------- -extern BOOL gNoRender; // Default constructor LLFloaterBump::LLFloaterBump(const LLSD& key) : LLFloater(key) { - if(gNoRender) return; } diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index 8cf7d23f88..72f64752d6 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -587,11 +587,6 @@ void LLHUDEffectLookAt::update() */ bool LLHUDEffectLookAt::calcTargetPosition() { - if (gNoRender) - { - return false; - } - LLViewerObject *target_obj = (LLViewerObject *)mTargetObject; LLVector3 local_offset; diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index 5f3178b955..8f14b53db0 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -38,8 +38,6 @@ #include "llviewercontrol.h" #include "llviewerobjectlist.h" -extern BOOL gNoRender; - // These are loaded from saved settings. LLColor4 LLHUDManager::sParentColor; LLColor4 LLHUDManager::sChildColor; @@ -150,11 +148,6 @@ LLHUDEffect *LLHUDManager::createViewerEffect(const U8 type, BOOL send_to_sim, B //static void LLHUDManager::processViewerEffect(LLMessageSystem *mesgsys, void **user_data) { - if (gNoRender) - { - return; - } - LLHUDEffect *effectp = NULL; LLUUID effect_id; U8 effect_type = 0; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 9623554200..060ad17c02 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3174,10 +3174,6 @@ public: //just like a normal IM //this is just replicated code from process_improved_im //and should really go in it's own function -jwolk - if (gNoRender) - { - return; - } LLChat chat; std::string message = message_params["message"].asString(); @@ -3254,11 +3250,6 @@ public: } //end if invitation has instant message else if ( input["body"].has("voice") ) { - if (gNoRender) - { - return; - } - if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking()) { // Don't display voice invites unless the user has voice enabled. diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index da891d1c51..81f4dd802a 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -516,17 +516,15 @@ BOOL LLSelectMgr::removeObjectFromSelections(const LLUUID &id) { BOOL object_found = FALSE; LLTool *tool = NULL; - if (!gNoRender) - { - tool = LLToolMgr::getInstance()->getCurrentTool(); - // It's possible that the tool is editing an object that is not selected - LLViewerObject* tool_editing_object = tool->getEditingObject(); - if( tool_editing_object && tool_editing_object->mID == id) - { - tool->stopEditing(); - object_found = TRUE; - } + tool = LLToolMgr::getInstance()->getCurrentTool(); + + // It's possible that the tool is editing an object that is not selected + LLViewerObject* tool_editing_object = tool->getEditingObject(); + if( tool_editing_object && tool_editing_object->mID == id) + { + tool->stopEditing(); + object_found = TRUE; } // Iterate through selected objects list and kill the object diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0eac7d5e2a..34a79bcde3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -354,11 +354,8 @@ bool idle_startup() LLStringUtil::setLocale (LLTrans::getString(system)); - if (!gNoRender) - { - //note: Removing this line will cause incorrect button size in the login screen. -- bao. - gTextureList.updateImages(0.01f) ; - } + //note: Removing this line will cause incorrect button size in the login screen. -- bao. + gTextureList.updateImages(0.01f) ; if ( STATE_FIRST == LLStartUp::getStartupState() ) { @@ -673,6 +670,7 @@ bool idle_startup() { gUserCredential = gLoginHandler.initializeLoginInfo(); } + // Previous initialĂzeLoginInfo may have generated user credentials. Re-check them. if (gUserCredential.isNull()) { show_connect_box = TRUE; @@ -731,9 +729,9 @@ bool idle_startup() { gUserCredential = gLoginHandler.initializeLoginInfo(); } - if (gNoRender) + if (gHeadlessClient) { - LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL; + LL_WARNS("AppInit") << "Waiting at connection box in headless client. Did you mean to add autologin params?" << LL_ENDL; } // Make sure the process dialog doesn't hide things gViewerWindow->setShowProgress(FALSE); @@ -941,10 +939,7 @@ bool idle_startup() gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - if (!gNoRender) - { - init_start_screen(agent_location_id); - } + init_start_screen(agent_location_id); // Display the startup progress bar. gViewerWindow->setShowProgress(TRUE); @@ -975,11 +970,6 @@ bool idle_startup() // Setting initial values... LLLoginInstance* login = LLLoginInstance::getInstance(); login->setNotificationsInterface(LLNotifications::getInstance()); - if(gNoRender) - { - // HACK, skip optional updates if you're running drones - login->setSkipOptionalUpdate(true); - } login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); login->setLastExecEvent(gLastExecEvent); @@ -1265,14 +1255,11 @@ bool idle_startup() gLoginMenuBarView->setVisible( FALSE ); gLoginMenuBarView->setEnabled( FALSE ); - if (!gNoRender) - { - // direct logging to the debug console's line buffer - LLError::logToFixedBuffer(gDebugView->mDebugConsolep); - - // set initial visibility of debug console - gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); - } + // direct logging to the debug console's line buffer + LLError::logToFixedBuffer(gDebugView->mDebugConsolep); + + // set initial visibility of debug console + gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); // // Set message handlers @@ -1300,7 +1287,7 @@ bool idle_startup() //gCacheName is required for nearby chat history loading //so I just moved nearby history loading a few states further - if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory")) + if (gSavedPerAccountSettings.getBOOL("LogShowHistory")) { LLNearbyChat* nearby_chat = LLNearbyChat::getInstance(); if (nearby_chat) nearby_chat->loadHistory(); @@ -1352,18 +1339,15 @@ bool idle_startup() gAgentCamera.resetCamera(); // Initialize global class data needed for surfaces (i.e. textures) - if (!gNoRender) - { - 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(); - LLGLState::checkTextureChannels(); + 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(); + LLGLState::checkTextureChannels(); - gSky.init(initial_sun_direction); + gSky.init(initial_sun_direction); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - } + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; // For all images pre-loaded into viewer cache, decode them. @@ -1726,46 +1710,43 @@ bool idle_startup() LLUIColorTable::instance().saveUserSettings(); }; - if (!gNoRender) - { - // JC: Initializing audio requests many sounds for download. - init_audio(); - - // 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()) + // JC: Initializing audio requests many sounds for download. + init_audio(); + + // 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) { - 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 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); - } + 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(); } + // no need to add gesture to inventory observer, it's already made in constructor + LLGestureMgr::instance().setFetchIDs(item_ids); + LLGestureMgr::instance().startFetch(); } gDisplaySwapBuffers = TRUE; @@ -1786,13 +1767,6 @@ bool idle_startup() // JC - 7/20/2002 gViewerWindow->sendShapeToSim(); - - // Ignore stipend information for now. Money history is on the web site. - // if needed, show the L$ history window - //if (stipend_since_login && !gNoRender) - //{ - //} - // 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 @@ -3218,7 +3192,7 @@ bool process_login_success_response() void transition_back_to_login_panel(const std::string& emsg) { - if (gNoRender) + if (gHeadlessClient && gSavedSettings.getBOOL("AutoLogin")) { LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL; LL_WARNS("AppInit") << emsg << LL_ENDL; diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 6fc8153b77..bccabe21a8 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -340,11 +340,6 @@ void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction) S32 i; LLSurfacePatch *patchp, *neighbor_patchp; - if (gNoRender) - { - return; - } - mNeighbors[direction] = neighborp; neighborp->mNeighbors[gDirOpposite[direction]] = this; diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp index dd35d5cf83..f820ae65df 100644 --- a/indra/newview/lltexturestats.cpp +++ b/indra/newview/lltexturestats.cpp @@ -37,7 +37,7 @@ void send_texture_stats_to_sim(const LLSD &texture_stats) { LLSD texture_stats_report; // Only send stats if the agent is connected to a region. - if (!gAgent.getRegion() || gNoRender) + if (!gAgent.getRegion()) { return; } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index ddb11829df..3e13537113 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -115,8 +115,7 @@ void display_startup() { if ( !gViewerWindow->getActive() || !gViewerWindow->mWindow->getVisible() - || gViewerWindow->mWindow->getMinimized() - || gNoRender ) + || gViewerWindow->mWindow->getMinimized() ) { return; } @@ -294,7 +293,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // Logic for forcing window updates if we're in drone mode. // - if (gNoRender) + // *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18 + if (gHeadlessClient) { #if LL_WINDOWS static F32 last_update_time = 0.f; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6fc85a3944..7e8fbf7345 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -343,12 +343,6 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) { LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); - if (!regionp || gNoRender) - { - return; - } - - S32 size; S8 type; @@ -2163,10 +2157,6 @@ void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string m void process_improved_im(LLMessageSystem *msg, void **user_data) { - if (gNoRender) - { - return; - } LLUUID from_id; BOOL from_group; LLUUID to_id; @@ -3936,7 +3926,14 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't // trigger a control event. U32 control_flags = gAgent.getControlFlags(); - MASK key_mask = gKeyboard->currentMask(TRUE); + + MASK key_mask = MASK_NONE; + // *TODO: Create a headless gKeyboard DK 2011-02-18 + if (gKeyboard) + { + key_mask = gKeyboard->currentMask(TRUE); + } + if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) { control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | @@ -4255,7 +4252,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) gSky.setSunPhase(phase); gSky.setSunTargetDirection(sun_direction, sun_ang_velocity); - if (!gNoRender && !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun())) + if ( !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()) ) { gSky.setSunDirection(sun_direction, sun_ang_velocity); } @@ -5517,21 +5514,12 @@ time_t gLastDisplayedTime = 0; void handle_show_mean_events(void *) { - if (gNoRender) - { - return; - } LLFloaterReg::showInstance("bumps"); //LLFloaterBump::showInstance(); } void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group) { - if (gNoRender) - { - return; - } - static const U32 max_collision_list_size = 20; if (gMeanCollisionList.size() > max_collision_list_size) { diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 090d3cadd4..c60bdf31c9 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -469,11 +469,6 @@ void LLViewerObject::initVOClasses() // Initialized shared class stuff first. LLVOAvatar::initClass(); LLVOTree::initClass(); - if (gNoRender) - { - // Don't init anything else in drone mode - return; - } llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl; LLVOGrass::initClass(); LLVOWater::initClass(); @@ -2151,12 +2146,6 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) } } - if (gNoRender) - { - // Skip drawable stuff if not rendering. - return TRUE; - } - updateDrawable(FALSE); return TRUE; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 970cc2e2a7..d112b3490e 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -636,19 +636,16 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) } - if (!gNoRender) + // Slam priorities for textures that we care about (hovered, selected, and focused) + // Hovered + // Assumes only one level deep of parenting + LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); + if (nodep) { - // Slam priorities for textures that we care about (hovered, selected, and focused) - // Hovered - // Assumes only one level deep of parenting - LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); - if (nodep) + objectp = nodep->getObject(); + if (objectp) { - objectp = nodep->getObject(); - if (objectp) - { - objectp->boostTexturePriority(); - } + objectp->boostTexturePriority(); } } @@ -1099,7 +1096,7 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) // We need to update many object caches, I'll document this more as I dig through the code // cleaning things out... - if (gNoRender || 0 == offset.magVecSquared()) + if (0 == offset.magVecSquared()) { return; } @@ -1505,11 +1502,6 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) { - if (gNoRender) - { - return; - } - if (objectp->isDead()) { llwarns << "Trying to find orphans for dead obj " << objectp->mID diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index fccd1156d3..e84e4a859a 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1383,11 +1383,6 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) // static void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user) { - if (gNoRender) - { - return; - } - // Extract the packed overlay information S32 packed_overlay_size = msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_Data); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 23b7b921b8..8e0373c79e 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -72,8 +72,6 @@ #pragma warning(disable:4355) #endif -extern BOOL gNoRender; - const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; @@ -234,28 +232,19 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, updateRenderMatrix(); mLandp = new LLSurface('l', NULL); - if (!gNoRender) - { - // Create the composition layer for the surface - mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge); - mCompositionp->setSurface(mLandp); - - // Create the surfaces - mLandp->setRegion(this); - mLandp->create(grids_per_region_edge, - grids_per_patch_edge, - mOriginGlobal, - mWidth); - } - if (!gNoRender) - { - mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); - } - else - { - mParcelOverlay = NULL; - } + // Create the composition layer for the surface + mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge); + mCompositionp->setSurface(mLandp); + + // Create the surfaces + mLandp->setRegion(this); + mLandp->create(grids_per_region_edge, + grids_per_patch_edge, + mOriginGlobal, + mWidth); + + mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); setOriginGlobal(from_region_handle(handle)); calculateCenterGlobal(); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 546ee9a334..e29370dfa4 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -711,7 +711,7 @@ void send_stats() // but that day is not today. // Only send stats if the agent is connected to a region. - if (!gAgent.getRegion() || gNoRender) + if (!gAgent.getRegion()) { return; } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index cd16b15e3e..16e73da79b 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1415,61 +1415,59 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) // mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) // << mID.getString() << llendl; BOOL res = TRUE; - if (!gNoRender) - { - // store original size only for locally-sourced images - if (mUrl.compare(0, 7, "file://") == 0) - { - mOrigWidth = mRawImage->getWidth(); - mOrigHeight = mRawImage->getHeight(); - // leave black border, do not scale image content - mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); - - mFullWidth = mRawImage->getWidth(); - mFullHeight = mRawImage->getHeight(); - setTexelsPerImage(); - } - else - { - mOrigWidth = mFullWidth; - mOrigHeight = mFullHeight; - } + // store original size only for locally-sourced images + if (mUrl.compare(0, 7, "file://") == 0) + { + mOrigWidth = mRawImage->getWidth(); + mOrigHeight = mRawImage->getHeight(); - bool size_okay = true; + // leave black border, do not scale image content + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); - U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel; - U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel; - if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) - { - llinfos << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << llendl; - size_okay = false; - } - - if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) - { - // A non power-of-two image was uploaded (through a non standard client) - llinfos << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << llendl; - size_okay = false; - } - - if( !size_okay ) - { - // An inappropriately-sized image was uploaded (through a non standard client) - // We treat these images as missing assets which causes them to - // be renderd as 'missing image' and to stop requesting data - setIsMissingAsset(); - destroyRawImage(); - return FALSE; - } - - if(!(res = insertToAtlas())) - { - res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); - resetFaceAtlas() ; - } - setActive() ; + mFullWidth = mRawImage->getWidth(); + mFullHeight = mRawImage->getHeight(); + setTexelsPerImage(); + } + else + { + mOrigWidth = mFullWidth; + mOrigHeight = mFullHeight; + } + + bool size_okay = true; + + U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel; + U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel; + if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) + { + llinfos << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << llendl; + size_okay = false; + } + + if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) + { + // A non power-of-two image was uploaded (through a non standard client) + llinfos << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << llendl; + size_okay = false; + } + + if( !size_okay ) + { + // An inappropriately-sized image was uploaded (through a non standard client) + // We treat these images as missing assets which causes them to + // be renderd as 'missing image' and to stop requesting data + setIsMissingAsset(); + destroyRawImage(); + return FALSE; + } + + if(!(res = insertToAtlas())) + { + res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); + resetFaceAtlas() ; } + setActive() ; if (!mForceToSaveRawImage) { diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 10126219f8..06f6ff23c2 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -91,11 +91,6 @@ void LLViewerTextureList::init() sNumImages = 0; mMaxResidentTexMemInMegaBytes = 0; mMaxTotalTextureMemInMegaBytes = 0 ; - if (gNoRender) - { - // Don't initialize GL stuff if we're not rendering. - return; - } mUpdateStats = TRUE; @@ -345,13 +340,6 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& LLGLenum primary_format, const LLUUID& force_id) { - if (gNoRender) - { - // Never mind that this ignores image_set_id; - // getImage() will handle that later. - return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLViewerTexture::BOOST_UI); - } - // generate UUID based on hash of filename LLUUID new_id; if (force_id.notNull()) @@ -741,7 +729,7 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create Images"); F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) { - if (gNoRender || gGLManager.mIsDisabled) return 0.0f; + if (gGLManager.mIsDisabled) return 0.0f; // // Create GL textures for all textures that need them (images which have been @@ -876,7 +864,6 @@ void LLViewerTextureList::updateImagesUpdateStats() void LLViewerTextureList::decodeAllImages(F32 max_time) { LLTimer timer; - if(gNoRender) return; // Update texture stats and priorities std::vector > image_list; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 166b110412..435da72622 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1225,8 +1225,9 @@ void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item) BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height) { + // *TODO: Enable similar information output for other platforms? DK 2011-02-18 #if LL_WINDOWS - if (gNoRender) + if (gHeadlessClient) { HWND window_handle = (HWND)window->getPlatformWindow(); PAINTSTRUCT ps; @@ -1256,7 +1257,7 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S len = temp_str.length(); TextOutA(hdc, 0, 25, temp_str.c_str(), len); - TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61); + TextOutA(hdc, 0, 50, "Set \"HeadlessClient FALSE\" in settings.ini file to reenable", 61); EndPaint(window_handle, &ps); return TRUE; } @@ -1404,9 +1405,9 @@ LLViewerWindow::LLViewerWindow( mWindow = LLWindowManager::createWindow(this, title, name, x, y, width, height, 0, fullscreen, - gNoRender, + gHeadlessClient, gSavedSettings.getBOOL("DisableVerticalSync"), - !gNoRender, + !gHeadlessClient, ignore_pixel_depth, gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled @@ -1862,11 +1863,8 @@ void LLViewerWindow::shutdownGL() LLVertexBuffer::cleanupClass(); llinfos << "Stopping GL during shutdown" << llendl; - if (!gNoRender) - { - stopGL(FALSE); - stop_glerror(); - } + stopGL(FALSE); + stop_glerror(); gGL.shutdown(); } @@ -1930,11 +1928,6 @@ void LLViewerWindow::reshape(S32 width, S32 height) // may have been destructed. if (!LLApp::isExiting()) { - if (gNoRender) - { - return; - } - gWindowResized = TRUE; // update our window rectangle @@ -2575,11 +2568,12 @@ void LLViewerWindow::updateUI() S32 x = mCurrentMousePoint.mX; S32 y = mCurrentMousePoint.mY; - MASK mask = gKeyboard->currentMask(TRUE); - if (gNoRender) + MASK mask = MASK_NONE; + // *TODO: Create a headless gKeyboard DK 2011-02-18 + if (gKeyboard) { - return; + mask = gKeyboard->currentMask(TRUE); } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) @@ -3410,11 +3404,6 @@ BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewe void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent) { - if (gNoRender) - { - return; - } - BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) { @@ -3450,11 +3439,6 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info) void LLViewerWindow::performPick() { - if (gNoRender) - { - return; - } - if (!mPicks.empty()) { std::vector::iterator pick_it; @@ -3486,11 +3470,6 @@ void LLViewerWindow::returnEmptyPicks() // Performs the GL object/land pick. LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent) { - if (gNoRender) - { - return LLPickInfo(); - } - BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) { @@ -3500,7 +3479,13 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans } // shortcut queueing in mPicks and just update mLastPick in place - mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL); + MASK key_mask = MASK_NONE; + // *TODO: Create a headless gKeyboard DK 2011-02-18 + if (gKeyboard) + { + key_mask = gKeyboard->currentMask(TRUE); + } + mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL); mLastPick.fetchResults(); return mLastPick; @@ -4774,12 +4759,9 @@ bool LLViewerWindow::onAlert(const LLSD& notify) { LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); - if (gNoRender) + if (gHeadlessClient) { llinfos << "Alert: " << notification->getName() << llendl; - notification->respond(LLSD::emptyMap()); - LLNotifications::instance().cancel(notification); - return false; } // If we're in mouselook, the mouse is hidden and so the user can't click diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fd89044995..26b595c923 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1295,18 +1295,8 @@ void LLVOAvatar::initInstance(void) } - if (gNoRender) - { - return; - } - buildCharacter(); - if (gNoRender) - { - return; - } - // preload specific motions here createMotion( ANIM_AGENT_CUSTOMIZE); createMotion( ANIM_AGENT_CUSTOMIZE_DONE); @@ -1747,12 +1737,6 @@ void LLVOAvatar::buildCharacter() BOOL status = loadAvatar(); stop_glerror(); - if (gNoRender) - { - // Still want to load the avatar skeleton so visual parameters work. - return; - } - // gPrintMessagesThisFrame = TRUE; lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; @@ -2223,7 +2207,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) setPixelAreaAndAngle(gAgent); // force asynchronous drawable update - if(mDrawable.notNull() && !gNoRender) + if(mDrawable.notNull()) { LLFastTimer t(FTM_JOINT_UPDATE); @@ -2280,11 +2264,6 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) LLVector3 root_pos_last = mRoot.getWorldPosition(); BOOL detailed_update = updateCharacter(agent); - if (gNoRender) - { - return TRUE; - } - static LLUICachedControl visualizers_in_calls("ShowVoiceVisualizersInCalls", false); bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && LLVoiceClient::getInstance()->getVoiceEnabled(mID); @@ -3257,17 +3236,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } } - if (gNoRender) - { - // Hack if we're running drones... - if (isSelf()) - { - gAgent.setPositionAgent(getPositionAgent()); - } - return FALSE; - } - - LLVector3d root_pos_global; if (!mIsBuilt) @@ -4194,7 +4162,7 @@ void LLVOAvatar::updateTextures() { BOOL render_avatar = TRUE; - if (mIsDummy || gNoRender) + if (mIsDummy) { return; } @@ -4468,11 +4436,6 @@ void LLVOAvatar::processAnimationStateChanges() { LLMemType mt(LLMemType::MTYPE_AVATAR); - if (gNoRender) - { - return; - } - if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) ) { startMotion(ANIM_AGENT_WALK_ADJUST); @@ -4867,7 +4830,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age LLVector3d z_vec(0.0f, 0.0f, 1.0f); LLVector3d p0_global, p1_global; - if (gNoRender || mIsDummy) + if (mIsDummy) { outNorm.setVec(z_vec); out_pos_agent = in_pos_agent; @@ -5439,11 +5402,6 @@ BOOL LLVOAvatar::loadLayersets() //----------------------------------------------------------------------------- void LLVOAvatar::updateVisualParams() { - if (gNoRender) - { - return; - } - setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); LLCharacter::updateVisualParams(); @@ -6174,8 +6132,6 @@ LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const void LLVOAvatar::updateMeshTextures() { // llinfos << "updateMeshTextures" << llendl; - if (gNoRender) return; - // if user has never specified a texture, assign the default for (U32 i=0; i < getNumTEs(); i++) { @@ -6831,11 +6787,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } } - if (gNoRender) - { - return; - } - ESex old_sex = getSex(); // llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 5f9e343907..c74b60f7e7 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2506,10 +2506,6 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const //------------------------------------------------------------------------ BOOL LLVOAvatarSelf::needsRenderBeam() { - if (gNoRender) - { - return FALSE; - } LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 399442e5c4..7f3a8deb47 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -98,11 +98,6 @@ LLWorld::LLWorld() : mEdgeWaterObjects[i] = NULL; } - if (gNoRender) - { - return; - } - LLPointer raw = new LLImageRaw(1,1,4); U8 *default_texture = raw->getData(); *(default_texture++) = MAX_WATER_COLOR.mV[0]; @@ -622,10 +617,7 @@ void LLWorld::updateVisibilities() if (LLViewerCamera::getInstance()->sphereInFrustum(regionp->getCenterAgent(), radius)) { regionp->calculateCameraDistance(); - if (!gNoRender) - { - regionp->getLand().updatePatchVisibilities(gAgent); - } + regionp->getLand().updatePatchVisibilities(gAgent); } else { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 59b526059b..b4ea455318 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1227,10 +1227,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) U32 LLPipeline::addObject(LLViewerObject *vobj) { LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT); - if (gNoRender) - { - return 0; - } if (gSavedSettings.getBOOL("RenderDelayCreation")) { -- cgit v1.3 From 3f5760b5ee4e422e11f3416133b7a4c3a73b1d8c Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 18 Feb 2011 23:53:38 +0000 Subject: More cleanup from self-reviewing headless client changes --- indra/llwindow/llwindowheadless.cpp | 1 - indra/newview/llappviewer.cpp | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index 2e811ab23f..35398f1c09 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -28,7 +28,6 @@ #include "indra_constants.h" #include "llwindowheadless.h" -#include "llgl.h" // // LLWindowHeadless diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 25bdaed0c9..0595d6f3c7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2640,8 +2640,7 @@ bool LLAppViewer::initWindow() LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; // store setting in a global for easy access and modification - gHeadlessClient = gSavedSettings.getBOOL("DisableRendering") - || gSavedSettings.getBOOL("HeadlessClient"); + gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); // always start windowed BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); -- cgit v1.3 From 96cac7c82fcb189a61d514a244b62970e943e4ad Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 18 Feb 2011 17:01:48 -0800 Subject: Fix up path resolution. --- indra/newview/lluilistener.cpp | 80 +++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 17 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index 22d3b8b219..d02d126cb5 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -32,6 +32,7 @@ #include "lluilistener.h" // STL headers // std headers +#include // external library headers // other Linden headers #include "llviewerwindow.h" // to get root view @@ -80,45 +81,90 @@ void LLUIListener::call(const LLSD& event) const } } +// Split string given a single character delimiter. +// Note that this returns empty strings for leading, trailing, and adjacent +// delimiters, such as "/foo/bar//baz/" -> ["", "foo", "bar", "", "baz", "" ] +std::vector split(const std::string& s, char delim) +{ + std::stringstream ss(s); + std::string item; + std::vector items; + while (std::getline(ss, item, delim)) + { + items.push_back(item); + } + return items; +} + +// Walk the LLView tree to resolve a path +// Paths can be discovered using Develop > XUI > Show XUI Paths +// +// A leading "/" indicates the root of the tree is the starting +// position of the search, (otherwise the context node is used) +// +// Adjacent "//" mean that the next level of the search is done +// recursively ("descendant" rather than "child"). +// +// Return values: If no match is found, NULL is returned, +// otherwise the matching LLView* is returned. +// +// Examples: +// +// "/" -> return the root view +// "/foo" -> find "foo" as a direct child of the root +// "foo" -> find "foo" as a direct child of the context node +// "//foo" -> find the first "foo" child anywhere in the tree +// "/foo/bar" -> find "foo" as direct child of the root, and +// "bar" as a direct child of "foo" +// "//foo//bar/baz" -> find the first "foo" anywhere in the +// tree, the first "bar" anywhere under it, and "baz" +// as a direct child of that +// const LLView* resolve_path(const LLView* context, const std::string path) { - std::vector parts; - const std::string delims("/"); - LLStringUtilBase::getTokens(path, parts, delims); + std::vector parts = split(path, '/'); + + if (parts.size() == 0) + { + return context; + } + + std::vector::iterator it = parts.begin(); + + // leading / means "start at root" + if ((*it).length() == 0) + { + context = (LLView*)(gViewerWindow->getRootView()); + it++; + } bool recurse = false; - for (std::vector::iterator it = parts.begin(); - it != parts.end() && context; it++) + for (; it != parts.end() && context; it++) { std::string part = *it; - + if (part.length() == 0) { - // Allow "foo//bar" meaning "descendant named bar" recurse = true; } else { const LLView* found = context->findChildView(part, recurse); if (!found) - { return NULL; - } - else - { - context = found; - } + + context = found; recurse = false; } } - return NULL; + return context; } void LLUIListener::getValue(const LLSD&event) const { - LLSD reply; - + LLSD reply = LLSD::emptyMap(); + const LLView* root = (LLView*)(gViewerWindow->getRootView()); const LLView* view = resolve_path(root, event["path"].asString()); const LLUICtrl* ctrl(dynamic_cast(view)); @@ -132,5 +178,5 @@ void LLUIListener::getValue(const LLSD&event) const // *TODO: ??? return something indicating failure to resolve } - sendReply(reply, event, "reply"); + sendReply(reply, event); } -- cgit v1.3 From b5e843abb59ac32cb8cd85dc4b1a43f2bb5c22ee Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Sat, 19 Feb 2011 02:21:51 +0000 Subject: Fix for more instances of dereferencing gKeyboard in headless client. --- indra/newview/llviewerwindow.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 336915ac8c..2d6fabf611 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2973,7 +2973,13 @@ void LLViewerWindow::updateLayout() } // Update the location of the blue box tool popup LLCoordGL select_center_screen; - gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) ); + MASK mask = MASK_NONE; + // *TODO: Create a headless gKeyboard DK 2011-02-18 + if (gKeyboard) + { + mask = gKeyboard->currentMask(TRUE); + } + gFloaterTools->updatePopup( select_center_screen, mask ); } else { @@ -3099,7 +3105,13 @@ void LLViewerWindow::updateKeyboardFocus() // sync all floaters with their focus state gFloaterView->highlightFocusedFloater(); gSnapshotFloaterView->highlightFocusedFloater(); - if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0) + MASK mask = MASK_NONE; + // *TODO: Create a headless gKeyboard DK 2011-02-18 + if (gKeyboard) + { + mask = gKeyboard->currentMask(TRUE); + } + if ((mask & MASK_CONTROL) == 0) { // control key no longer held down, finish cycle mode gFloaterView->setCycleMode(FALSE); -- cgit v1.3 From 2ebcf802cbec59b4d9fe404af5bd125818d4eefa Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 22 Feb 2011 13:28:48 -0700 Subject: set "RenderVBOMappingDisable" to be true by default to stop VBO memory leaking. --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 58abd4c091..a010524091 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8460,7 +8460,7 @@ Type Boolean Value - 0 + 1 RenderUseStreamVBO -- cgit v1.3 From 1362a3e117dadbc5b1de18487314d4af57ce850f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 22 Feb 2011 20:13:07 -0500 Subject: Move Josh's resolvePath() function to LLUI. Use boost::split_iterator to split LLView pathname on slashes. --- indra/llui/llui.cpp | 49 +++++++++++++++++++++++ indra/llui/llui.h | 27 +++++++++++++ indra/newview/lluilistener.cpp | 89 ++---------------------------------------- 3 files changed, 80 insertions(+), 85 deletions(-) (limited to 'indra/newview') diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index c300fe55d9..87669574c2 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -61,6 +61,8 @@ // for XUIParse #include "llquaternion.h" #include +#include +#include // // Globals @@ -2020,6 +2022,53 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE ); } +LLView* LLUI::resolvePath(LLView* context, const std::string& path) +{ + // Nothing about resolvePath() should require non-const LLView*. If caller + // wants non-const, call the const flavor and then cast away const-ness. + return const_cast(resolvePath(const_cast(context), path)); +} + +const LLView* LLUI::resolvePath(const LLView* context, const std::string& path) +{ + // Create an iterator over slash-separated parts of 'path'. Dereferencing + // this iterator returns an iterator_range over the substring. Unlike + // LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent + // delimiters: leading/trailing slash produces an empty substring, double + // slash produces an empty substring. That's what we need. + boost::split_iterator ti(path, boost::first_finder("/")), tend; + + if (ti == tend) + { + // 'path' is completely empty, no navigation + return context; + } + + // leading / means "start at root" + if (ti->empty()) + { + context = getRootView(); + ++ti; + } + + bool recurse = false; + for (; ti != tend && context; ++ti) + { + if (ti->empty()) + { + recurse = true; + } + else + { + std::string part(ti->begin(), ti->end()); + context = context->findChildView(part, recurse); + recurse = false; + } + } + + return context; +} + // LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 62d10df8b2..50cb9e6632 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -185,6 +185,33 @@ public: //helper functions (should probably move free standing rendering helper functions here) static LLView* getRootView() { return sRootView; } static void setRootView(LLView* view) { sRootView = view; } + /** + * Walk the LLView tree to resolve a path + * Paths can be discovered using Develop > XUI > Show XUI Paths + * + * A leading "/" indicates the root of the tree is the starting + * position of the search, (otherwise the context node is used) + * + * Adjacent "//" mean that the next level of the search is done + * recursively ("descendant" rather than "child"). + * + * Return values: If no match is found, NULL is returned, + * otherwise the matching LLView* is returned. + * + * Examples: + * + * "/" -> return the root view + * "/foo" -> find "foo" as a direct child of the root + * "foo" -> find "foo" as a direct child of the context node + * "//foo" -> find the first "foo" child anywhere in the tree + * "/foo/bar" -> find "foo" as direct child of the root, and + * "bar" as a direct child of "foo" + * "//foo//bar/baz" -> find the first "foo" anywhere in the + * tree, the first "bar" anywhere under it, and "baz" + * as a direct child of that + */ + static const LLView* resolvePath(const LLView* context, const std::string& path); + static LLView* resolvePath(LLView* context, const std::string& path); static std::string locateSkin(const std::string& filename); static void setMousePositionScreen(S32 x, S32 y); static void getMousePositionScreen(S32 *x, S32 *y); diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp index d02d126cb5..6b2cd71d40 100644 --- a/indra/newview/lluilistener.cpp +++ b/indra/newview/lluilistener.cpp @@ -32,10 +32,9 @@ #include "lluilistener.h" // STL headers // std headers -#include // external library headers // other Linden headers -#include "llviewerwindow.h" // to get root view +#include "llui.h" // getRootView(), resolvePath() #include "lluictrl.h" #include "llerror.h" @@ -55,7 +54,7 @@ LLUIListener::LLUIListener(): "For the UI control identified by the path in [\"path\"], return the control's\n" "current value as [\"value\"] reply.", &LLUIListener::getValue, - LLSD().with("path", LLSD())); + LLSDMap("path", LLSD())("reply", LLSD())); } void LLUIListener::call(const LLSD& event) const @@ -81,92 +80,12 @@ void LLUIListener::call(const LLSD& event) const } } -// Split string given a single character delimiter. -// Note that this returns empty strings for leading, trailing, and adjacent -// delimiters, such as "/foo/bar//baz/" -> ["", "foo", "bar", "", "baz", "" ] -std::vector split(const std::string& s, char delim) -{ - std::stringstream ss(s); - std::string item; - std::vector items; - while (std::getline(ss, item, delim)) - { - items.push_back(item); - } - return items; -} - -// Walk the LLView tree to resolve a path -// Paths can be discovered using Develop > XUI > Show XUI Paths -// -// A leading "/" indicates the root of the tree is the starting -// position of the search, (otherwise the context node is used) -// -// Adjacent "//" mean that the next level of the search is done -// recursively ("descendant" rather than "child"). -// -// Return values: If no match is found, NULL is returned, -// otherwise the matching LLView* is returned. -// -// Examples: -// -// "/" -> return the root view -// "/foo" -> find "foo" as a direct child of the root -// "foo" -> find "foo" as a direct child of the context node -// "//foo" -> find the first "foo" child anywhere in the tree -// "/foo/bar" -> find "foo" as direct child of the root, and -// "bar" as a direct child of "foo" -// "//foo//bar/baz" -> find the first "foo" anywhere in the -// tree, the first "bar" anywhere under it, and "baz" -// as a direct child of that -// -const LLView* resolve_path(const LLView* context, const std::string path) -{ - std::vector parts = split(path, '/'); - - if (parts.size() == 0) - { - return context; - } - - std::vector::iterator it = parts.begin(); - - // leading / means "start at root" - if ((*it).length() == 0) - { - context = (LLView*)(gViewerWindow->getRootView()); - it++; - } - - bool recurse = false; - for (; it != parts.end() && context; it++) - { - std::string part = *it; - - if (part.length() == 0) - { - recurse = true; - } - else - { - const LLView* found = context->findChildView(part, recurse); - if (!found) - return NULL; - - context = found; - recurse = false; - } - } - - return context; -} - void LLUIListener::getValue(const LLSD&event) const { LLSD reply = LLSD::emptyMap(); - const LLView* root = (LLView*)(gViewerWindow->getRootView()); - const LLView* view = resolve_path(root, event["path"].asString()); + const LLView* root = LLUI::getRootView(); + const LLView* view = LLUI::resolvePath(root, event["path"].asString()); const LLUICtrl* ctrl(dynamic_cast(view)); if (ctrl) -- cgit v1.3 From 28ef58285e95e3234d0faa5f230456ae47ecde13 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 23 Feb 2011 02:10:54 +0000 Subject: Comment fix from code review with brad --- indra/newview/llstartup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 34a79bcde3..49d4983294 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -670,7 +670,7 @@ bool idle_startup() { gUserCredential = gLoginHandler.initializeLoginInfo(); } - // Previous initialĂzeLoginInfo may have generated user credentials. Re-check them. + // Previous initializeLoginInfo may have generated user credentials. Re-check them. if (gUserCredential.isNull()) { show_connect_box = TRUE; -- cgit v1.3 From 0929315ab103433275a71f26a4900ee0615932e9 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 23 Feb 2011 05:40:08 +0000 Subject: Added headless client keyboard --- indra/llwindow/CMakeLists.txt | 2 ++ indra/llwindow/llkeyboardheadless.cpp | 50 +++++++++++++++++++++++++++++++++++ indra/llwindow/llkeyboardheadless.h | 45 +++++++++++++++++++++++++++++++ indra/llwindow/llwindowheadless.cpp | 4 +++ indra/newview/llviewermessage.cpp | 7 +---- indra/newview/llviewerwindow.cpp | 28 +++----------------- 6 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 indra/llwindow/llkeyboardheadless.cpp create mode 100644 indra/llwindow/llkeyboardheadless.h (limited to 'indra/newview') diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 00aaba2052..08ebaf7577 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -34,6 +34,7 @@ include_directories( set(llwindow_SOURCE_FILES llkeyboard.cpp + llkeyboardheadless.cpp llwindowheadless.cpp llwindowcallbacks.cpp llwindowlistener.cpp @@ -43,6 +44,7 @@ set(llwindow_HEADER_FILES CMakeLists.txt llkeyboard.h + llkeyboardheadless.h llwindowheadless.h llwindowcallbacks.h llwindowlistener.h diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp new file mode 100644 index 0000000000..4dfaaed4e1 --- /dev/null +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -0,0 +1,50 @@ +/** + * @file llkeyboardheadless.cpp + * @brief Handler for assignable key bindings + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llkeyboardheadless.h" +#include "llwindowcallbacks.h" + +LLKeyboardHeadless::LLKeyboardHeadless() +{ } + +void LLKeyboardHeadless::resetMaskKeys() +{ } + + +BOOL LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) +{ return FALSE; } + + +BOOL LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) +{ return FALSE; } + +MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event) +{ return MASK_NONE; } + +void LLKeyboardHeadless::scanKeyboard() +{ } + diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h new file mode 100644 index 0000000000..4e666f8ce8 --- /dev/null +++ b/indra/llwindow/llkeyboardheadless.h @@ -0,0 +1,45 @@ +/** + * @file llkeyboardheadless.h + * @brief Handler for assignable key bindings + * + * $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$ + */ + +#ifndef LL_LLKEYBOARDHEADLESS_H +#define LL_LLKEYBOARDHEADLESS_H + +#include "llkeyboard.h" + +class LLKeyboardHeadless : public LLKeyboard +{ +public: + LLKeyboardHeadless(); + /*virtual*/ ~LLKeyboardHeadless() {}; + + /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); + /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); + /*virtual*/ void resetMaskKeys(); + /*virtual*/ MASK currentMask(BOOL for_mouse_event); + /*virtual*/ void scanKeyboard(); +}; + +#endif diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index 35398f1c09..e6e6bc67ff 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -28,6 +28,7 @@ #include "indra_constants.h" #include "llwindowheadless.h" +#include "llkeyboardheadless.h" // // LLWindowHeadless @@ -37,6 +38,9 @@ LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::stri BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { + // Initialize a headless keyboard. + gKeyboard = new LLKeyboardHeadless(); + gKeyboard->setCallbacks(callbacks); } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 852911ceb7..3097e98509 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3935,12 +3935,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // trigger a control event. U32 control_flags = gAgent.getControlFlags(); - MASK key_mask = MASK_NONE; - // *TODO: Create a headless gKeyboard DK 2011-02-18 - if (gKeyboard) - { - key_mask = gKeyboard->currentMask(TRUE); - } + MASK key_mask = gKeyboard->currentMask(TRUE); if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 21e3626bf8..a5218786d8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2577,12 +2577,7 @@ void LLViewerWindow::updateUI() S32 x = mCurrentMousePoint.mX; S32 y = mCurrentMousePoint.mY; - MASK mask = MASK_NONE; - // *TODO: Create a headless gKeyboard DK 2011-02-18 - if (gKeyboard) - { - mask = gKeyboard->currentMask(TRUE); - } + MASK mask = gKeyboard->currentMask(TRUE); if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { @@ -2973,12 +2968,7 @@ void LLViewerWindow::updateLayout() } // Update the location of the blue box tool popup LLCoordGL select_center_screen; - MASK mask = MASK_NONE; - // *TODO: Create a headless gKeyboard DK 2011-02-18 - if (gKeyboard) - { - mask = gKeyboard->currentMask(TRUE); - } + MASK mask = gKeyboard->currentMask(TRUE); gFloaterTools->updatePopup( select_center_screen, mask ); } else @@ -3105,12 +3095,7 @@ void LLViewerWindow::updateKeyboardFocus() // sync all floaters with their focus state gFloaterView->highlightFocusedFloater(); gSnapshotFloaterView->highlightFocusedFloater(); - MASK mask = MASK_NONE; - // *TODO: Create a headless gKeyboard DK 2011-02-18 - if (gKeyboard) - { - mask = gKeyboard->currentMask(TRUE); - } + MASK mask = gKeyboard->currentMask(TRUE); if ((mask & MASK_CONTROL) == 0) { // control key no longer held down, finish cycle mode @@ -3499,12 +3484,7 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans } // shortcut queueing in mPicks and just update mLastPick in place - MASK key_mask = MASK_NONE; - // *TODO: Create a headless gKeyboard DK 2011-02-18 - if (gKeyboard) - { - key_mask = gKeyboard->currentMask(TRUE); - } + MASK key_mask = gKeyboard->currentMask(TRUE); mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL); mLastPick.fetchResults(); -- cgit v1.3