diff options
Diffstat (limited to 'indra')
145 files changed, 4916 insertions, 1371 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 8d4969a49e..d01e1869b6 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -22,7 +22,10 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") include(Variables) if (DARWIN) - cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR) + # 2.6.4 fixes a Mac bug in get_target_property(... "SLPlugin" LOCATION): + # before that version it returns "pathname/SLPlugin", whereas the correct + # answer is "pathname/SLPlugin.app/Contents/MacOS/SLPlugin". + cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR) endif (DARWIN) if (NOT CMAKE_BUILD_TYPE) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index a114d6e778..db2cdb5ff8 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -38,10 +38,10 @@ if (WINDOWS) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP" CACHE STRING "C++ compiler debug options" FORCE) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP" + "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Ob2" CACHE STRING "C++ compiler release-with-debug options" FORCE) set(CMAKE_CXX_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP" + "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /Ob2" CACHE STRING "C++ compiler release options" FORCE) set(CMAKE_CXX_STANDARD_LIBRARIES "") diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 79c3bb7da2..29e2492551 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -1,265 +1,273 @@ -# -*- cmake -*- -include(LLTestCommand) -include(GoogleMock) - -MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) - # Given a project name and a list of sourcefiles (with optional properties on each), - # add targets to build and run the tests specified. - # ASSUMPTIONS: - # * this macro is being executed in the project file that is passed in - # * current working SOURCE dir is that project dir - # * there is a subfolder tests/ with test code corresponding to the filenames passed in - # * properties for each sourcefile passed in indicate what libs to link that file with (MAKE NO ASSUMPTIONS ASIDE FROM TUT) - # - # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code - # - # WARNING: do NOT modify this code without working with poppy - - # there is another branch that will conflict heavily with any changes here. -INCLUDE(GoogleMock) - - - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}") - ENDIF(LL_TEST_VERBOSE) - - # Start with the header and project-wide setup before making targets - #project(UNITTEST_PROJECT_${project}) - # Setup includes, paths, etc - SET(alltest_SOURCE_FILES - ${CMAKE_SOURCE_DIR}/test/test.cpp - ${CMAKE_SOURCE_DIR}/test/lltut.cpp - ) - SET(alltest_DEP_TARGETS - # needed by the test harness itself - ${APRUTIL_LIBRARIES} - ${APR_LIBRARIES} - llcommon - ) - IF(NOT "${project}" STREQUAL "llmath") - # add llmath as a dep unless the tested module *is* llmath! - LIST(APPEND alltest_DEP_TARGETS - llmath - ) - ENDIF(NOT "${project}" STREQUAL "llmath") - SET(alltest_INCLUDE_DIRS - ${LLMATH_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LIBS_OPEN_DIR}/test - ${GOOGLEMOCK_INCLUDE_DIRS} - ) - SET(alltest_LIBRARIES - ${GOOGLEMOCK_LIBRARIES} - ${PTHREAD_LIBRARY} - ${WINDOWS_LIBRARIES} - ) - # Headers, for convenience in targets. - SET(alltest_HEADER_FILES - ${CMAKE_SOURCE_DIR}/test/test.h - ) - - # Use the default flags - if (LINUX) - SET(CMAKE_EXE_LINKER_FLAGS "") - endif (LINUX) - - # start the source test executable definitions - SET(${project}_TEST_OUTPUT "") - FOREACH (source ${sources}) - STRING( REGEX REPLACE "(.*)\\.[^.]+$" "\\1" name ${source} ) - STRING( REGEX REPLACE ".*\\.([^.]+)$" "\\1" extension ${source} ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} individual source: ${source} (${name}.${extension})") - ENDIF(LL_TEST_VERBOSE) - - # - # Per-codefile additional / external source, header, and include dir property extraction - # - # Source - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_SOURCE_FILES ${source} LL_TEST_ADDITIONAL_SOURCE_FILES) - IF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND) - SET(${name}_test_additional_SOURCE_FILES "") - ENDIF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND) - SET(${name}_test_SOURCE_FILES ${source} tests/${name}_test.${extension} ${alltest_SOURCE_FILES} ${${name}_test_additional_SOURCE_FILES} ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}") - ENDIF(LL_TEST_VERBOSE) - # Headers - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES) - IF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND) - SET(${name}_test_additional_HEADER_FILES "") - ENDIF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND) - SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES}) - set_source_files_properties(${${name}_test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) - LIST(APPEND ${name}_test_SOURCE_FILES ${${name}_test_HEADER_FILES}) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_HEADER_FILES ${${name}_test_HEADER_FILES}") - ENDIF(LL_TEST_VERBOSE) - # Include dirs - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS) - IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) - SET(${name}_test_additional_INCLUDE_DIRS "") - ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) - INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}") - ENDIF(LL_TEST_VERBOSE) - - - # Setup target - ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES}) - SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") - - # - # Per-codefile additional / external project dep and lib dep property extraction - # - # WARNING: it's REALLY IMPORTANT to not mix these. I guarantee it will not work in the future. + poppy 2009-04-19 - # Projects - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_PROJECTS ${source} LL_TEST_ADDITIONAL_PROJECTS) - IF(${name}_test_additional_PROJECTS MATCHES NOTFOUND) - SET(${name}_test_additional_PROJECTS "") - ENDIF(${name}_test_additional_PROJECTS MATCHES NOTFOUND) - # Libraries - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_LIBRARIES ${source} LL_TEST_ADDITIONAL_LIBRARIES) - IF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND) - SET(${name}_test_additional_LIBRARIES "") - ENDIF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_PROJECTS ${${name}_test_additional_PROJECTS}") - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_LIBRARIES ${${name}_test_additional_LIBRARIES}") - ENDIF(LL_TEST_VERBOSE) - # Add to project - TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} ) - - # - # Setup test targets - # - GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION) - SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt) - SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR}) - - # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19 - IF(LL_TEST_VERBOSE) - MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}") - ENDIF(LL_TEST_VERBOSE) - - SET_TEST_PATH(LD_LIBRARY_PATH) - LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${TEST_CMD}) - IF(LL_TEST_VERBOSE) - MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}") - ENDIF(LL_TEST_VERBOSE) - # Add test - ADD_CUSTOM_COMMAND( - OUTPUT ${TEST_OUTPUT} - COMMAND ${TEST_SCRIPT_CMD} - DEPENDS PROJECT_${project}_TEST_${name} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) - # Why not add custom target and add POST_BUILD command? - # Slightly less uncertain behavior - # (OUTPUT commands run non-deterministically AFAIK) + poppy 2009-04-19 - # > I did not use a post build step as I could not make it notify of a - # > failure after the first time you build and fail a test. - daveh 2009-04-20 - LIST(APPEND ${project}_TEST_OUTPUT ${TEST_OUTPUT}) - ENDFOREACH (source) - - # Add the test runner target per-project - # (replaces old _test_ok targets all over the place) - ADD_CUSTOM_TARGET(${project}_tests ALL DEPENDS ${${project}_TEST_OUTPUT}) - ADD_DEPENDENCIES(${project} ${project}_tests) -ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS) - -FUNCTION(LL_ADD_INTEGRATION_TEST - testname - additional_source_files - library_dependencies -# variable args - ) - if(TEST_DEBUG) - message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on") - endif(TEST_DEBUG) - - SET(source_files - tests/${testname}_test.cpp - ${CMAKE_SOURCE_DIR}/test/test.cpp - ${CMAKE_SOURCE_DIR}/test/lltut.cpp - ${additional_source_files} - ) - - SET(libraries - ${library_dependencies} - ${GOOGLEMOCK_LIBRARIES} - ${PTHREAD_LIBRARY} - ) - - # Add test executable build target - if(TEST_DEBUG) - message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})") - endif(TEST_DEBUG) - ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files}) - SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") - - # Add link deps to the executable - if(TEST_DEBUG) - message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})") - endif(TEST_DEBUG) - TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries}) - - # Create the test running command - SET(test_command ${ARGN}) - GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION) - LIST(FIND test_command "{}" test_exe_pos) - IF(test_exe_pos LESS 0) - # The {} marker means "the full pathname of the test executable." - # test_exe_pos -1 means we didn't find it -- so append the test executable - # name to $ARGN, the variable part of the arg list. This is convenient - # shorthand for both straightforward execution of the test program (empty - # $ARGN) and for running a "wrapper" program of some kind accepting the - # pathname of the test program as the last of its args. You need specify - # {} only if the test program's pathname isn't the last argument in the - # desired command line. - LIST(APPEND test_command "${TEST_EXE}") - ELSE (test_exe_pos LESS 0) - # Found {} marker at test_exe_pos. Remove the {}... - LIST(REMOVE_AT test_command test_exe_pos) - # ...and replace it with the actual name of the test executable. - LIST(INSERT test_command test_exe_pos "${TEST_EXE}") - ENDIF (test_exe_pos LESS 0) - - SET_TEST_PATH(LD_LIBRARY_PATH) - LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${test_command}) - - if(TEST_DEBUG) - message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}") - endif(TEST_DEBUG) - - ADD_CUSTOM_COMMAND( - TARGET INTEGRATION_TEST_${testname} - POST_BUILD - COMMAND ${TEST_SCRIPT_CMD} - ) - - # Use CTEST? Not sure how to yet... - # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD}) - -ENDFUNCTION(LL_ADD_INTEGRATION_TEST) - -MACRO(SET_TEST_PATH LISTVAR) - IF(WINDOWS) - # We typically build/package only Release variants of third-party - # libraries, so append the Release staging dir in case the library being - # sought doesn't have a debug variant. - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release) - ELSEIF(DARWIN) - # We typically build/package only Release variants of third-party - # libraries, so append the Release staging dir in case the library being - # sought doesn't have a debug variant. - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib) - ELSE(WINDOWS) - # Linux uses a single staging directory anyway. - IF (STANDALONE) - set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib) - ELSE (STANDALONE) - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib) - ENDIF (STANDALONE) - ENDIF(WINDOWS) -ENDMACRO(SET_TEST_PATH) +# -*- cmake -*-
+include(LLTestCommand)
+include(GoogleMock)
+
+MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
+ # Given a project name and a list of sourcefiles (with optional properties on each),
+ # add targets to build and run the tests specified.
+ # ASSUMPTIONS:
+ # * this macro is being executed in the project file that is passed in
+ # * current working SOURCE dir is that project dir
+ # * there is a subfolder tests/ with test code corresponding to the filenames passed in
+ # * properties for each sourcefile passed in indicate what libs to link that file with (MAKE NO ASSUMPTIONS ASIDE FROM TUT)
+ #
+ # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code
+ #
+ # WARNING: do NOT modify this code without working with poppy -
+ # there is another branch that will conflict heavily with any changes here.
+INCLUDE(GoogleMock)
+
+
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")
+ ENDIF(LL_TEST_VERBOSE)
+
+ # Start with the header and project-wide setup before making targets
+ #project(UNITTEST_PROJECT_${project})
+ # Setup includes, paths, etc
+ SET(alltest_SOURCE_FILES
+ ${CMAKE_SOURCE_DIR}/test/test.cpp
+ ${CMAKE_SOURCE_DIR}/test/lltut.cpp
+ )
+ SET(alltest_DEP_TARGETS
+ # needed by the test harness itself
+ ${APRUTIL_LIBRARIES}
+ ${APR_LIBRARIES}
+ llcommon
+ )
+ IF(NOT "${project}" STREQUAL "llmath")
+ # add llmath as a dep unless the tested module *is* llmath!
+ LIST(APPEND alltest_DEP_TARGETS
+ llmath
+ )
+ ENDIF(NOT "${project}" STREQUAL "llmath")
+ SET(alltest_INCLUDE_DIRS
+ ${LLMATH_INCLUDE_DIRS}
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LIBS_OPEN_DIR}/test
+ ${GOOGLEMOCK_INCLUDE_DIRS}
+ )
+ SET(alltest_LIBRARIES
+ ${GOOGLEMOCK_LIBRARIES}
+ ${PTHREAD_LIBRARY}
+ ${WINDOWS_LIBRARIES}
+ )
+ # Headers, for convenience in targets.
+ SET(alltest_HEADER_FILES
+ ${CMAKE_SOURCE_DIR}/test/test.h
+ )
+
+ # Use the default flags
+ if (LINUX)
+ SET(CMAKE_EXE_LINKER_FLAGS "")
+ endif (LINUX)
+
+ # start the source test executable definitions
+ SET(${project}_TEST_OUTPUT "")
+ FOREACH (source ${sources})
+ STRING( REGEX REPLACE "(.*)\\.[^.]+$" "\\1" name ${source} )
+ STRING( REGEX REPLACE ".*\\.([^.]+)$" "\\1" extension ${source} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} individual source: ${source} (${name}.${extension})")
+ ENDIF(LL_TEST_VERBOSE)
+
+ #
+ # Per-codefile additional / external source, header, and include dir property extraction
+ #
+ # Source
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_SOURCE_FILES ${source} LL_TEST_ADDITIONAL_SOURCE_FILES)
+ IF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND)
+ SET(${name}_test_additional_SOURCE_FILES "")
+ ENDIF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND)
+ SET(${name}_test_SOURCE_FILES ${source} tests/${name}_test.${extension} ${alltest_SOURCE_FILES} ${${name}_test_additional_SOURCE_FILES} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Headers
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES)
+ IF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND)
+ SET(${name}_test_additional_HEADER_FILES "")
+ ENDIF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND)
+ SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES})
+ set_source_files_properties(${${name}_test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)
+ LIST(APPEND ${name}_test_SOURCE_FILES ${${name}_test_HEADER_FILES})
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_HEADER_FILES ${${name}_test_HEADER_FILES}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Include dirs
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS)
+ IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
+ SET(${name}_test_additional_INCLUDE_DIRS "")
+ ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
+ INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}")
+ ENDIF(LL_TEST_VERBOSE)
+
+
+ # Setup target
+ ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES})
+ SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+
+ #
+ # Per-codefile additional / external project dep and lib dep property extraction
+ #
+ # WARNING: it's REALLY IMPORTANT to not mix these. I guarantee it will not work in the future. + poppy 2009-04-19
+ # Projects
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_PROJECTS ${source} LL_TEST_ADDITIONAL_PROJECTS)
+ IF(${name}_test_additional_PROJECTS MATCHES NOTFOUND)
+ SET(${name}_test_additional_PROJECTS "")
+ ENDIF(${name}_test_additional_PROJECTS MATCHES NOTFOUND)
+ # Libraries
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_LIBRARIES ${source} LL_TEST_ADDITIONAL_LIBRARIES)
+ IF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND)
+ SET(${name}_test_additional_LIBRARIES "")
+ ENDIF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND)
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_PROJECTS ${${name}_test_additional_PROJECTS}")
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_LIBRARIES ${${name}_test_additional_LIBRARIES}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Add to project
+ TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} )
+ # Compile-time Definitions
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS)
+ IF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
+ SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES COMPILE_FLAGS ${${name}_test_additional_CFLAGS} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}")
+ ENDIF(LL_TEST_VERBOSE)
+ ENDIF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
+
+ #
+ # Setup test targets
+ #
+ GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION)
+ SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt)
+ SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR})
+
+ # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
+ IF(LL_TEST_VERBOSE)
+ MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}")
+ ENDIF(LL_TEST_VERBOSE)
+
+ SET_TEST_PATH(LD_LIBRARY_PATH)
+ LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${TEST_CMD})
+ IF(LL_TEST_VERBOSE)
+ MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Add test
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${TEST_OUTPUT}
+ COMMAND ${TEST_SCRIPT_CMD}
+ DEPENDS PROJECT_${project}_TEST_${name}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ # Why not add custom target and add POST_BUILD command?
+ # Slightly less uncertain behavior
+ # (OUTPUT commands run non-deterministically AFAIK) + poppy 2009-04-19
+ # > I did not use a post build step as I could not make it notify of a
+ # > failure after the first time you build and fail a test. - daveh 2009-04-20
+ LIST(APPEND ${project}_TEST_OUTPUT ${TEST_OUTPUT})
+ ENDFOREACH (source)
+
+ # Add the test runner target per-project
+ # (replaces old _test_ok targets all over the place)
+ ADD_CUSTOM_TARGET(${project}_tests ALL DEPENDS ${${project}_TEST_OUTPUT})
+ ADD_DEPENDENCIES(${project} ${project}_tests)
+ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS)
+
+FUNCTION(LL_ADD_INTEGRATION_TEST
+ testname
+ additional_source_files
+ library_dependencies
+# variable args
+ )
+ if(TEST_DEBUG)
+ message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on")
+ endif(TEST_DEBUG)
+
+ SET(source_files
+ tests/${testname}_test.cpp
+ ${CMAKE_SOURCE_DIR}/test/test.cpp
+ ${CMAKE_SOURCE_DIR}/test/lltut.cpp
+ ${additional_source_files}
+ )
+
+ SET(libraries
+ ${library_dependencies}
+ ${GOOGLEMOCK_LIBRARIES}
+ ${PTHREAD_LIBRARY}
+ )
+
+ # Add test executable build target
+ if(TEST_DEBUG)
+ message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})")
+ endif(TEST_DEBUG)
+ ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})
+ SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+
+ # Add link deps to the executable
+ if(TEST_DEBUG)
+ message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})")
+ endif(TEST_DEBUG)
+ TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})
+
+ # Create the test running command
+ SET(test_command ${ARGN})
+ GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION)
+ LIST(FIND test_command "{}" test_exe_pos)
+ IF(test_exe_pos LESS 0)
+ # The {} marker means "the full pathname of the test executable."
+ # test_exe_pos -1 means we didn't find it -- so append the test executable
+ # name to $ARGN, the variable part of the arg list. This is convenient
+ # shorthand for both straightforward execution of the test program (empty
+ # $ARGN) and for running a "wrapper" program of some kind accepting the
+ # pathname of the test program as the last of its args. You need specify
+ # {} only if the test program's pathname isn't the last argument in the
+ # desired command line.
+ LIST(APPEND test_command "${TEST_EXE}")
+ ELSE (test_exe_pos LESS 0)
+ # Found {} marker at test_exe_pos. Remove the {}...
+ LIST(REMOVE_AT test_command test_exe_pos)
+ # ...and replace it with the actual name of the test executable.
+ LIST(INSERT test_command test_exe_pos "${TEST_EXE}")
+ ENDIF (test_exe_pos LESS 0)
+
+ SET_TEST_PATH(LD_LIBRARY_PATH)
+ LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${test_command})
+
+ if(TEST_DEBUG)
+ message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}")
+ endif(TEST_DEBUG)
+
+ ADD_CUSTOM_COMMAND(
+ TARGET INTEGRATION_TEST_${testname}
+ POST_BUILD
+ COMMAND ${TEST_SCRIPT_CMD}
+ )
+
+ # Use CTEST? Not sure how to yet...
+ # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD})
+
+ENDFUNCTION(LL_ADD_INTEGRATION_TEST)
+
+MACRO(SET_TEST_PATH LISTVAR)
+ IF(WINDOWS)
+ # We typically build/package only Release variants of third-party
+ # libraries, so append the Release staging dir in case the library being
+ # sought doesn't have a debug variant.
+ set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release)
+ ELSEIF(DARWIN)
+ # We typically build/package only Release variants of third-party
+ # libraries, so append the Release staging dir in case the library being
+ # sought doesn't have a debug variant.
+ set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib)
+ ELSE(WINDOWS)
+ # Linux uses a single staging directory anyway.
+ IF (STANDALONE)
+ set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib)
+ ELSE (STANDALONE)
+ set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib)
+ ENDIF (STANDALONE)
+ ENDIF(WINDOWS)
+ENDMACRO(SET_TEST_PATH)
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index 0901c1b7a2..748c8c2bec 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -9,10 +9,12 @@ if (WINDOWS) NAMES python25.exe python23.exe python.exe NO_DEFAULT_PATH # added so that cmake does not find cygwin python PATHS + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] diff --git a/indra/cmake/TemplateCheck.cmake b/indra/cmake/TemplateCheck.cmake index fa4e387dd5..90d58d93ad 100644 --- a/indra/cmake/TemplateCheck.cmake +++ b/indra/cmake/TemplateCheck.cmake @@ -7,8 +7,9 @@ macro (check_message_template _target) TARGET ${_target} POST_BUILD COMMAND ${PYTHON_EXECUTABLE} - ARGS ${SCRIPTS_DIR}/template_verifier.py - --mode=development --cache_master - COMMENT "Verifying message template" + ARGS ${SCRIPTS_DIR}/md5check.py + 3f19d130400c547de36278a6b6f9b028 + ${SCRIPTS_DIR}/messages/message_template.msg + COMMENT "Verifying message template - See http://wiki.secondlife.com/wiki/Template_verifier.py" ) endmacro (check_message_template) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index 32c4bc81df..df013b1665 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -3,7 +3,7 @@ include(Prebuilt) if (NOT STANDALONE) use_prebuilt_binary(libuuid) - use_prebuilt_binary(vivox) + use_prebuilt_binary(slvoice) use_prebuilt_binary(fontconfig) endif(NOT STANDALONE) diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index 23c34e52e7..d909516bf8 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -49,6 +49,7 @@ const guint ROTATE_IMAGE_TIMEOUT = 8000; typedef struct _updater_app_state { std::string app_name; std::string url; + std::string file; std::string image_dir; std::string dest_dir; std::string strings_dirs; @@ -113,7 +114,7 @@ BOOL install_package(std::string package_file, std::string destination); BOOL spawn_viewer(UpdaterAppState *app_state); extern "C" { - void on_window_closed(GtkWidget *sender, gpointer state); + void on_window_closed(GtkWidget *sender, GdkEvent *event, gpointer state); gpointer worker_thread_cb(gpointer *data); int download_progress_cb(gpointer data, double t, double d, double utotal, double ulnow); gboolean rotate_image_cb(gpointer data); @@ -220,7 +221,7 @@ std::string next_image_filename(std::string& image_path) return image_path + "/" + image_filename; } -void on_window_closed(GtkWidget *sender, gpointer data) +void on_window_closed(GtkWidget *sender, GdkEvent* event, gpointer data) { UpdaterAppState *app_state; @@ -266,85 +267,95 @@ gpointer worker_thread_cb(gpointer data) CURLcode result; FILE *package_file; GError *error = NULL; - char *tmp_filename = NULL; int fd; //g_return_val_if_fail (data != NULL, NULL); app_state = (UpdaterAppState *) data; try { - // create temporary file to store the package. - fd = g_file_open_tmp - ("secondlife-update-XXXXXX", &tmp_filename, &error); - if (error != NULL) - { - llerrs << "Unable to create temporary file: " - << error->message - << llendl; - - g_error_free(error); - throw 0; - } - package_file = fdopen(fd, "wb"); - if (package_file == NULL) + if(!app_state->url.empty()) { - llerrs << "Failed to create temporary file: " - << tmp_filename - << llendl; + char* tmp_local_filename = NULL; + // create temporary file to store the package. + fd = g_file_open_tmp + ("secondlife-update-XXXXXX", &tmp_local_filename, &error); + if (error != NULL) + { + llerrs << "Unable to create temporary file: " + << error->message + << llendl; - gdk_threads_enter(); - display_error(app_state->window, - LLTrans::getString("UpdaterFailDownloadTitle"), - LLTrans::getString("UpdaterFailUpdateDescriptive")); - gdk_threads_leave(); - throw 0; - } + g_error_free(error); + throw 0; + } + + if(tmp_local_filename != NULL) + { + app_state->file = tmp_local_filename; + g_free(tmp_local_filename); + } - // initialize curl and start downloading the package - llinfos << "Downloading package: " << app_state->url << llendl; + package_file = fdopen(fd, "wb"); + if (package_file == NULL) + { + llerrs << "Failed to create temporary file: " + << app_state->file.c_str() + << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailDownloadTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); + throw 0; + } - curl = curl_easy_init(); - if (curl == NULL) - { - llerrs << "Failed to initialize libcurl" << llendl; + // initialize curl and start downloading the package + llinfos << "Downloading package: " << app_state->url << llendl; - gdk_threads_enter(); - display_error(app_state->window, - LLTrans::getString("UpdaterFailDownloadTitle"), - LLTrans::getString("UpdaterFailUpdateDescriptive")); - gdk_threads_leave(); - throw 0; - } + curl = curl_easy_init(); + if (curl == NULL) + { + llerrs << "Failed to initialize libcurl" << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailDownloadTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); + throw 0; + } - curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str()); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, - &download_progress_cb); - curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state); + curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str()); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, + &download_progress_cb); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state); - result = curl_easy_perform(curl); - fclose(package_file); - curl_easy_cleanup(curl); + result = curl_easy_perform(curl); + fclose(package_file); + curl_easy_cleanup(curl); - if (result) - { - llerrs << "Failed to download update: " - << app_state->url - << llendl; + if (result) + { + llerrs << "Failed to download update: " + << app_state->url + << llendl; - gdk_threads_enter(); - display_error(app_state->window, - LLTrans::getString("UpdaterFailDownloadTitle"), - LLTrans::getString("UpdaterFailUpdateDescriptive")); - gdk_threads_leave(); + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailDownloadTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); - throw 0; + throw 0; + } } - + // now pulse the progres bar back and forth while the package is // being unpacked gdk_threads_enter(); @@ -357,7 +368,7 @@ gpointer worker_thread_cb(gpointer data) // *TODO: if the destination is not writable, terminate this // thread and show file chooser? - if (!install_package(tmp_filename, app_state->dest_dir)) + if (!install_package(app_state->file.c_str(), app_state->dest_dir)) { llwarns << "Failed to install package to destination: " << app_state->dest_dir @@ -392,15 +403,6 @@ gpointer worker_thread_cb(gpointer data) app_state->failure = TRUE; } - // FIXME: delete package file also if delete-event is raised on window - if (tmp_filename != NULL) - { - if (gDirUtilp->fileExists(tmp_filename)) - { - LLFile::remove(tmp_filename); - } - } - gdk_threads_enter(); updater_app_quit(app_state); gdk_threads_leave(); @@ -712,7 +714,7 @@ BOOL spawn_viewer(UpdaterAppState *app_state) void show_usage_and_exit() { - std::cout << "Usage: linux-updater --url URL --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE" + std::cout << "Usage: linux-updater <--url URL | --file FILE> --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE" << "[--image-dir PATH]" << std::endl; exit(1); @@ -728,6 +730,10 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) { app_state->url = argv[i]; } + else if ((!strcmp(argv[i], "--file")) && (++i < argc)) + { + app_state->file = argv[i]; + } else if ((!strcmp(argv[i], "--name")) && (++i < argc)) { app_state->app_name = argv[i]; @@ -756,7 +762,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) } if (app_state->app_name.empty() - || app_state->url.empty() + || (app_state->url.empty() && app_state->file.empty()) || app_state->dest_dir.empty()) { show_usage_and_exit(); @@ -771,10 +777,10 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) int main(int argc, char **argv) { - UpdaterAppState app_state; + UpdaterAppState* app_state = new UpdaterAppState; GThread *worker_thread; - parse_args_and_init(argc, argv, &app_state); + parse_args_and_init(argc, argv, app_state); // Initialize logger, and rename old log file gDirUtilp->initAppDirs("SecondLife"); @@ -797,17 +803,29 @@ int main(int argc, char **argv) gtk_init(&argc, &argv); // create UI - updater_app_ui_init(&app_state); + updater_app_ui_init(app_state); //llinfos << "SAMPLE TRANSLATION IS: " << LLTrans::getString("LoginInProgress") << llendl; // create download thread worker_thread = g_thread_create - (GThreadFunc(worker_thread_cb), &app_state, FALSE, NULL); + (GThreadFunc(worker_thread_cb), app_state, FALSE, NULL); gdk_threads_enter(); gtk_main(); gdk_threads_leave(); - return (app_state.failure == FALSE) ? 0 : 1; + // Delete the file only if created from url download. + if(!app_state->url.empty() && !app_state->file.empty()) + { + if (gDirUtilp->fileExists(app_state->file)) + { + LLFile::remove(app_state->file); + } + } + + bool success = !app_state->failure; + delete app_state; + return success ? 0 : 1; } + diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 478f2fedbd..9342a22d46 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -93,6 +93,7 @@ set(llcommon_SOURCE_FILES llstringtable.cpp llsys.cpp llthread.cpp + llthreadsafequeue.cpp lltimer.cpp lluri.cpp lluuid.cpp @@ -225,6 +226,7 @@ set(llcommon_HEADER_FILES llstringtable.h llsys.h llthread.h + llthreadsafequeue.h lltimer.h lltreeiterators.h lluri.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index b0618bfe59..95cb606240 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -245,9 +245,6 @@ const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only const U8 SIM_ACCESS_DOWN = 254; const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; -// group constants -const S32 MAX_AGENT_GROUPS = 25; - // attachment constants const S32 MAX_AGENT_ATTACHMENTS = 38; const U8 ATTACHMENT_ADD = 0x80; @@ -300,6 +297,14 @@ const U32 START_LOCATION_ID_COUNT = 6; // group constants const U32 GROUP_MIN_SIZE = 2; +// gMaxAgentGroups is now sent by login.cgi, which +// looks it up from globals.xml. +// +// For now we need an old default value however, +// so the viewer can be deployed ahead of login.cgi. +// +const S32 DEFAULT_MAX_AGENT_GROUPS = 25; + // radius within which a chat message is fully audible const F32 CHAT_WHISPER_RADIUS = 10.f; const F32 CHAT_NORMAL_RADIUS = 20.f; diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 289ce0bc2c..8f02391e75 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -318,7 +318,12 @@ void llofstream::close() if(is_open()) { if (_Filebuffer->close() == 0) + { _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/ + } + delete _Filebuffer; + _Filebuffer = NULL; + _ShouldClose = false; } } diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index d7b7c3699c..148aaf8aed 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -147,16 +147,20 @@ void LLThread::shutdown() { // This thread just wouldn't stop, even though we gave it time llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; + // Put a stake in its heart. + apr_thread_exit(mAPRThreadp, -1); return; } mAPRThreadp = NULL; } delete mRunCondition; + mRunCondition = 0; - if (mIsLocalPool) + if (mIsLocalPool && mAPRPoolp) { apr_pool_destroy(mAPRPoolp); + mAPRPoolp = 0; } } diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp new file mode 100644 index 0000000000..8a73e632a9 --- /dev/null +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -0,0 +1,109 @@ +/** + * @file llthread.cpp + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include <apr_pools.h> +#include <apr_queue.h> +#include "llthreadsafequeue.h" + + + +// LLThreadSafeQueueImplementation +//----------------------------------------------------------------------------- + + +LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity): + mOwnsPool(pool == 0), + mPool(pool), + mQueue(0) +{ + if(mOwnsPool) { + apr_status_t status = apr_pool_create(&mPool, 0); + if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool"); + } else { + ; // No op. + } + + apr_status_t status = apr_queue_create(&mQueue, capacity, mPool); + if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue"); +} + + +LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation() +{ + if(mQueue != 0) { + if(apr_queue_size(mQueue) != 0) llwarns << + "terminating queue which still contains " << apr_queue_size(mQueue) << + " elements;" << "memory will be leaked" << LL_ENDL; + apr_queue_term(mQueue); + } + if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool); +} + + +void LLThreadSafeQueueImplementation::pushFront(void * element) +{ + apr_status_t status = apr_queue_push(mQueue, element); + + if(status == APR_EINTR) { + throw LLThreadSafeQueueInterrupt(); + } else if(status != APR_SUCCESS) { + throw LLThreadSafeQueueError("push failed"); + } else { + ; // Success. + } +} + + +bool LLThreadSafeQueueImplementation::tryPushFront(void * element){ + return apr_queue_trypush(mQueue, element) == APR_SUCCESS; +} + + +void * LLThreadSafeQueueImplementation::popBack(void) +{ + void * element; + apr_status_t status = apr_queue_pop(mQueue, &element); + + if(status == APR_EINTR) { + throw LLThreadSafeQueueInterrupt(); + } else if(status != APR_SUCCESS) { + throw LLThreadSafeQueueError("pop failed"); + } else { + return element; + } +} + + +bool LLThreadSafeQueueImplementation::tryPopBack(void *& element) +{ + return apr_queue_trypop(mQueue, &element) == APR_SUCCESS; +} + + +size_t LLThreadSafeQueueImplementation::size() +{ + return apr_queue_size(mQueue); +} diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h new file mode 100644 index 0000000000..58cac38769 --- /dev/null +++ b/indra/llcommon/llthreadsafequeue.h @@ -0,0 +1,205 @@ +/** + * @file llthreadsafequeue.h + * @brief Base classes for thread, mutex and condition handling. + * + * $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_LLTHREADSAFEQUEUE_H +#define LL_LLTHREADSAFEQUEUE_H + + +#include <string> +#include <stdexcept> + + +struct apr_pool_t; // From apr_pools.h +class LLThreadSafeQueueImplementation; // See below. + + +// +// A general queue exception. +// +class LL_COMMON_API LLThreadSafeQueueError: +public std::runtime_error +{ +public: + LLThreadSafeQueueError(std::string const & message): + std::runtime_error(message) + { + ; // No op. + } +}; + + +// +// An exception raised when blocking operations are interrupted. +// +class LL_COMMON_API LLThreadSafeQueueInterrupt: + public LLThreadSafeQueueError +{ +public: + LLThreadSafeQueueInterrupt(void): + LLThreadSafeQueueError("queue operation interrupted") + { + ; // No op. + } +}; + + +struct apr_queue_t; // From apr_queue.h + + +// +// Implementation details. +// +class LL_COMMON_API LLThreadSafeQueueImplementation +{ +public: + LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity); + ~LLThreadSafeQueueImplementation(); + void pushFront(void * element); + bool tryPushFront(void * element); + void * popBack(void); + bool tryPopBack(void *& element); + size_t size(); + +private: + bool mOwnsPool; + apr_pool_t * mPool; + apr_queue_t * mQueue; +}; + + +// +// Implements a thread safe FIFO. +// +template<typename ElementT> +class LLThreadSafeQueue +{ +public: + typedef ElementT value_type; + + // If the pool is set to NULL one will be allocated and managed by this + // queue. + LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024); + + // Add an element to the front of queue (will block if the queue has + // reached capacity). + // + // This call will raise an interrupt error if the queue is deleted while + // the caller is blocked. + void pushFront(ElementT const & element); + + // Try to add an element to the front ofqueue without blocking. Returns + // true only if the element was actually added. + bool tryPushFront(ElementT const & element); + + // Pop the element at the end of the queue (will block if the queue is + // empty). + // + // This call will raise an interrupt error if the queue is deleted while + // the caller is blocked. + ElementT popBack(void); + + // Pop an element from the end of the queue if there is one available. + // Returns true only if an element was popped. + bool tryPopBack(ElementT & element); + + // Returns the size of the queue. + size_t size(); + +private: + LLThreadSafeQueueImplementation mImplementation; +}; + + + +// LLThreadSafeQueue +//----------------------------------------------------------------------------- + + +template<typename ElementT> +LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity): + mImplementation(pool, capacity) +{ + ; // No op. +} + + +template<typename ElementT> +void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element) +{ + ElementT * elementCopy = new ElementT(element); + try { + mImplementation.pushFront(elementCopy); + } catch (LLThreadSafeQueueInterrupt) { + delete elementCopy; + throw; + } +} + + +template<typename ElementT> +bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element) +{ + ElementT * elementCopy = new ElementT(element); + bool result = mImplementation.tryPushFront(elementCopy); + if(!result) delete elementCopy; + return result; +} + + +template<typename ElementT> +ElementT LLThreadSafeQueue<ElementT>::popBack(void) +{ + ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack()); + ElementT result(*element); + delete element; + return result; +} + + +template<typename ElementT> +bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element) +{ + void * storedElement; + bool result = mImplementation.tryPopBack(storedElement); + if(result) { + ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement); + element = *elementPtr; + delete elementPtr; + } else { + ; // No op. + } + return result; +} + + +template<typename ElementT> +size_t LLThreadSafeQueue<ElementT>::size(void) +{ + return mImplementation.size(); +} + + +#endif diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 5cc7d355cc..04f72d93b4 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,7 +28,7 @@ #define LL_LLVERSIONVIEWER_H const S32 LL_VERSION_MAJOR = 2; -const S32 LL_VERSION_MINOR = 4; +const S32 LL_VERSION_MINOR = 5; const S32 LL_VERSION_PATCH = 0; const S32 LL_VERSION_BUILD = 211776; diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index ff9af21e54..19c42bf61a 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1620,7 +1620,10 @@ void LLUI::initClass(const settings_map_t& settings, void LLUI::cleanupClass() { - sImageProvider->cleanUp(); + if(sImageProvider) + { + sImageProvider->cleanUp(); + } } void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups) diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp index 83ccb277b3..8788bd63e8 100644 --- a/indra/llvfs/tests/lldir_test.cpp +++ b/indra/llvfs/tests/lldir_test.cpp @@ -263,7 +263,9 @@ namespace tut std::string path = dir + delim + file; LLFILE* handle = LLFile::fopen( path, "w" ); ensure("failed to open test file '"+path+"'", handle != NULL ); - ensure("failed to write to test file '"+path+"'", !fputs("test file", handle) ); + // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs + // returns EOF; otherwise, it returns some other, nonnegative value." + ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0); fclose(handle); return path; } diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index f9a39826f5..27c694dde9 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1107,7 +1107,7 @@ bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::strin return sd.asBoolean(); else { - CONTROL_ERRS << "Invalid BOOL value" << llendl; + CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << llendl; return FALSE; } } @@ -1119,7 +1119,7 @@ S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& return sd.asInteger(); else { - CONTROL_ERRS << "Invalid S32 value" << llendl; + CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << llendl; return 0; } } @@ -1131,7 +1131,7 @@ U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& return sd.asInteger(); else { - CONTROL_ERRS << "Invalid U32 value" << llendl; + CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << llendl; return 0; } } @@ -1143,7 +1143,7 @@ F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& return (F32) sd.asReal(); else { - CONTROL_ERRS << "Invalid F32 value" << llendl; + CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << llendl; return 0.0f; } } @@ -1155,7 +1155,7 @@ std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, co return sd.asString(); else { - CONTROL_ERRS << "Invalid string value" << llendl; + CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << llendl; return LLStringUtil::null; } } @@ -1173,7 +1173,7 @@ LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const return (LLVector3)sd; else { - CONTROL_ERRS << "Invalid LLVector3 value" << llendl; + CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << llendl; return LLVector3::zero; } } @@ -1185,7 +1185,7 @@ LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, cons return (LLVector3d)sd; else { - CONTROL_ERRS << "Invalid LLVector3d value" << llendl; + CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << llendl; return LLVector3d::zero; } } @@ -1197,7 +1197,7 @@ LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::s return LLRect(sd); else { - CONTROL_ERRS << "Invalid rect value" << llendl; + CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << llendl; return LLRect::null; } } @@ -1211,19 +1211,19 @@ LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const st LLColor4 color(sd); if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) { - llwarns << "Color " << control_name << " value out of range " << llendl; + llwarns << "Color " << control_name << " red value out of range: " << color << llendl; } else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) { - llwarns << "Color " << control_name << " value out of range " << llendl; + llwarns << "Color " << control_name << " green value out of range: " << color << llendl; } else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) { - llwarns << "Color " << control_name << " value out of range " << llendl; + llwarns << "Color " << control_name << " blue value out of range: " << color << llendl; } else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) { - llwarns << "Color " << control_name << " value out of range " << llendl; + llwarns << "Color " << control_name << " alpha value out of range: " << color << llendl; } return LLColor4(sd); @@ -1242,7 +1242,7 @@ LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const st return sd; else { - CONTROL_ERRS << "Invalid LLColor3 value" << llendl; + CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << llendl; return LLColor3::white; } } diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp index 23980ffac2..5d19e8a889 100644 --- a/indra/mac_updater/mac_updater.cpp +++ b/indra/mac_updater/mac_updater.cpp @@ -26,6 +26,9 @@ #include "linden_common.h" +#include <boost/format.hpp> + +#include <libgen.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -62,6 +65,8 @@ Boolean gCancelled = false; const char *gUpdateURL; const char *gProductName; const char *gBundleID; +const char *gDmgFile; +const char *gMarkerPath; void *updatethreadproc(void*); @@ -334,6 +339,14 @@ int parse_args(int argc, char **argv) { gBundleID = argv[j]; } + else if ((!strcmp(argv[j], "-dmg")) && (++j < argc)) + { + gDmgFile = argv[j]; + } + else if ((!strcmp(argv[j], "-marker")) && (++j < argc)) + { + gMarkerPath = argv[j];; + } } return 0; @@ -361,10 +374,12 @@ int main(int argc, char **argv) gUpdateURL = NULL; gProductName = NULL; gBundleID = NULL; + gDmgFile = NULL; + gMarkerPath = NULL; parse_args(argc, argv); - if (!gUpdateURL) + if ((gUpdateURL == NULL) && (gDmgFile == NULL)) { - llinfos << "Usage: mac_updater -url <url> [-name <product_name>] [-program <program_name>]" << llendl; + llinfos << "Usage: mac_updater -url <url> | -dmg <dmg file> [-name <product_name>] [-program <program_name>]" << llendl; exit(1); } else @@ -488,11 +503,18 @@ int main(int argc, char **argv) NULL, &retval_mac); } - + + if(gMarkerPath != 0) + { + // Create a install fail marker that can be used by the viewer to + // detect install problems. + std::ofstream stream(gMarkerPath); + if(stream) stream << -1; + } + exit(-1); + } else { + exit(0); } - - // Don't dispose of things, just exit. This keeps the update thread from potentially getting hosed. - exit(0); if(gWindow != NULL) { @@ -700,17 +722,26 @@ static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app) // Looks promising. Check to see if it has the right bundle identifier. if(isFSRefViewerBundle(&ref)) { + llinfos << name << " is the one" << llendl; // This is the one. Return it. *app = ref; found = true; + break; + } else { + llinfos << name << " is not the bundle we are looking for; move along" << llendl; } + } } } } - while(!err && !found); + while(!err); + + llinfos << "closing the iterator" << llendl; FSCloseIterator(iterator); + + llinfos << "closed" << llendl; } if(!err && !found) @@ -921,6 +952,22 @@ void *updatethreadproc(void*) #endif // 0 *HACK for DEV-11935 + // Skip downloading the file if the dmg was passed on the command line. + std::string dmgName; + if(gDmgFile != NULL) { + dmgName = basename((char *)gDmgFile); + char * dmgDir = dirname((char *)gDmgFile); + strncpy(tempDir, dmgDir, sizeof(tempDir)); + err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); + if(err != noErr) throw 0; + chdir(tempDir); + goto begin_install; + } else { + // Continue on to download file. + dmgName = "SecondLife.dmg"; + } + + strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); if(mkdtemp(temp) == NULL) { @@ -979,14 +1026,17 @@ void *updatethreadproc(void*) fclose(downloadFile); downloadFile = NULL; } - + + begin_install: sendProgress(0, 0, CFSTR("Mounting image...")); LLFile::mkdir("mnt", 0700); // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder, // but if our cleanup fails, this makes it much harder for the user to unmount the image. std::string mountOutput; - FILE* mounter = popen("hdiutil attach SecondLife.dmg -mountpoint mnt", "r"); /* Flawfinder: ignore */ + boost::format cmdFormat("hdiutil attach %s -mountpoint mnt"); + cmdFormat % dmgName; + FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */ if(mounter == NULL) { @@ -1052,12 +1102,19 @@ void *updatethreadproc(void*) throw 0; } + sendProgress(0, 0, CFSTR("Searching for the app bundle...")); err = findAppBundleOnDiskImage(&mountRef, &sourceRef); if(err != noErr) { llinfos << "Couldn't find application bundle on mounted disk image." << llendl; throw 0; } + else + { + llinfos << "found the bundle." << llendl; + } + + sendProgress(0, 0, CFSTR("Preparing to copy files...")); FSRef asideRef; char aside[MAX_PATH]; /* Flawfinder: ignore */ @@ -1077,7 +1134,11 @@ void *updatethreadproc(void*) // Move aside old version (into work directory) err = FSMoveObject(&targetRef, &tempDirRef, &asideRef); if(err != noErr) + { + llwarns << "failed to move aside old version (error code " << + err << ")" << llendl; throw 0; + } // Grab the path for later use. err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside)); @@ -1175,6 +1236,10 @@ void *updatethreadproc(void*) llinfos << "Moving work directory to the trash." << llendl; err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL); + if(err != noErr) { + llwarns << "failed to move files to trash, (error code " << + err << ")" << llendl; + } // snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir); // printf("%s\n", temp); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3a4b9be0d7..fa49c1ac4c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -64,6 +64,7 @@ include_directories( ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile ${LLLOGIN_INCLUDE_DIRS} + ${UPDATER_INCLUDE_DIRS} ) set(viewer_SOURCE_FILES @@ -284,6 +285,7 @@ set(viewer_SOURCE_FILES llloginhandler.cpp lllogininstance.cpp llmachineid.cpp + llmainlooprepeater.cpp llmanip.cpp llmaniprotate.cpp llmanipscale.cpp @@ -445,6 +447,7 @@ set(viewer_SOURCE_FILES lltoastimpanel.cpp lltoastnotifypanel.cpp lltoastpanel.cpp + lltoastscripttextbox.cpp lltool.cpp lltoolbrush.cpp lltoolcomp.cpp @@ -817,6 +820,7 @@ set(viewer_HEADER_FILES llloginhandler.h lllogininstance.h llmachineid.h + llmainlooprepeater.h llmanip.h llmaniprotate.h llmanipscale.h @@ -975,6 +979,7 @@ set(viewer_HEADER_FILES lltoastimpanel.h lltoastnotifypanel.h lltoastpanel.h + lltoastscripttextbox.h lltool.h lltoolbrush.h lltoolcomp.h @@ -1644,7 +1649,14 @@ if (WINDOWS) endif (PACKAGE) endif (WINDOWS) +# *NOTE - this list is very sensitive to ordering, test carefully on all +# platforms if you change the releative order of the entries here. +# In particular, cmake 2.6.4 (when buidling with linux/makefile generators) +# appears to sometimes de-duplicate redundantly listed dependencies improperly. +# To work around this, higher level modules should be listed before the modules +# that they depend upon. -brad target_link_libraries(${VIEWER_BINARY_NAME} + ${UPDATER_LIBRARIES} ${LLAUDIO_LIBRARIES} ${LLCHARACTER_LIBRARIES} ${LLIMAGE_LIBRARIES} @@ -1831,10 +1843,18 @@ if (PACKAGE) set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) endif (LINUX) + if(CMAKE_CFG_INTDIR STREQUAL ".") + set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) + else(CMAKE_CFG_INTDIR STREQUAL ".") + # set LLBUILD_CONFIG to be a shell variable evaluated at build time + # reflecting the configuration we are currently building. + set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) + endif(CMAKE_CFG_INTDIR STREQUAL ".") add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" COMMAND "${PYTHON_EXECUTABLE}" ARGS "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" + "${LLBUILD_CONFIG}" "${VIEWER_DIST_DIR}" "${VIEWER_EXE_GLOBS}" "${VIEWER_LIB_GLOB}" @@ -1843,7 +1863,7 @@ if (PACKAGE) DEPENDS generate_breakpad_symbols.py VERBATIM ) - add_custom_target(generate_breakpad_symbols ALL DEPENDS "${VIEWER_SYMBOL_FILE}") + add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") add_dependencies(package generate_breakpad_symbols) endif (PACKAGE) @@ -1858,6 +1878,7 @@ if (LL_TESTS) llmediadataclient.cpp lllogininstance.cpp llviewerhelputil.cpp + llversioninfo.cpp ) ################################################## diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index 0562cf5480..1b8393330d 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -363,8 +363,7 @@ <map> <key>count</key> <integer>1</integer> - <key>map-to</key> - <string>VersionChannelName</string> + <!-- Special case. Not mapped to a setting. --> </map> <key>loginpage</key> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 561456c9d6..0f946b0f0b 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1365,6 +1365,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>LetterKeysFocusChatBar</key> + <map> + <key>Comment</key> + <string>When printable characters keys (possibly with Shift held) are pressed, the chatbar takes focus</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>0</integer> + </map> <key>ChatBubbleOpacity</key> <map> <key>Comment</key> @@ -8340,6 +8351,17 @@ <key>Value</key> <real>1.0</real> </map> + <key>RenderTransparentWater</key> + <map> + <key>Comment</key> + <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RenderTreeLODFactor</key> <map> <key>Comment</key> @@ -11068,7 +11090,62 @@ <key>Value</key> <integer>15</integer> </map> - <key>UploadBakedTexOld</key> + <key>UpdaterServiceActive</key> + <map> + <key>Comment</key> + <string>Enable or disable the updater service.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>UpdaterServiceCheckPeriod</key> + <map> + <key>Comment</key> + <string>Default period between update checking.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>3600</integer> + </map> + <key>UpdaterServiceURL</key> + <map> + <key>Comment</key> + <string>Default location for the updater service.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>http://update.secondlife.com</string> + </map> + <key>UpdaterServicePath</key> + <map> + <key>Comment</key> + <string>Path on the update server host.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>update</string> + </map> + <key>UpdaterServiceProtocolVersion</key> + <map> + <key>Comment</key> + <string>The update protocol version to use.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>v1.0</string> + </map> + <key>UploadBakedTexOld</key> <map> <key>Comment</key> <string>Forces the baked texture pipeline to upload using the old method.</string> @@ -11421,17 +11498,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>VersionChannelName</key> - <map> - <key>Comment</key> - <string>Versioning Channel Name.</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>Second Life Release</string> - </map> <key>VertexShaderEnable</key> <map> <key>Comment</key> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index d69842d5f1..a95abd7dd1 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -42,6 +42,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVBOEnable 1 1 @@ -80,6 +81,7 @@ RenderObjectBump 1 0 RenderReflectionDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 0.5 @@ -108,6 +110,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -135,6 +138,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -162,6 +166,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index efe29005f2..a52b32355d 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -42,6 +42,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVBOEnable 1 1 @@ -79,6 +80,7 @@ RenderObjectBump 1 0 RenderReflectionDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 0.5 @@ -107,6 +109,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -134,6 +137,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -161,6 +165,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index f030c9f8e5..6dabef53a8 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -43,6 +43,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 3 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVBOEnable 1 1 @@ -80,6 +81,7 @@ RenderObjectBump 1 0 RenderReflectionDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 0.5 @@ -107,6 +109,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -133,6 +136,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -159,6 +163,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 3 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index dae7705971..a09ba17c62 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -42,6 +42,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVBOEnable 1 1 @@ -80,6 +81,7 @@ RenderObjectBump 1 0 RenderReflectionDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 0.5 @@ -108,6 +110,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -135,6 +138,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 @@ -162,6 +166,7 @@ RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py index 8f2dfd2348..4fd04d780e 100644 --- a/indra/newview/generate_breakpad_symbols.py +++ b/indra/newview/generate_breakpad_symbols.py @@ -31,6 +31,7 @@ import fnmatch import itertools import operator import os +import re import sys import shlex import subprocess @@ -45,8 +46,12 @@ class MissingModuleError(Exception): Exception.__init__(self, "Failed to find required modules: %r" % modules) self.modules = modules -def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file): - print "generate_breakpad_symbols run with args: %s" % str((viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file)) +def main(configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file): + print "generate_breakpad_symbols run with args: %s" % str((configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file)) + + if not re.match("release", configuration, re.IGNORECASE): + print "skipping breakpad symbol generation for non-release build." + return 0 # split up list of viewer_exes # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin'] @@ -122,7 +127,7 @@ def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_fil return 0 if __name__ == "__main__": - if len(sys.argv) != 6: + if len(sys.argv) != 7: usage() sys.exit(1) sys.exit(main(*sys.argv[1:])) diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index d5712f80cf..4e8ed807ee 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -85,6 +85,8 @@ AutoCloseWindow true ; after all files install, close window InstallDir "$PROGRAMFILES\${INSTNAME}" InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "" DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup) +Page directory dirPre +Page instfiles ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Variables @@ -95,6 +97,8 @@ Var INSTFLAGS Var INSTSHORTCUT Var COMMANDLINE ; command line passed to this installer, set in .onInit Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer +Var SKIP_DIALOGS ; set from command line in .onInit. autoinstall + ; GUI and the defaults. ;;; Function definitions should go before file includes, because calls to ;;; DLLs like LangDLL trigger an implicit file include, so if that call is at @@ -110,6 +114,9 @@ Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function .onInstSuccess Push $R0 # Option value, unused + + StrCmp $SKIP_DIALOGS "true" label_launch + ${GetOptions} $COMMANDLINE "/AUTOSTART" $R0 # If parameter was there (no error) just launch # Otherwise ask @@ -128,6 +135,13 @@ label_no_launch: Pop $R0 FunctionEnd +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Pre-directory page callback +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +Function dirPre + StrCmp $SKIP_DIALOGS "true" 0 +2 + Abort +FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Make sure we're not on Windows 98 / ME @@ -145,7 +159,8 @@ Function CheckWindowsVersion StrCmp $R0 "NT" win_ver_bad Return win_ver_bad: - MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort + StrCmp $SKIP_DIALOGS "true" +2 ; If skip_dialogs is set just install + MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort Return win_ver_abort: Quit @@ -184,13 +199,13 @@ FunctionEnd ; If it has, allow user to bail out of install process. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function CheckIfAlreadyCurrent - Push $0 - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" - StrCmp $0 ${VERSION_LONG} 0 DONE - MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE + Push $0 + ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" + StrCmp $0 ${VERSION_LONG} 0 continue_install + StrCmp $SKIP_DIALOGS "true" continue_install + MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK continue_install Quit - - DONE: +continue_install: Pop $0 Return FunctionEnd @@ -203,7 +218,9 @@ Function CloseSecondLife Push $0 FindWindow $0 "Second Life" "" IntCmp $0 0 DONE - MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL + + StrCmp $SKIP_DIALOGS "true" CLOSE + MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL CANCEL_INSTALL: Quit @@ -659,23 +676,29 @@ FunctionEnd Function .onInit Push $0 ${GetParameters} $COMMANDLINE ; get our command line + + ${GetOptions} $COMMANDLINE "/SKIP_DIALOGS" $0 + IfErrors +2 0 ; If error jump past setting SKIP_DIALOGS + StrCpy $SKIP_DIALOGS "true" + ${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English ; If no language (error), then proceed - IfErrors lbl_check_silent + IfErrors lbl_configure_default_lang ; No error means we got a language, so use it StrCpy $LANGUAGE $0 Goto lbl_return -lbl_check_silent: - ; For silent installs, no language prompt, use default - IfSilent lbl_return - - ; If we currently have a version of SL installed, default to the language of that install +lbl_configure_default_lang: + ; If we currently have a version of SL installed, default to the language of that install ; Otherwise don't change $LANGUAGE and it will default to the OS UI language. - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" - IfErrors lbl_build_menu + ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" + IfErrors +2 0 ; If error skip the copy instruction StrCpy $LANGUAGE $0 + ; For silent installs, no language prompt, use default + IfSilent lbl_return + StrCmp $SKIP_DIALOGS "true" lbl_return + lbl_build_menu: Push "" # Use separate file so labels can be UTF-16 but we can still merge changes diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index c9bd7851ed..3a45c79ec3 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -59,6 +59,7 @@ #include "llsidetray.h" #include "llsky.h" #include "llsmoothstep.h" +#include "llstartup.h" #include "llstatusbar.h" #include "llteleportflags.h" #include "lltool.h" @@ -2452,7 +2453,7 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO BOOL LLAgent::canJoinGroups() const { - return mGroups.count() < MAX_AGENT_GROUPS; + return mGroups.count() < gMaxAgentGroups; } LLQuaternion LLAgent::getHeadRotation() diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f66663891d..b6f52e3e15 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -83,6 +83,7 @@ #include "llweb.h" #include "llsecondlifeurls.h" +#include "llupdaterservice.h" // Linden library includes #include "llavatarnamecache.h" @@ -196,6 +197,8 @@ #include "llsecapi.h" #include "llmachineid.h" +#include "llmainlooprepeater.h" + // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either // this app, or another 'component' of the viewer. App globals should be @@ -576,7 +579,8 @@ LLAppViewer::LLAppViewer() : mAgentRegionLastAlive(false), mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)), mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), - mFastTimerLogThread(NULL) + mFastTimerLogThread(NULL), + mUpdater(new LLUpdaterService()) { if(NULL != sInstance) { @@ -652,10 +656,13 @@ bool LLAppViewer::init() initThreads(); writeSystemInfo(); - // Build a string representing the current version number. - gCurrentVersion = llformat("%s %s", - gSavedSettings.getString("VersionChannelName").c_str(), - LLVersionInfo::getVersion().c_str()); + // Initialize updater service (now that we have an io pump) + initUpdater(); + if(isQuitting()) + { + // Early out here because updater set the quitting flag. + return true; + } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -799,6 +806,9 @@ bool LLAppViewer::init() return 1; } + // Initialize the repeater service. + LLMainLoopRepeater::instance().start(); + // // Initialize the window // @@ -895,7 +905,8 @@ bool LLAppViewer::init() gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); // Save the current version to the prefs file - gSavedSettings.setString("LastRunVersion", gCurrentVersion); + gSavedSettings.setString("LastRunVersion", + LLVersionInfo::getVersionAndChannel()); gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; @@ -970,7 +981,7 @@ bool LLAppViewer::mainLoop() gServicePump = new LLPumpIO(gAPRPoolp); LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); - + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. LLVoiceChannel::initClass(); @@ -1353,11 +1364,14 @@ bool LLAppViewer::cleanup() llinfos << "Cleaning Up" << llendflush; // Must clean up texture references before viewer window is destroyed. - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDObject::cleanupHUDObjects(); - llinfos << "HUD Objects cleaned up" << llendflush; + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDObject::cleanupHUDObjects(); + llinfos << "HUD Objects cleaned up" << llendflush; + } LLKeyframeDataCache::clear(); @@ -1369,8 +1383,10 @@ bool LLAppViewer::cleanup() // Note: this is where gWorldMap used to be deleted. // Note: this is where gHUDManager used to be deleted. - LLHUDManager::getInstance()->shutdownClass(); - + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->shutdownClass(); + } delete gAssetStorage; gAssetStorage = NULL; @@ -1666,7 +1682,10 @@ bool LLAppViewer::cleanup() #ifndef LL_RELEASE_FOR_DOWNLOAD llinfos << "Auditing VFS" << llendl; - gVFS->audit(); + if(gVFS) + { + gVFS->audit(); + } #endif llinfos << "Misc Cleanup" << llendflush; @@ -1707,6 +1726,8 @@ bool LLAppViewer::cleanup() llinfos << "File launched." << llendflush; } + LLMainLoopRepeater::instance().stop(); + ll_close_fail_log(); llinfos << "Goodbye!" << llendflush; @@ -1953,8 +1974,6 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setString("ClientSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); - gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel()); - #ifndef LL_RELEASE_FOR_DOWNLOAD // provide developer build only overrides for these control variables that are not // persisted to settings.xml @@ -2095,6 +2114,11 @@ bool LLAppViewer::initConfiguration() } } + if(clp.hasOption("channel")) + { + LLVersionInfo::resetChannel(clp.getOption("channel")[0]); + } + // If we have specified crash on startup, set the global so we'll trigger the crash at the right time if(clp.hasOption("crashonstartup")) @@ -2364,6 +2388,58 @@ bool LLAppViewer::initConfiguration() return true; // Config was successful. } +namespace { + // *TODO - decide if there's a better place for this function. + // do we need a file llupdaterui.cpp or something? -brad + bool notify_update(LLSD const & evt) + { + switch (evt["type"].asInteger()) + { + case LLUpdaterService::DOWNLOAD_COMPLETE: + LLNotificationsUtil::add("DownloadBackground"); + break; + case LLUpdaterService::INSTALL_ERROR: + LLNotificationsUtil::add("FailedUpdateInstall"); + break; + default: + llinfos << "unhandled update event " << evt << llendl; + break; + } + + // let others also handle this event by default + return false; + } +}; + +void LLAppViewer::initUpdater() +{ + // Initialize the updater service. + // Generate URL to the udpater service + // Get Channel + // Get Version + std::string url = gSavedSettings.getString("UpdaterServiceURL"); + std::string channel = LLVersionInfo::getChannel(); + std::string version = LLVersionInfo::getVersion(); + std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion"); + std::string service_path = gSavedSettings.getString("UpdaterServicePath"); + U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod"); + + mUpdater->setAppExitCallback(boost::bind(&LLAppViewer::forceQuit, this)); + mUpdater->initialize(protocol_version, + url, + service_path, + channel, + version); + mUpdater->setCheckPeriod(check_period); + if(gSavedSettings.getBOOL("UpdaterServiceActive")) + { + bool install_if_ready = true; + mUpdater->startChecking(install_if_ready); + } + + LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()); + updater_pump.listen("notify_update", ¬ify_update); +} void LLAppViewer::checkForCrash(void) { @@ -2524,15 +2600,18 @@ void LLAppViewer::cleanupSavedSettings() // save window position if not maximized // as we don't track it in callbacks - BOOL maximized = gViewerWindow->mWindow->getMaximized(); - if (!maximized) + if(NULL != gViewerWindow) { - LLCoordScreen window_pos; - - if (gViewerWindow->mWindow->getPosition(&window_pos)) + BOOL maximized = gViewerWindow->mWindow->getMaximized(); + if (!maximized) { - gSavedSettings.setS32("WindowX", window_pos.mX); - gSavedSettings.setS32("WindowY", window_pos.mY); + LLCoordScreen window_pos; + + if (gViewerWindow->mWindow->getPosition(&window_pos)) + { + gSavedSettings.setS32("WindowX", window_pos.mX); + gSavedSettings.setS32("WindowY", window_pos.mY); + } } } @@ -2555,7 +2634,7 @@ void LLAppViewer::writeSystemInfo() { gDebugInfo["SLLog"] = LLError::logFileName(); - gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName"); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); @@ -2658,7 +2737,7 @@ void LLAppViewer::handleViewerCrash() //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version //to check against no matter what - gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName"); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); @@ -4271,7 +4350,10 @@ void LLAppViewer::disconnectViewer() // This is where we used to call gObjectList.destroy() and then delete gWorldp. // Now we just ask the LLWorld singleton to cleanly shut down. - LLWorld::getInstance()->destroyClass(); + if(LLWorld::instanceExists()) + { + LLWorld::getInstance()->destroyClass(); + } // call all self-registered classes LLDestroyClassList::instance().fireCallbacks(); @@ -4385,7 +4467,7 @@ void LLAppViewer::handleLoginComplete() initMainloopTimeout("Mainloop Init"); // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName"); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); @@ -4491,7 +4573,7 @@ void LLAppViewer::launchUpdater() // *TODO change userserver to be grid on both viewer and sim, since // userserver no longer exists. query_map["userserver"] = LLGridManager::getInstance()->getGridLabel(); - query_map["channel"] = gSavedSettings.getString("VersionChannelName"); + query_map["channel"] = LLVersionInfo::getChannel(); // *TODO constantize this guy // *NOTE: This URL is also used in win_setup/lldownloader.cpp LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index a14ab4362f..aa4256a2bd 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -39,7 +39,7 @@ class LLTextureCache; class LLImageDecodeThread; class LLTextureFetch; class LLWatchdogTimeout; -class LLCommandLineParser; +class LLUpdaterService; struct apr_dso_handle_t; @@ -186,7 +186,7 @@ private: bool initThreads(); // Initialize viewer threads, return false on failure. bool initConfiguration(); // Initialize settings from the command line/config file. - + void initUpdater(); // Initialize the updater service. bool initCache(); // Initialize local client cache. @@ -264,7 +264,14 @@ private: U32 mAvailPhysicalMemInKB ; U32 mAvailVirtualMemInKB ; + + boost::scoped_ptr<LLUpdaterService> mUpdater; + + //--------------------------------------------- + //*NOTE: Mani - legacy updater stuff + // Still useable? public: + //some information for updater typedef struct { @@ -274,6 +281,7 @@ public: static LLUpdaterInfo *sUpdaterInfo ; void launchUpdater(); + //--------------------------------------------- }; // consts from viewer.h diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 8f385160e9..885d553524 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -1092,9 +1092,11 @@ LLChicletPanel::LLChicletPanel(const Params&p) LLChicletPanel::~LLChicletPanel() { - LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton); - LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton); - + if(LLTransientFloaterMgr::instanceExists()) + { + LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton); + LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton); + } } void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){ diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index 2b92b228b3..b4a1457f47 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -166,7 +166,7 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo() gAgent.getSecureSessionID().asString()); keywordArgs.appendString("language", LLUI::getLanguage()); keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy); - keywordArgs.appendString("viewerChannel", gSavedSettings.getString("VersionChannelName")); + keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel()); keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor()); keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor()); keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch()); @@ -241,7 +241,7 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) { keywordArgs.appendString("password", password); } - keywordArgs.appendString("viewerChannel", gSavedSettings.getString("VersionChannelName")); + keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel()); keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor()); keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor()); keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch()); diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 0ee70bcdd1..dc94924da4 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -48,7 +48,8 @@ #include "llviewershadermgr.h" #include "llwaterparammanager.h" -const LLUUID WATER_TEST("2bfd3884-7e27-69b9-ba3a-3e673f680004"); +const LLUUID TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004"); +const LLUUID OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055"); static float sTime; @@ -71,10 +72,14 @@ LLDrawPoolWater::LLDrawPoolWater() : gGL.getTexUnit(0)->bind(mHBTex[1]); mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP); - mWaterImagep = LLViewerTextureManager::getFetchedTexture(WATER_TEST); - mWaterImagep->setNoDelete() ; + + mWaterImagep = LLViewerTextureManager::getFetchedTexture(TRANSPARENT_WATER_TEXTURE); + llassert(mWaterImagep); + mWaterImagep->setNoDelete(); + mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(OPAQUE_WATER_TEXTURE); + llassert(mOpaqueWaterImagep); mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL); - mWaterNormp->setNoDelete() ; + mWaterNormp->setNoDelete(); restoreGL(); } @@ -161,6 +166,14 @@ void LLDrawPoolWater::render(S32 pass) std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater()); + // See if we are rendering water as opaque or not + if (!gSavedSettings.getBOOL("RenderTransparentWater")) + { + // render water for low end hardware + renderOpaqueLegacyWater(); + return; + } + LLGLEnable blend(GL_BLEND); if ((mVertexShaderLevel > 0) && !sSkipScreenCopy) @@ -314,6 +327,87 @@ void LLDrawPoolWater::render(S32 pass) gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } +// for low end hardware +void LLDrawPoolWater::renderOpaqueLegacyWater() +{ + LLVOSky *voskyp = gSky.mVOSkyp; + + stop_glerror(); + + // Depth sorting and write to depth buffer + // since this is opaque, we should see nothing + // behind the water. No blending because + // of no transparency. And no face culling so + // that the underside of the water is also opaque. + LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); + LLGLDisable no_cull(GL_CULL_FACE); + LLGLDisable no_blend(GL_BLEND); + + gPipeline.disableLights(); + + mOpaqueWaterImagep->addTextureStats(1024.f*1024.f); + + // Activate the texture binding and bind one + // texture since all images will have the same texture + gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->bind(mOpaqueWaterImagep); + + // Automatically generate texture coords for water texture + glEnable(GL_TEXTURE_GEN_S); //texture unit 0 + glEnable(GL_TEXTURE_GEN_T); //texture unit 0 + glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + + // Use the fact that we know all water faces are the same size + // to save some computation + + // Slowly move texture coordinates over time so the watter appears + // to be moving. + F32 movement_period_secs = 50.f; + + F32 offset = fmod(gFrameTimeSeconds, movement_period_secs); + + if (movement_period_secs != 0) + { + offset /= movement_period_secs; + } + else + { + offset = 0; + } + + F32 tp0[4] = { 16.f / 256.f, 0.0f, 0.0f, offset }; + F32 tp1[4] = { 0.0f, 16.f / 256.f, 0.0f, offset }; + + glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0); + glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1); + + glColor3f(1.f, 1.f, 1.f); + + for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); + iter != mDrawFace.end(); iter++) + { + LLFace *face = *iter; + if (voskyp->isReflFace(face)) + { + continue; + } + + face->renderIndexed(); + } + + stop_glerror(); + + // Reset the settings back to expected values + glDisable(GL_TEXTURE_GEN_S); //texture unit 0 + glDisable(GL_TEXTURE_GEN_T); //texture unit 0 + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); +} + + void LLDrawPoolWater::renderReflection(LLFace* face) { LLVOSky *voskyp = gSky.mVOSkyp; diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index 2648a5276c..99b541ca5a 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -39,6 +39,7 @@ class LLDrawPoolWater: public LLFacePool protected: LLPointer<LLViewerTexture> mHBTex[2]; LLPointer<LLViewerTexture> mWaterImagep; + LLPointer<LLViewerTexture> mOpaqueWaterImagep; LLPointer<LLViewerTexture> mWaterNormp; public: @@ -80,6 +81,9 @@ public: void renderReflection(LLFace* face); void shade(); + +protected: + void renderOpaqueLegacyWater(); }; void cgErrorCallback(); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 135137069c..8ae3ccbae3 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -213,7 +213,7 @@ LLSD LLFloaterAbout::getInfo() info["VIEWER_VERSION_STR"] = LLVersionInfo::getVersion(); info["BUILD_DATE"] = __DATE__; info["BUILD_TIME"] = __TIME__; - info["CHANNEL"] = gSavedSettings.getString("VersionChannelName"); + info["CHANNEL"] = LLVersionInfo::getChannel(); info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url(); @@ -291,7 +291,7 @@ static std::string get_viewer_release_notes_url() std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); if (! LLStringUtil::endsWith(url, "/")) url += "/"; - url += gSavedSettings.getString("VersionChannelName") + "/"; + url += LLVersionInfo::getChannel() + "/"; url += LLVersionInfo::getShortVersion(); return LLWeb::escapeURL(url); } diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index 234a09d157..d84364a68a 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -41,6 +41,7 @@ #include "llbutton.h" #include "llgroupactions.h" #include "llscrolllistctrl.h" +#include "llstartup.h" #include "lltextbox.h" #include "lluictrlfactory.h" #include "lltrans.h" @@ -171,7 +172,7 @@ void LLPanelGroups::reset() group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); } getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count())); - getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",MAX_AGENT_GROUPS)); + getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups)); init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID()); enableButtons(); @@ -182,7 +183,7 @@ BOOL LLPanelGroups::postBuild() childSetCommitCallback("group list", onGroupList, this); getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count())); - getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",MAX_AGENT_GROUPS)); + getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups)); LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list"); if (list) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c105f023c7..ac940f4f77 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -282,7 +282,8 @@ std::string LLFloaterPreference::sSkin = ""; LLFloaterPreference::LLFloaterPreference(const LLSD& key) : LLFloater(key), mGotPersonalInfo(false), - mOriginalIMViaEmail(false) + mOriginalIMViaEmail(false), + mDoubleClickActionDirty(false) { //Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); @@ -320,6 +321,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); + mCommitCallbackRegistrar.add("Pref.CommitDoubleClickChekbox", boost::bind(&LLFloaterPreference::onDoubleClickCheckBox, this, _1)); + mCommitCallbackRegistrar.add("Pref.CommitRadioDoubleClick", boost::bind(&LLFloaterPreference::onDoubleClickRadio, this)); sSkin = gSavedSettings.getString("SkinCurrent"); @@ -342,6 +345,8 @@ BOOL LLFloaterPreference::postBuild() if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) tabcontainer->selectFirstTab(); + updateDoubleClickControls(); + getChild<LLUICtrl>("cache_location")->setEnabled(FALSE); // make it read-only but selectable (STORM-227) std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); setCacheLocation(cache_location); @@ -475,6 +480,12 @@ void LLFloaterPreference::apply() gAgent.sendAgentUpdateUserInfo(new_im_via_email,mDirectoryVisibility); } } + + if (mDoubleClickActionDirty) + { + updateDoubleClickSettings(); + mDoubleClickActionDirty = false; + } } void LLFloaterPreference::cancel() @@ -501,6 +512,12 @@ void LLFloaterPreference::cancel() // reverts any changes to current skin gSavedSettings.setString("SkinCurrent", sSkin); + + if (mDoubleClickActionDirty) + { + updateDoubleClickControls(); + mDoubleClickActionDirty = false; + } } void LLFloaterPreference::onOpen(const LLSD& key) @@ -1318,6 +1335,68 @@ void LLFloaterPreference::onClickBlockList() } } +void LLFloaterPreference::onDoubleClickCheckBox(LLUICtrl* ctrl) +{ + if (!ctrl) return; + mDoubleClickActionDirty = true; + LLRadioGroup* radio_double_click_action = getChild<LLRadioGroup>("double_click_action"); + if (!radio_double_click_action) return; + // select default value("teleport") in radio-group. + radio_double_click_action->setSelectedIndex(0); + // set radio-group enabled depending on state of checkbox + radio_double_click_action->setEnabled(ctrl->getValue()); +} + +void LLFloaterPreference::onDoubleClickRadio() +{ + mDoubleClickActionDirty = true; +} + +void LLFloaterPreference::updateDoubleClickSettings() +{ + LLCheckBoxCtrl* double_click_action_cb = getChild<LLCheckBoxCtrl>("double_click_chkbox"); + if (!double_click_action_cb) return; + bool enable = double_click_action_cb->getValue().asBoolean(); + + LLRadioGroup* radio_double_click_action = getChild<LLRadioGroup>("double_click_action"); + if (!radio_double_click_action) return; + + // enable double click radio-group depending on state of checkbox + radio_double_click_action->setEnabled(enable); + + if (!enable) + { + // set double click action settings values to false if checkbox was unchecked + gSavedSettings.setBOOL("DoubleClickAutoPilot", false); + gSavedSettings.setBOOL("DoubleClickTeleport", false); + } + else + { + std::string selected = radio_double_click_action->getValue().asString(); + bool teleport_selected = selected == "radio_teleport"; + // set double click action settings values depending on chosen radio-button + gSavedSettings.setBOOL( "DoubleClickTeleport", teleport_selected ); + gSavedSettings.setBOOL( "DoubleClickAutoPilot", !teleport_selected ); + } +} + +void LLFloaterPreference::updateDoubleClickControls() +{ + // check is one of double-click actions settings enabled + bool double_click_action_enabled = gSavedSettings.getBOOL("DoubleClickAutoPilot") || gSavedSettings.getBOOL("DoubleClickTeleport"); + LLCheckBoxCtrl* double_click_action_cb = getChild<LLCheckBoxCtrl>("double_click_chkbox"); + if (double_click_action_cb) + { + // check checkbox if one of double-click actions settings enabled, uncheck otherwise + double_click_action_cb->setValue(double_click_action_enabled); + } + LLRadioGroup* double_click_action_radio = getChild<LLRadioGroup>("double_click_action"); + if (!double_click_action_radio) return; + // set radio-group enabled if one of double-click actions settings enabled + double_click_action_radio->setEnabled(double_click_action_enabled); + // select button in radio-group depending on setting + double_click_action_radio->setSelectedIndex(gSavedSettings.getBOOL("DoubleClickAutoPilot")); +} void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param) { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index e99731b92e..46f50d9a4d 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -95,6 +95,14 @@ protected: void setHardwareDefaults(); // callback for when client turns on shaders void onVertexShaderEnable(); + // callback for changing double click action checkbox + void onDoubleClickCheckBox(LLUICtrl* ctrl); + // callback for selecting double click action radio-button + void onDoubleClickRadio(); + // updates double-click action settings depending on controls from preferences + void updateDoubleClickSettings(); + // updates double-click action controls depending on values from settings.xml + void updateDoubleClickControls(); // This function squirrels away the current values of the controls so that // cancel() can restore them. @@ -145,6 +153,9 @@ public: static void refreshSkin(void* data); private: static std::string sSkin; + // set true if state of double-click action checkbox or radio-group was changed by user + // (reset back to false on apply or cancel) + bool mDoubleClickActionDirty; bool mGotPersonalInfo; bool mOriginalIMViaEmail; diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 159dee7631..b3b7645dd4 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -37,34 +37,120 @@ #include "llagent.h" #include "llhttpclient.h" +#include "llhttpnode.h" #include "lllineeditor.h" #include "lltexteditor.h" #include "llviewerregion.h" -class Responder : public LLHTTPClient::Responder { -public: - Responder(LLTextEditor *output) : mOutput(output) - { - } - - /*virtual*/ - void error(U32 status, const std::string& reason) - { - } - - /*virtual*/ - void result(const LLSD& content) - { - std::string text = content.asString() + "\n\n> "; - mOutput->appendText(text, false); - }; - - LLTextEditor * mOutput; -}; +// Two versions of the sim console API are supported. +// +// SimConsole capability (deprecated): +// This is the initial implementation that is supported by some versions of the +// simulator. It is simple and straight forward, just POST a command and the +// body of the response has the result. This API is deprecated because it +// doesn't allow the sim to use any asynchronous API. +// +// SimConsoleAsync capability: +// This capability replaces the original SimConsole capability. It is similar +// in that the command is POSTed to the SimConsoleAsync cap, but the response +// comes in through the event poll, which gives the simulator more flexibility +// and allows it to perform complex operations without blocking any frames. +// +// We will assume the SimConsoleAsync capability is available, and fall back to +// the SimConsole cap if it is not. The simulator will only support one or the +// other. + +namespace +{ + // Signal used to notify the floater of responses from the asynchronous + // API. + typedef boost::signals2::signal< + void (const std::string& output)> console_reply_signal_t; + console_reply_signal_t sConsoleReplySignal; + + const std::string PROMPT("\n\n> "); + const std::string UNABLE_TO_SEND_COMMAND( + "ERROR: The last command was not received by the server."); + const std::string CONSOLE_UNAVAILABLE( + "ERROR: No console available for this region/simulator."); + const std::string CONSOLE_NOT_SUPPORTED( + "This region does not support the simulator console."); + + // This responder handles the initial response. Unless error() is called + // we assume that the simulator has received our request. Error will be + // called if this request times out. + class AsyncConsoleResponder : public LLHTTPClient::Responder + { + public: + /* virtual */ + void error(U32 status, const std::string& reason) + { + sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); + } + }; + + class ConsoleResponder : public LLHTTPClient::Responder + { + public: + ConsoleResponder(LLTextEditor *output) : mOutput(output) + { + } + + /*virtual*/ + void error(U32 status, const std::string& reason) + { + if (mOutput) + { + mOutput->appendText( + UNABLE_TO_SEND_COMMAND + PROMPT, + false); + } + } + + /*virtual*/ + void result(const LLSD& content) + { + if (mOutput) + { + mOutput->appendText( + content.asString() + PROMPT, false); + } + } + + LLTextEditor * mOutput; + }; + + // This handles responses for console commands sent via the asynchronous + // API. + class ConsoleResponseNode : public LLHTTPNode + { + public: + /* virtual */ + void post( + LLHTTPNode::ResponsePtr reponse, + const LLSD& context, + const LLSD& input) const + { + llinfos << "Received response from the debug console: " + << input << llendl; + sConsoleReplySignal(input["body"].asString()); + } + }; +} LLFloaterRegionDebugConsole::LLFloaterRegionDebugConsole(LLSD const & key) : LLFloater(key), mOutput(NULL) { + mReplySignalConnection = sConsoleReplySignal.connect( + boost::bind( + &LLFloaterRegionDebugConsole::onReplyReceived, + this, + _1)); +} + +LLFloaterRegionDebugConsole::~LLFloaterRegionDebugConsole() +{ + mReplySignalConnection.disconnect(); } BOOL LLFloaterRegionDebugConsole::postBuild() @@ -77,17 +163,21 @@ BOOL LLFloaterRegionDebugConsole::postBuild() mOutput = getChild<LLTextEditor>("region_debug_console_output"); - std::string url = gAgent.getRegion()->getCapability("SimConsole"); - if ( url.size() == 0 ) + std::string url = gAgent.getRegion()->getCapability("SimConsoleAsync"); + if (url.empty()) { - mOutput->appendText("This region does not support the simulator console.\n\n> ", false); + // Fall back to see if the old API is supported. + url = gAgent.getRegion()->getCapability("SimConsole"); + if (url.empty()) + { + mOutput->appendText( + CONSOLE_NOT_SUPPORTED + PROMPT, + false); + return TRUE; + } } - else - { - mOutput->appendText("> ", false); - } - + mOutput->appendText("> ", false); return TRUE; } @@ -96,20 +186,42 @@ void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param) LLLineEditor* input = static_cast<LLLineEditor*>(ctrl); std::string text = input->getText() + "\n"; - - std::string url = gAgent.getRegion()->getCapability("SimConsole"); - - if ( url.size() > 0 ) + std::string url = gAgent.getRegion()->getCapability("SimConsoleAsync"); + if (url.empty()) { - LLHTTPClient::post(url, LLSD(input->getText()), new ::Responder(mOutput)); + // Fall back to the old API + url = gAgent.getRegion()->getCapability("SimConsole"); + if (url.empty()) + { + text += CONSOLE_UNAVAILABLE + PROMPT; + } + else + { + // Using SimConsole (deprecated) + LLHTTPClient::post( + url, + LLSD(input->getText()), + new ConsoleResponder(mOutput)); + } } else { - text += "\nError: No console available for this region/simulator.\n\n> "; + // Using SimConsoleAsync + LLHTTPClient::post( + url, + LLSD(input->getText()), + new AsyncConsoleResponder); } mOutput->appendText(text, false); - input->clear(); } +void LLFloaterRegionDebugConsole::onReplyReceived(const std::string& output) +{ + mOutput->appendText(output + PROMPT, false); +} + +LLHTTPRegistration<ConsoleResponseNode> + gHTTPRegistrationMessageDebugConsoleResponse( + "/message/SimConsoleResponse"); diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h index 69d7773fec..4171a4da6b 100644 --- a/indra/newview/llfloaterregiondebugconsole.h +++ b/indra/newview/llfloaterregiondebugconsole.h @@ -34,6 +34,8 @@ #ifndef LL_LLFLOATERREGIONDEBUGCONSOLE_H #define LL_LLFLOATERREGIONDEBUGCONSOLE_H +#include <boost/signals2.hpp> + #include "llfloater.h" #include "llhttpclient.h" @@ -43,6 +45,7 @@ class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Respo { public: LLFloaterRegionDebugConsole(LLSD const & key); + virtual ~LLFloaterRegionDebugConsole(); // virtual BOOL postBuild(); @@ -50,6 +53,11 @@ public: void onInput(LLUICtrl* ctrl, const LLSD& param); LLTextEditor * mOutput; + + private: + void onReplyReceived(const std::string& output); + + boost::signals2::connection mReplySignalConnection; }; #endif // LL_LLFLOATERREGIONDEBUGCONSOLE_H diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index fc758569e4..c099a3964b 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -87,7 +87,6 @@ LLHUDNameTag::LLHUDNameTag(const U8 type) mZCompare(TRUE), mVisibleOffScreen(FALSE), mOffscreen(FALSE), - mColor(1.f, 1.f, 1.f, 1.f), // mScale(), mWidth(0.f), mHeight(0.f), @@ -109,6 +108,8 @@ LLHUDNameTag::LLHUDNameTag(const U8 type) { LLPointer<LLHUDNameTag> ptr(this); sTextObjects.insert(ptr); + + mColor = LLUIColorTable::instance().getColor("BackgroundChatColor"); } LLHUDNameTag::~LLHUDNameTag() @@ -256,6 +257,7 @@ void LLHUDNameTag::renderText(BOOL for_select) LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f); F32 alpha_factor = 1.f; + mColor = LLUIColorTable::instance().getColor("BackgroundChatColor"); LLColor4 text_color = mColor; if (mDoFade) { @@ -521,7 +523,6 @@ void LLHUDNameTag::renderText(BOOL for_select) x_offset += 1; } - text_color = segment_iter->mColor; text_color.mV[VALPHA] *= alpha_factor; hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, FALSE); diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index e000abda2a..bdc0dfa7e2 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -680,8 +680,6 @@ void LLIMFloater::updateMessages() if (messages.size()) { -// LLUIColor chat_color = LLUIColorTable::instance().getColor("IMChatColor"); - LLSD chat_args; chat_args["use_plain_text_chat_history"] = use_plain_text_chat_history; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index cc48226052..3578c98622 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -537,7 +537,15 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline() void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name) { - mHistoryFileName = av_name.mUsername; + if (av_name.mUsername.empty()) + { + // display names is off, use mDisplayName which will be the legacy name + mHistoryFileName = LLCacheName::buildUsername(av_name.mDisplayName); + } + else + { + mHistoryFileName = av_name.mUsername; + } } void LLIMModel::LLIMSession::buildHistoryFileName() diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 029e700c4c..83a8134580 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -42,6 +42,7 @@ // newview #include "llviewernetwork.h" #include "llviewercontrol.h" +#include "llversioninfo.h" #include "llslurl.h" #include "llstartup.h" #include "llfloaterreg.h" @@ -149,6 +150,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia requested_options.append("newuser-config"); requested_options.append("ui-config"); #endif + requested_options.append("max-agent-groups"); requested_options.append("map-server-url"); requested_options.append("voice-config"); requested_options.append("tutorial_setting"); @@ -181,8 +183,8 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia request_params["read_critical"] = false; // handleTOSResponse request_params["last_exec_event"] = mLastExecEvent; request_params["mac"] = hashed_unique_id_string; - request_params["version"] = gCurrentVersion; // Includes channel name - request_params["channel"] = gSavedSettings.getString("VersionChannelName"); + request_params["version"] = LLVersionInfo::getVersionAndChannel(); // Includes channel name + request_params["channel"] = LLVersionInfo::getChannel(); request_params["id0"] = mSerialNumber; mRequestData.clear(); diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp new file mode 100644 index 0000000000..5c020e6d98 --- /dev/null +++ b/indra/newview/llmainlooprepeater.cpp @@ -0,0 +1,88 @@ +/** + * @file llmachineid.cpp + * @brief retrieves unique machine ids + * + * $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$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llapr.h" +#include "llevents.h" +#include "llmainlooprepeater.h" + + + +// LLMainLoopRepeater +//----------------------------------------------------------------------------- + + +LLMainLoopRepeater::LLMainLoopRepeater(void): + mQueue(0) +{ + ; // No op. +} + + +void LLMainLoopRepeater::start(void) +{ + if(mQueue != 0) return; + + mQueue = new LLThreadSafeQueue<LLSD>(gAPRPoolp, 1024); + mMainLoopConnection = LLEventPumps::instance(). + obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1)); + mRepeaterConnection = LLEventPumps::instance(). + obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1)); +} + + +void LLMainLoopRepeater::stop(void) +{ + mMainLoopConnection.release(); + mRepeaterConnection.release(); + + delete mQueue; + mQueue = 0; +} + + +bool LLMainLoopRepeater::onMainLoop(LLSD const &) +{ + LLSD message; + while(mQueue->tryPopBack(message)) { + std::string pump = message["pump"].asString(); + if(pump.length() == 0 ) continue; // No pump. + LLEventPumps::instance().obtain(pump).post(message["payload"]); + } + return false; +} + + +bool LLMainLoopRepeater::onMessage(LLSD const & event) +{ + try { + mQueue->pushFront(event); + } catch(LLThreadSafeQueueError & e) { + llwarns << "could not repeat message (" << e.what() << ")" << + event.asString() << LL_ENDL; + } + return false; +} diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h new file mode 100644 index 0000000000..f84c0ca94c --- /dev/null +++ b/indra/newview/llmainlooprepeater.h @@ -0,0 +1,65 @@ +/** + * @file llmainlooprepeater.h + * @brief a service for repeating messages on the main loop. + * + * $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$ + */ + +#ifndef LL_LLMAINLOOPREPEATER_H +#define LL_LLMAINLOOPREPEATER_H + + +#include "llsd.h" +#include "llthreadsafequeue.h" + + +// +// A service which creates the pump 'mainlooprepeater' to which any thread can +// post a message that will be re-posted on the main loop. +// +// The posted message should contain two map elements: pump and payload. The +// pump value is a string naming the pump to which the message should be +// re-posted. The payload value is what will be posted to the designated pump. +// +class LLMainLoopRepeater: + public LLSingleton<LLMainLoopRepeater> +{ +public: + LLMainLoopRepeater(void); + + // Start the repeater service. + void start(void); + + // Stop the repeater service. + void stop(void); + +private: + LLTempBoundListener mMainLoopConnection; + LLTempBoundListener mRepeaterConnection; + LLThreadSafeQueue<LLSD> * mQueue; + + bool onMainLoop(LLSD const &); + bool onMessage(LLSD const & event); +}; + + +#endif diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 6658e1d7e8..d38bb5aa4a 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -552,7 +552,7 @@ LLPanelStandStopFlying::LLPanelStandStopFlying() : } // static -inline LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance() +LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance() { static LLPanelStandStopFlying* panel = getStandStopFlyingPanel(); return panel; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 467aefc60f..cf567fb208 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -230,7 +230,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, getChild<LLPanel>("login")->setDefaultBtn("connect_btn"); - std::string channel = gSavedSettings.getString("VersionChannelName"); + std::string channel = LLVersionInfo::getChannel(); std::string version = llformat("%s (%d)", LLVersionInfo::getShortVersion().c_str(), LLVersionInfo::getBuild()); @@ -817,7 +817,7 @@ void LLPanelLogin::loadLoginPage() LLVersionInfo::getShortVersion().c_str(), LLVersionInfo::getBuild()); - char* curl_channel = curl_escape(gSavedSettings.getString("VersionChannelName").c_str(), 0); + char* curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0); char* curl_version = curl_escape(version.c_str(), 0); oStr << "&channel=" << curl_channel; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 904e3dabcc..17433a557b 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -329,15 +329,23 @@ void LLPanelMainInventory::setSortBy(const LLSD& userdata) if (sort_field == "name") { U32 order = getActivePanel()->getSortOrder(); - getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); - + order &= ~LLInventoryFilter::SO_DATE; + + getActivePanel()->setSortOrder( order ); + + gSavedSettings.setU32("InventorySortOrder", order); + gSavedSettings.setBOOL("Inventory.SortByName", TRUE ); gSavedSettings.setBOOL("Inventory.SortByDate", FALSE ); } else if (sort_field == "date") { U32 order = getActivePanel()->getSortOrder(); - getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE ); + order |= LLInventoryFilter::SO_DATE; + + getActivePanel()->setSortOrder( order ); + + gSavedSettings.setU32("InventorySortOrder", order); gSavedSettings.setBOOL("Inventory.SortByName", FALSE ); gSavedSettings.setBOOL("Inventory.SortByDate", TRUE ); @@ -375,6 +383,8 @@ void LLPanelMainInventory::setSortBy(const LLSD& userdata) gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE ); } getActivePanel()->setSortOrder( order ); + + gSavedSettings.setU32("InventorySortOrder", order); } } @@ -915,6 +925,7 @@ void LLPanelMainInventory::initListCommandsHandlers() )); mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2)); + mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2)); mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2)); mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mGearMenuButton->setMenu(mMenuGearDefault); @@ -1000,6 +1011,11 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata) const LLSD arg = "date"; setSortBy(arg); } + if (command_name == "sort_system_folders_to_top") + { + const LLSD arg = "systemfolderstotop"; + setSortBy(arg); + } if (command_name == "show_filters") { toggleFindOptions(); @@ -1173,6 +1189,31 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata) return TRUE; } +BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata) +{ + const std::string command_name = userdata.asString(); + + if (command_name == "sort_by_name") + { + U32 order = getActivePanel()->getSortOrder(); + return ~order & LLInventoryFilter::SO_DATE; + } + + if (command_name == "sort_by_recent") + { + U32 order = getActivePanel()->getSortOrder(); + return order & LLInventoryFilter::SO_DATE; + } + + if (command_name == "sort_system_folders_to_top") + { + U32 order = getActivePanel()->getSortOrder(); + return order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + } + + return FALSE; +} + bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept) { *accept = ACCEPT_NO; diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index d136e2d32e..c2b78ff9ea 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -136,6 +136,7 @@ protected: void onTrashButtonClick(); void onClipboardAction(const LLSD& userdata); BOOL isActionEnabled(const LLSD& command_name); + BOOL isActionChecked(const LLSD& userdata); void onCustomAction(const LLSD& command_name); bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); /** diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index 2334f0cde5..170e23e4c5 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -32,11 +32,13 @@ #include "llchannelmanager.h" #include "llchiclet.h" #include "llfloaterreg.h" +#include "lllslconstants.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llscreenchannel.h" #include "llsyswellwindow.h" #include "lltoastnotifypanel.h" +#include "lltoastscripttextbox.h" #include "lltrans.h" #include "llviewerwindow.h" #include "llimfloater.h" @@ -151,10 +153,18 @@ void LLScriptFloater::createForm(const LLUUID& notification_id) // create new form LLRect toast_rect = getRect(); - // LLToastNotifyPanel will fit own content in vertical direction, - // but it needs an initial rect to properly calculate its width - // Use an initial rect of the script floater to make the floater window more configurable. - mScriptForm = new LLToastNotifyPanel(notification, toast_rect); + if (isScriptTextbox(notification)) + { + mScriptForm = new LLToastScriptTextbox(notification); + } + else + { + // LLToastNotifyPanel will fit own content in vertical direction, + // but it needs an initial rect to properly calculate its width + // Use an initial rect of the script floater to make the floater + // window more configurable. + mScriptForm = new LLToastNotifyPanel(notification, toast_rect); + } addChild(mScriptForm); // position form on floater @@ -564,4 +574,32 @@ void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bo } } +////////////////////////////////////////////////////////////////// + +bool LLScriptFloater::isScriptTextbox(LLNotificationPtr notification) +{ + // get a form for the notification + LLNotificationFormPtr form(notification->getForm()); + + if (form) + { + // get number of elements in the form + int num_options = form->getNumElements(); + + // if ANY of the buttons have the magic lltextbox string as + // name, then treat the whole dialog as a simple text entry + // box (i.e. mixed button and textbox forms are not supported) + for (int i=0; i<num_options; ++i) + { + LLSD form_element = form->getElement(i); + if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN) + { + return true; + } + } + } + + return false; +} + // EOF diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h index da70bb4334..dc52baa115 100644 --- a/indra/newview/llscriptfloater.h +++ b/indra/newview/llscriptfloater.h @@ -28,6 +28,7 @@ #define LL_SCRIPTFLOATER_H #include "lltransientdockablefloater.h" +#include "llnotificationptr.h" class LLToastNotifyPanel; @@ -203,6 +204,8 @@ protected: void dockToChiclet(bool dock); private: + bool isScriptTextbox(LLNotificationPtr notification); + LLToastNotifyPanel* mScriptForm; LLUUID mNotificationId; LLUUID mObjectId; diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp index 3dce66f394..c76ecae4a2 100644 --- a/indra/newview/llspeakbutton.cpp +++ b/indra/newview/llspeakbutton.cpp @@ -134,8 +134,11 @@ LLSpeakButton::LLSpeakButton(const Params& p) LLSpeakButton::~LLSpeakButton() { - LLTransientFloaterMgr::getInstance()->removeControlView(mSpeakBtn); - LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn); + if(LLTransientFloaterMgr::instanceExists()) + { + LLTransientFloaterMgr::getInstance()->removeControlView(mSpeakBtn); + LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn); + } } void LLSpeakButton::setSpeakToolTip(const std::string& msg) diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp index ede1d6bebe..9b38bf22ff 100644 --- a/indra/newview/llspeakingindicatormanager.cpp +++ b/indra/newview/llspeakingindicatormanager.cpp @@ -308,7 +308,10 @@ void LLSpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker void LLSpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator) { - SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator); + if(SpeakingIndicatorManager::instanceExists()) + { + SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator); + } } // EOF diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 5ee4599200..80cf7e3cd0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -198,6 +198,7 @@ // exported globals // bool gAgentMovementCompleted = false; +S32 gMaxAgentGroups; std::string SCREEN_HOME_FILENAME = "screen_home.bmp"; std::string SCREEN_LAST_FILENAME = "screen_last.bmp"; @@ -3151,6 +3152,18 @@ bool process_login_success_response() LLViewerMedia::openIDSetup(openid_url, openid_token); } + if(response.has("max-agent-groups")) { + std::string max_agent_groups(response["max-agent-groups"]); + gMaxAgentGroups = atoi(max_agent_groups.c_str()); + LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: " + << gMaxAgentGroups << LL_ENDL; + } + else { + gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS; + LL_INFOS("LLStartup") << "using gMaxAgentGroups default: " + << gMaxAgentGroups << LL_ENDL; + } + bool success = false; // JC: gesture loading done below, when we have an asset system // in place. Don't delete/clear gUserCredentials until then. diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index be1043cf91..b3d9ef1dcc 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -70,6 +70,7 @@ typedef enum { // exported symbols extern bool gAgentMovementCompleted; +extern S32 gMaxAgentGroups; extern LLPointer<LLViewerTexture> gStartTexture; class LLStartUp diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 371aad64bb..563c27c4d7 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -60,7 +60,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLGroupData groupData; if (!gAgent.getGroupData(payload["group_id"].asUUID(),groupData)) { - llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl; + llwarns << "Group notice for unknown group: " << payload["group_id"].asUUID() << llendl; } //group icon diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index 9017f5ec55..3f7dc24ade 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -33,6 +33,7 @@ // library includes #include "lldbstrings.h" +#include "lllslconstants.h" #include "llnotifications.h" #include "lluiconstants.h" #include "llrect.h" @@ -70,11 +71,11 @@ mCloseNotificationOnDestroy(true) mControlPanel = getChild<LLPanel>("control_panel"); BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth"); // customize panel's attributes - // is it intended for displaying a tip + // is it intended for displaying a tip? mIsTip = notification->getType() == "notifytip"; - // is it a script dialog + // is it a script dialog? mIsScriptDialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup"); - // is it a caution + // is it a caution? // // caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the // notify xml template specifies that it is a caution @@ -139,6 +140,12 @@ mCloseNotificationOnDestroy(true) LLSD form_element = form->getElement(i); if (form_element["type"].asString() != "button") { + // not a button. + continue; + } + if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN) + { + // a textbox pretending to be a button. continue; } LLButton* new_button = createButton(form_element, TRUE); @@ -159,7 +166,7 @@ mCloseNotificationOnDestroy(true) if(h_pad < 2*HPAD) { /* - * Probably it is a scriptdialog toast + * Probably it is a scriptdialog toast * for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons. * In last case set default h_pad to avoid heaping of buttons */ @@ -261,7 +268,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt } else if (mIsScriptDialog && is_ignore_btn) { - // this is ignore button,make it smaller + // this is ignore button, make it smaller p.rect.height = BTN_HEIGHT_SMALL; p.rect.width = 1; p.auto_resize = true; diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp new file mode 100644 index 0000000000..c013f521cc --- /dev/null +++ b/indra/newview/lltoastscripttextbox.cpp @@ -0,0 +1,109 @@ +/** + * @file lltoastscripttextbox.cpp + * @brief Panel for script llTextBox dialogs + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltoastscripttextbox.h" + +#include "llfocusmgr.h" + +#include "llbutton.h" +#include "llnotifications.h" +#include "llviewertexteditor.h" + +#include "llavatarnamecache.h" +#include "lluiconstants.h" +#include "llui.h" +#include "llviewercontrol.h" +#include "lltrans.h" +#include "llstyle.h" + +#include "llglheaders.h" +#include "llagent.h" + +const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 7; + +LLToastScriptTextbox::LLToastScriptTextbox(LLNotificationPtr& notification) +: LLToastNotifyPanel(notification) +{ + buildFromFile( "panel_notify_textbox.xml"); + + const LLSD& payload = notification->getPayload(); + + //message body + const std::string& message = payload["message"].asString(); + + LLViewerTextEditor* pMessageText = getChild<LLViewerTextEditor>("message"); + pMessageText->clear(); + + LLStyle::Params style; + style.font = pMessageText->getDefaultFont(); + pMessageText->appendText(message, TRUE, style); + + //submit button + LLButton* pSubmitBtn = getChild<LLButton>("btn_submit"); + pSubmitBtn->setClickedCallback((boost::bind(&LLToastScriptTextbox::onClickSubmit, this))); + setDefaultBtn(pSubmitBtn); + + S32 maxLinesCount; + std::istringstream ss( getString("message_max_lines_count") ); + if (!(ss >> maxLinesCount)) + { + maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT; + } + //snapToMessageHeight(pMessageText, maxLinesCount); +} + +// virtual +LLToastScriptTextbox::~LLToastScriptTextbox() +{ +} + +void LLToastScriptTextbox::close() +{ + die(); +} + +#include "lllslconstants.h" +void LLToastScriptTextbox::onClickSubmit() +{ + LLViewerTextEditor* pMessageText = getChild<LLViewerTextEditor>("message"); + + if (pMessageText) + { + LLSD response = mNotification->getResponseTemplate(); + response[TEXTBOX_MAGIC_TOKEN] = pMessageText->getText(); + if (response[TEXTBOX_MAGIC_TOKEN].asString().empty()) + { + // so we can distinguish between a successfully + // submitted blank textbox, and an ignored toast + response[TEXTBOX_MAGIC_TOKEN] = true; + } + mNotification->respond(response); + close(); + llwarns << response << llendl; + } +} diff --git a/indra/newview/lltoastscripttextbox.h b/indra/newview/lltoastscripttextbox.h new file mode 100644 index 0000000000..ae3b545e0a --- /dev/null +++ b/indra/newview/lltoastscripttextbox.h @@ -0,0 +1,58 @@ +/** + * @file lltoastscripttextbox.h + * @brief Panel for script llTextBox dialogs + * + * $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$ + */ + +#ifndef LL_LLTOASTSCRIPTTEXTBOX_H +#define LL_LLTOASTSCRIPTTEXTBOX_H + +#include "lltoastnotifypanel.h" +#include "llnotificationptr.h" + +class LLButton; + +/** + * Toast panel for scripted llTextbox notifications. + */ +class LLToastScriptTextbox +: public LLToastNotifyPanel +{ +public: + void close(); + + static bool onNewNotification(const LLSD& notification); + + // Non-transient messages. You can specify non-default button + // layouts (like one for script dialogs) by passing various + // numbers in for "layout". + LLToastScriptTextbox(LLNotificationPtr& notification); + + /*virtual*/ ~LLToastScriptTextbox(); +protected: + void onClickSubmit(); +private: + static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT; +}; + +#endif diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp index 78dd602f39..6deab96b45 100644 --- a/indra/newview/lltransientfloatermgr.cpp +++ b/indra/newview/lltransientfloatermgr.cpp @@ -36,8 +36,11 @@ LLTransientFloaterMgr::LLTransientFloaterMgr() { - gViewerWindow->getRootView()->addMouseDownCallback(boost::bind( + if(gViewerWindow) + { + gViewerWindow->getRootView()->addMouseDownCallback(boost::bind( &LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3)); + } mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(GLOBAL, std::set<LLView*>())); mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(DOCKED, std::set<LLView*>())); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 050e34ade9..8ccfdb071b 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -36,7 +36,7 @@ #include "llbufferstream.h" #include "llui.h" -#include "llversionviewer.h" +#include "llversioninfo.h" #include "llviewercontrol.h" #include "jsoncpp/reader.h" @@ -64,11 +64,11 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std getTranslateUrl(url, from_lang, to_lang, mesg); std::string user_agent = llformat("%s %d.%d.%d (%d)", - LL_CHANNEL, - LL_VERSION_MAJOR, - LL_VERSION_MINOR, - LL_VERSION_PATCH, - LL_VERSION_BUILD ); + LLVersionInfo::getChannel().c_str(), + LLVersionInfo::getMajor(), + LLVersionInfo::getMinor(), + LLVersionInfo::getPatch(), + LLVersionInfo::getBuild()); if (!m_Header.size()) { diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 733d05834a..53994c68f2 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -95,9 +95,42 @@ const std::string &LLVersionInfo::getShortVersion() return version; } +namespace +{ + /// Storage of the channel name the viewer is using. + // The channel name is set by hardcoded constant, + // or by calling LLVersionInfo::resetChannel() + std::string sWorkingChannelName(LL_CHANNEL); + + // Storage for the "version and channel" string. + // This will get reset too. + std::string sVersionChannel(""); +} + +//static +const std::string &LLVersionInfo::getVersionAndChannel() +{ + if (sVersionChannel.empty()) + { + // cache the version string + std::ostringstream stream; + stream << LLVersionInfo::getVersion() + << " " + << LLVersionInfo::getChannel(); + sVersionChannel = stream.str(); + } + + return sVersionChannel; +} + //static const std::string &LLVersionInfo::getChannel() { - static std::string name(LL_CHANNEL); - return name; + return sWorkingChannelName; +} + +void LLVersionInfo::resetChannel(const std::string& channel) +{ + sWorkingChannelName = channel; + sVersionChannel.clear(); // Reset version and channel string til next use. } diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index e468b6ae4e..36defbcd68 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -58,8 +58,15 @@ public: /// return the viewer version as a string like "2.0.0" static const std::string &getShortVersion(); + /// return the viewer version and channel as a string + /// like "2.0.0.200030 Second Life Release" + static const std::string &getVersionAndChannel(); + /// return the channel name, e.g. "Second Life" static const std::string &getChannel(); + + /// reset the channel name used by the viewer. + static void resetChannel(const std::string& channel); }; #endif diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index fbec2a7b9e..622d09c600 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -70,6 +70,7 @@ #include "llpaneloutfitsinventory.h" #include "llpanellogin.h" #include "llpaneltopinfobar.h" +#include "llupdaterservice.h" #ifdef TOGGLE_HACKED_GODLIKE_VIEWER BOOL gHackGodmode = FALSE; @@ -82,7 +83,6 @@ LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings std::string gLastRunVersion; -std::string gCurrentVersion; extern BOOL gResizeScreenTexture; extern BOOL gDebugGL; @@ -117,10 +117,23 @@ static bool handleSetShaderChanged(const LLSD& newvalue) gBumpImageList.destroyGL(); gBumpImageList.restoreGL(); + // Changing shader also changes the terrain detail to high, reflect that change here + if (newvalue.asBoolean()) + { + // shaders enabled, set terrain detail to high + gSavedSettings.setS32("RenderTerrainDetail", 1); + } + // else, leave terrain detail as is LLViewerShaderMgr::instance()->setShaders(); return true; } +bool handleRenderTransparentWaterChanged(const LLSD& newvalue) +{ + LLWorld::getInstance()->updateWaterObjects(); + return true; +} + static bool handleReleaseGLBufferChanged(const LLSD& newvalue) { if (gPipeline.isInit()) @@ -489,6 +502,18 @@ bool toggle_show_object_render_cost(const LLSD& newvalue) return true; } +void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value) +{ + if(new_value.asBoolean()) + { + LLUpdaterService().startChecking(); + } + else + { + LLUpdaterService().stopChecking(); + } +} + //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() @@ -636,7 +661,9 @@ void settings_setup_listeners() gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2)); gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2)); gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2)); + gSavedSettings.getControl("UpdaterServiceActive")->getSignal()->connect(&toggle_updater_service_active); gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2)); + gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index 22b48f8906..d7191f5c8d 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -57,7 +57,5 @@ extern LLControlGroup gCrashSettings; // Set after settings loaded extern std::string gLastRunVersion; -extern std::string gCurrentVersion; - #endif // LL_LLVIEWERCONTROL_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 31cf0acdd7..fae4eb3c05 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -492,7 +492,7 @@ std::string LLViewerMedia::getCurrentUserAgent() // Just in case we need to check browser differences in A/B test // builds. - std::string channel = gSavedSettings.getString("VersionChannelName"); + std::string channel = LLVersionInfo::getChannel(); // append our magic version number string to the browser user agent id // See the HTTP 1.0 and 1.1 specifications for allowed formats: diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 92a78c155e..b7432cd1ec 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6500,16 +6500,6 @@ class LLToggleControl : public view_listener_t std::string control_name = userdata.asString(); BOOL checked = gSavedSettings.getBOOL( control_name ); gSavedSettings.setBOOL( control_name, !checked ); - - // Doubleclick actions - there can be only one - if ((control_name == "DoubleClickAutoPilot") && !checked) - { - gSavedSettings.setBOOL( "DoubleClickTeleport", FALSE ); - } - else if ((control_name == "DoubleClickTeleport") && !checked) - { - gSavedSettings.setBOOL( "DoubleClickAutoPilot", FALSE ); - } return true; } }; @@ -7805,6 +7795,9 @@ void initialize_menus() view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); + // Me > Movement + view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying"); + // World menu commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL)); view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); @@ -7878,9 +7871,6 @@ void initialize_menus() // Advanced Other Settings view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); - - // Advanced > Shortcuts - view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying"); // Advanced > Render > Types view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7c0fc681a4..5cbd5ffa0b 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -39,6 +39,7 @@ #include "llfloaterreg.h" #include "llfollowcamparams.h" #include "llinventorydefines.h" +#include "lllslconstants.h" #include "llregionhandle.h" #include "llsdserialize.h" #include "llteleportflags.h" @@ -638,7 +639,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response) if(option == 0 && !group_id.isNull()) { // check for promotion or demotion. - S32 max_groups = MAX_AGENT_GROUPS; + S32 max_groups = gMaxAgentGroups; if(gAgent.isInGroup(group_id)) ++max_groups; if(gAgent.mGroups.count() < max_groups) @@ -3031,6 +3032,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) } else { + args["NAME"] = source_name; LLNotificationsUtil::add("OfferCallingCard", args, payload); } } @@ -6435,8 +6437,22 @@ const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n"; bool callback_script_dialog(const LLSD& notification, const LLSD& response) { LLNotificationForm form(notification["form"]); - std::string button = LLNotification::getSelectedOptionName(response); - S32 button_idx = LLNotification::getSelectedOption(notification, response); + + std::string rtn_text; + S32 button_idx; + button_idx = LLNotification::getSelectedOption(notification, response); + if (response[TEXTBOX_MAGIC_TOKEN].isDefined()) + { + if (response[TEXTBOX_MAGIC_TOKEN].isString()) + rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString(); + else + rtn_text.clear(); // bool marks empty string + } + else + { + rtn_text = LLNotification::getSelectedOptionName(response); + } + // Didn't click "Ignore" if (button_idx != -1) { @@ -6449,7 +6465,7 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response) msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); msg->addS32("ButtonIndex", button_idx); - msg->addString("ButtonLabel", button); + msg->addString("ButtonLabel", rtn_text); msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e693fc65ea..c73b5fdd40 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1400,7 +1400,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("SendUserReportWithScreenshot"); capabilityNames.append("ServerReleaseNotes"); capabilityNames.append("SetDisplayName"); - capabilityNames.append("SimConsole"); + capabilityNames.append("SimConsoleAsync"); capabilityNames.append("StartGroupProposal"); capabilityNames.append("TextureStats"); capabilityNames.append("UntrustedSimulatorMessage"); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 46c78e2bb4..402f00c5e7 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -48,6 +48,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llviewercontrol.h" +#include "llversioninfo.h" #include "llfloatertools.h" #include "lldebugview.h" #include "llfasttimerview.h" @@ -749,7 +750,7 @@ void send_stats() // send fps only for time app spends in foreground agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); - agent["version"] = gCurrentVersion; + agent["version"] = LLVersionInfo::getVersionAndChannel(); std::string language = LLUI::getLanguage(); agent["language"] = language; diff --git a/indra/newview/llviewerthrottle.cpp b/indra/newview/llviewerthrottle.cpp index b614ccdbc2..5147272122 100644 --- a/indra/newview/llviewerthrottle.cpp +++ b/indra/newview/llviewerthrottle.cpp @@ -46,7 +46,7 @@ const F32 MAX_FRACTIONAL = 1.5f; const F32 MIN_FRACTIONAL = 0.2f; const F32 MIN_BANDWIDTH = 50.f; -const F32 MAX_BANDWIDTH = 1500.f; +const F32 MAX_BANDWIDTH = 3000.f; const F32 STEP_FRACTIONAL = 0.1f; const F32 TIGHTEN_THROTTLE_THRESHOLD = 3.0f; // packet loss % per s const F32 EASE_THROTTLE_THRESHOLD = 0.5f; // packet loss % per s diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 743def4a0c..a7790243ed 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2266,6 +2266,20 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) return TRUE; } + // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, + // no view has keyboard focus, this is a printable character key (and no modifier key is + // pressed except shift), then give focus to nearby chat (STORM-560) + if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && + !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) + { + LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL; + if (chat_editor) + { + // passing NULL here, character will be added later when it is handled by character handler. + LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL); + return TRUE; + } + } // give menus a chance to handle unmodified accelerator keys if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 9280eb8fa4..71f08ec36d 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -60,8 +60,10 @@ const U32 WIDTH = (N_RES * WAVE_STEP); //128.f //64 // width of wave tile, in const F32 WAVE_STEP_INV = (1. / WAVE_STEP); -LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -: LLStaticViewerObject(id, pcode, regionp), +LLVOWater::LLVOWater(const LLUUID &id, + const LLPCode pcode, + LLViewerRegion *regionp) : + LLStaticViewerObject(id, pcode, regionp), mRenderType(LLPipeline::RENDER_TYPE_WATER) { // Terrain must draw during selection passes so it can block objects behind it. @@ -153,11 +155,17 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) LLStrider<U16> indicesp; U16 index_offset; - S32 size = 16; - S32 num_quads = size*size; - face->setSize(4*num_quads, 6*num_quads); + // A quad is 4 vertices and 6 indices (making 2 triangles) + static const unsigned int vertices_per_quad = 4; + static const unsigned int indices_per_quad = 6; + const S32 size = gSavedSettings.getBOOL("RenderTransparentWater") ? 16 : 1; + + const S32 num_quads = size * size; + face->setSize(vertices_per_quad * num_quads, + indices_per_quad * num_quads); + if (face->mVertexBuffer.isNull()) { face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index f8660419b4..aeea2306f7 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -400,9 +400,6 @@ name="HighlightParentColor" value="0.67 0.83 0.96 1" /> <color - name="IMChatColor" - reference="LtGray" /> - <color name="IMHistoryBgColor" reference="Unused?" /> <color diff --git a/indra/newview/skins/default/xui/da/floater_bumps.xml b/indra/newview/skins/default/xui/da/floater_bumps.xml index d22de6e7f1..1db2e93fd2 100644 --- a/indra/newview/skins/default/xui/da/floater_bumps.xml +++ b/indra/newview/skins/default/xui/da/floater_bumps.xml @@ -4,19 +4,19 @@ Ingen registreret </floater.string> <floater.string name="bump"> - [TIME] [FIRST] [LAST] ramte dig + [TIME] [NAME] ramte dig </floater.string> <floater.string name="llpushobject"> - [TIME] [FIRST] [LAST] skubbede dig med et script + [TIME] [NAME] skubbede dig med et script </floater.string> <floater.string name="selected_object_collide"> - [TIME] [FIRST] [LAST] ramte dig med et objekt + [TIME] [NAME] ramte dig med et objekt </floater.string> <floater.string name="scripted_object_collide"> - [TIME] [FIRST] [LAST] ramte dig med et scriptet objekt + [TIME] [NAME] ramte dig med et scriptet objekt </floater.string> <floater.string name="physical_object_collide"> - [TIME] [FIRST] [LAST] ramte dig med et fysisk objekt + [TIME] [NAME] ramte dig med et fysisk objekt </floater.string> <floater.string name="timeStr"> [[hour,datetime,slt]:[min,datetime,slt]] diff --git a/indra/newview/skins/default/xui/da/floater_pay.xml b/indra/newview/skins/default/xui/da/floater_pay.xml index b2cdc0bfe7..5ebdd3f084 100644 --- a/indra/newview/skins/default/xui/da/floater_pay.xml +++ b/indra/newview/skins/default/xui/da/floater_pay.xml @@ -11,7 +11,7 @@ </text> <icon name="icon_person" tool_tip="Person"/> <text name="payee_name"> - [FIRST] [LAST] + Test Name That Is Extremely Long To Check Clipping </text> <button label="L$1" label_selected="L$1" name="fastpay 1"/> <button label="L$5" label_selected="L$5" name="fastpay 5"/> diff --git a/indra/newview/skins/default/xui/da/floater_pay_object.xml b/indra/newview/skins/default/xui/da/floater_pay_object.xml index 368d678681..260b257c33 100644 --- a/indra/newview/skins/default/xui/da/floater_pay_object.xml +++ b/indra/newview/skins/default/xui/da/floater_pay_object.xml @@ -8,7 +8,7 @@ </string> <icon name="icon_person" tool_tip="Person"/> <text name="payee_name"> - [FIRST] [LAST] + Ericacita Moostopolison </text> <text name="object_name_label"> Via objekt: diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 917b7cc21e..a8849861cf 100644 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -931,10 +931,10 @@ Henvis til dette fra en hjemmeside for at give andre nem adgang til denne lokati Erstattet manglende tøj/kropsdele med standard. </notification> <notification name="FriendOnline"> - [FIRST] [LAST] er Online + [NAME] er Online </notification> <notification name="FriendOffline"> - [FIRST] [LAST] er Offline + [NAME] er Offline </notification> <notification name="AddSelfFriend"> Selvom du nok er meget sød, kan du ikke tilføje dig selv som ven. @@ -1002,9 +1002,6 @@ Prøv venligst igen. <notification name="CannotRemoveProtectedCategories"> Du kan ikke fjerne beskyttede kategorier. </notification> - <notification name="OfferedCard"> - Du har tilbudt et visitkort til [FIRST] [LAST] - </notification> <notification name="UnableToBuyWhileDownloading"> Ikke muligt at købe, imens genstandens data hentes. Prøv venligst igen. @@ -1120,7 +1117,7 @@ Prøv venligst at geninstallere plugin eller kontakt leverandøren hvis probleme De genstande du ejer pÃ¥ det valgte stykke land er blevet returneret til din beholdning. </notification> <notification name="OtherObjectsReturned"> - Genstandene pÃ¥ det valgte stykke land der er ejet af [FIRST] [LAST] er blevet returneret til hans eller hendes beholdning. + Genstandene pÃ¥ det valgte stykke land der er ejet af [NAME] er blevet returneret til hans eller hendes beholdning. </notification> <notification name="OtherObjectsReturned2"> Objekterne i den valgte parcel, ejet af beboeren '[NAME]', er blevet returneret til deres ejer. @@ -1321,7 +1318,7 @@ Prøv igen om lidt. Tilbud om venskab afvist. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] tilbyder dig et visitkort. + [NAME] tilbyder dig et visitkort. Dette vil lave et bogmørke i din beholding, sÃ¥ du hurtigt kan sende en IM til denne beboer. <form name="form"> <button name="Accept" text="Acceptér"/> @@ -1380,7 +1377,7 @@ Tillad denne anmodning? </form> </notification> <notification name="ScriptDialog"> - [FIRST] [LAST]'s '[TITLE]' + [NAME]'s '<nolink>[TITLE]</nolink>' [MESSAGE] <form name="form"> <button name="Ignore" text="Ignorér"/> @@ -1424,13 +1421,13 @@ Klik pÃ¥ Acceptér for at deltage eller Afvis for at afvise invitationen. Klik p </form> </notification> <notification name="AutoUnmuteByIM"> - [FIRST] [LAST] fik tilsendt en personlig besked og er dermed automatisk ikke mere blokeret. + [NAME] fik tilsendt en personlig besked og er dermed automatisk ikke mere blokeret. </notification> <notification name="AutoUnmuteByMoney"> - [FIRST] [LAST] blev givet penge og er dermed automatisk ikke mere blokeret. + [NAME] blev givet penge og er dermed automatisk ikke mere blokeret. </notification> <notification name="AutoUnmuteByInventory"> - [FIRST] [LAST] blev tilbudt en genstand og er dermed automatisk ikke mere blokeret. + [NAME] blev tilbudt en genstand og er dermed automatisk ikke mere blokeret. </notification> <notification name="VoiceInviteGroup"> [NAME] har has sluttet sig til stemme-chaten i gruppen [GROUP]. diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index afd933c7fa..1c583f2e95 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -3469,7 +3469,7 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE]. Du er den eneste deltager i denne samtale </string> <string name="offline_message"> - [FIRST] [LAST] er ikke logget pÃ¥. + [NAME] er ikke logget pÃ¥. </string> <string name="invite_message"> Tryk pÃ¥ [BUTTON NAME] knappen for at acceptére/tilslutte til denne stemme chat. diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index c2ca0c2fb0..a904604b62 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2481,7 +2481,7 @@ Versuchen Sie es in einigen Minuten erneut. Ihr Freundschaftsangebot wurde abgelehnt. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] bietet Ihnen ihre/seine Visitenkarte an. + [NAME] bietet Ihnen ihre/seine Visitenkarte an. Ihrem Inventar wird ein Lesezeichen erstellt, damit Sie diesem Einwohner einfach eine IM schicken können. <form name="form"> <button name="Accept" text="Akzeptieren"/> diff --git a/indra/newview/skins/default/xui/de/panel_edit_profile.xml b/indra/newview/skins/default/xui/de/panel_edit_profile.xml index 7f6054dd60..be124050e8 100644 --- a/indra/newview/skins/default/xui/de/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/de/panel_edit_profile.xml @@ -54,7 +54,7 @@ <text name="my_account_link" value="[[URL] Meine Startseite aufrufen]"/> <text name="title_partner_text" value="Mein Partner:"/> <panel name="partner_data_panel"> - <text initial_value="(wird in Datenbank gesucht)" name="partner_text" value="[FIRST] [LAST]"/> + <text initial_value="(wird in Datenbank gesucht)" name="partner_text"/> </panel> <text name="partner_edit_link" value="[[URL] bearbeiten]"/> </panel> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index f361cb7f8e..e70e1eb61b 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -160,7 +160,7 @@ layout="topleft" left="10" height="70" - top="54" + top="59" name="focus_radio_group"> <radio_item top_pad="6" @@ -197,7 +197,7 @@ <radio_group left="10" height="70" - top="54" + top="59" layout="topleft" name="move_radio_group"> <radio_item @@ -931,7 +931,7 @@ height="23" image_overlay="Edit_Wrench" layout="topleft" - left_pad="3" + left_pad="13" name="button set group" tab_stop="false" tool_tip="Choose a group to share this object's permissions" @@ -944,7 +944,7 @@ name="checkbox share with group" tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions." top_pad="10" - left="106" + left="100" width="87" /> <button follows="top|left" @@ -953,7 +953,7 @@ label_selected="Deed" layout="topleft" name="button deed" - left_pad="3" + left_pad="19" tool_tip="Deeding gives this item away with next owner permissions. Group shared objects can be deeded by a group officer." width="80" /> <text @@ -974,7 +974,7 @@ layout="topleft" name="clickaction" width="148" - left_pad="0"> + left_pad="10"> <combo_box.item label="Touch (default)" name="Touch/grab(default)" @@ -1009,7 +1009,7 @@ width="100" /> <!-- NEW SALE TYPE COMBO BOX --> <combo_box - left_pad="0" + left_pad="10" layout="topleft" follows="left|top" allow_text_entry="false" @@ -1041,7 +1041,7 @@ even though the user gets a free copy. decimal_digits="0" increment="1" top_pad="8" - left="108" + left="118" control_name="Edit Cost" name="Edit Cost" label="Price: L$" diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml index 679d5bc82e..7fa4cd840a 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml @@ -16,22 +16,39 @@ </menu_item_call> <menu_item_separator layout="topleft" /> - <menu_item_call + <menu_item_check label="Sort by Name" layout="topleft" name="sort_by_name"> <on_click function="Inventory.GearDefault.Custom.Action" parameter="sort_by_name" /> - </menu_item_call> - <menu_item_call + <on_check + function="Inventory.GearDefault.Check" + parameter="sort_by_name" /> + </menu_item_check> + <menu_item_check label="Sort by Most Recent" layout="topleft" name="sort_by_recent"> <on_click function="Inventory.GearDefault.Custom.Action" parameter="sort_by_recent" /> - </menu_item_call> + <on_check + function="Inventory.GearDefault.Check" + parameter="sort_by_recent" /> + </menu_item_check> + <menu_item_check + label="Sort System Folders to Top" + layout="topleft" + name="sort_system_folders_to_top"> + <on_click + function="Inventory.GearDefault.Custom.Action" + parameter="sort_system_folders_to_top" /> + <on_check + function="Inventory.GearDefault.Check" + parameter="sort_system_folders_to_top" /> + </menu_item_check> <menu_item_separator layout="topleft" /> <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 9fcf952bf0..0aaed36cf0 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -94,6 +94,49 @@ function="Floater.Toggle" parameter="voice_effect" /> </menu_item_check> + <menu + create_jump_keys="true" + label="Movement" + name="Movement" + tear_off="true"> + <menu_item_call + label="Sit Down" + layout="topleft" + shortcut="alt|shift|S" + name="Sit Down Here"> + <menu_item_call.on_click + function="Self.SitDown" + parameter="" /> + <menu_item_call.on_enable + function="Self.EnableSitDown" /> + </menu_item_call> + <menu_item_check + label="Fly" + name="Fly" + shortcut="Home"> + <menu_item_check.on_check + function="Agent.getFlying" /> + <menu_item_check.on_click + function="Agent.toggleFlying" /> + <menu_item_check.on_enable + function="Agent.enableFlying" /> + </menu_item_check> + <menu_item_check + label="Always Run" + name="Always Run" + shortcut="control|R"> + <menu_item_check.on_check + function="World.CheckAlwaysRun" /> + <menu_item_check.on_click + function="World.AlwaysRun" /> + </menu_item_check> + <menu_item_call + label="Stop Animating Me" + name="Stop Animating My Avatar"> + <menu_item_call.on_click + function="Tools.StopAllAnimations" /> + </menu_item_call> + </menu> <menu create_jump_keys="true" label="My Status" @@ -996,12 +1039,6 @@ tear_off="true" visible="false"> <menu_item_call - label="Stop Animating Me" - name="Stop Animating My Avatar"> - <menu_item_call.on_click - function="Tools.StopAllAnimations" /> - </menu_item_call> - <menu_item_call label="Rebake Textures" name="Rebake Texture" shortcut="control|alt|R"> @@ -1553,29 +1590,6 @@ <menu_item_separator/> - <menu_item_check - label="Always Run" - name="Always Run" - shortcut="control|R"> - <menu_item_check.on_check - function="World.CheckAlwaysRun" /> - <menu_item_check.on_click - function="World.AlwaysRun" /> - </menu_item_check> - <menu_item_check - label="Fly" - name="Fly" - shortcut="Home"> - <menu_item_check.on_check - function="Agent.getFlying" /> - <menu_item_check.on_click - function="Agent.toggleFlying" /> - <menu_item_check.on_enable - function="Agent.enableFlying" /> - </menu_item_check> - - <menu_item_separator/> - <menu_item_call label="Close Window" name="Close Window" @@ -2661,24 +2675,16 @@ function="Advanced.PrintTextureMemoryStats" /> </menu_item_call> <menu_item_check - label="Double-ClickAuto-Pilot" - name="Double-ClickAuto-Pilot"> - <menu_item_check.on_check - function="CheckControl" - parameter="DoubleClickAutoPilot" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="DoubleClickAutoPilot" /> - </menu_item_check> - <menu_item_check - label="Double-Click Teleport" - name="DoubleClick Teleport"> + label="Region Debug Console" + name="Region Debug Console" + shortcut="control|shift|`" + use_mac_ctrl="true"> <menu_item_check.on_check - function="CheckControl" - parameter="DoubleClickTeleport" /> + function="Floater.Visible" + parameter="region_debug_console" /> <menu_item_check.on_click - function="ToggleControl" - parameter="DoubleClickTeleport" /> + function="Floater.Toggle" + parameter="region_debug_console" /> </menu_item_check> <menu_item_check label="Region Debug Console" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a0fd0a13cc..9536bf2cf7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2871,6 +2871,25 @@ Download to your Applications folder? <notification icon="alertmodal.tga" + name="FailedUpdateInstall" + type="alertmodal"> +An error occurred installing the viewer update. +Please download and install the latest viewer from +http://secondlife.com/download. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + <notification + icon="notifytip.tga" + name="DownloadBackground" + type="notifytip"> +An updated version of [APP_NAME] has been downloaded. +It will be applied the next time you restart [APP_NAME] + </notification> + + <notification + icon="alertmodal.tga" name="DeedObjectToGroup" type="alertmodal"> Deeding this object will cause the group to: @@ -5539,7 +5558,7 @@ Friendship offer declined. name="OfferCallingCard" persist="true" type="notify"> -[FIRST] [LAST] is offering their calling card. +[NAME] is offering their calling card. This will add a bookmark in your inventory so you can quickly IM this Resident. <form name="form"> <button diff --git a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml new file mode 100644 index 0000000000..4634eeed46 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + background_visible="true" + height="230" + label="instant_message" + layout="topleft" + left="0" + name="panel_notify_textbox" + top="0" + width="305"> + <string + name="message_max_lines_count" + value="7" /> + <panel + bevel_style="none" + follows="left|right|top" + height="150" + label="info_panel" + layout="topleft" + left="0" + name="info_panel" + top="0" + width="305"> + <text_editor + parse_urls="true" + enabled="true" + follows="all" + height="60" + layout="topleft" + left="25" + max_length="250" + name="message" + parse_highlights="true" + read_only="false" + top="40" + type="string" + use_ellipses="true" + value="message" + width="260" + word_wrap="true" > + </text_editor> + parse_urls="false" + <button + top="110" + follows="top|left" + height="20" + label="Submit" + layout="topleft" + left="25" + name="btn_submit" + width="70" /> + </panel> + <panel + background_visible="false" + follows="left|right|bottom" + height="0" + width="290" + label="control_panel" + layout="topleft" + left="10" + name="control_panel" + top_pad="5"> + <!-- + Notes: + This panel holds the Ignore button and possibly other buttons of notification. + --> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 15d1222d00..d6e4c56113 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -79,6 +79,7 @@ </radio_group> <check_box + control_name="AllowMultipleViewers" follows="top|left" height="15" label="Allow Multiple Viewer" @@ -88,6 +89,7 @@ top_pad="20" width="237"/> <check_box + control_name="ForceShowGrid" follows="top|left" height="15" label="Show Grid Selection at login" @@ -97,6 +99,7 @@ top_pad="5" width="237"/> <check_box + control_name="UseDebugMenus" follows="top|left" height="15" label="Show Advanced Menu" @@ -106,6 +109,7 @@ top_pad="5" width="237"/> <check_box + control_name="QAMode" follows="top|left" height="15" label="Show Developer Menu" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml index 036730a646..6dc419a96c 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml @@ -113,22 +113,22 @@ </text> <color_swatch can_apply_immediately="true" - color="LtGray" + color="EmphasisColor_35" follows="left|top" height="24" label_height="0" label_width="60" layout="topleft" left="360" - name="im" + name="objects" top_pad="-15" width="44"> <color_swatch.init_callback function="Pref.getUIColor" - parameter="IMChatColor" /> + parameter="ObjectChatColor" /> <color_swatch.commit_callback function="Pref.applyUIColor" - parameter="IMChatColor" /> + parameter="ObjectChatColor" /> </color_swatch> <text type="string" @@ -141,7 +141,7 @@ name="text_box3" top_delta="5" width="95"> - IM + Objects </text> <color_swatch can_apply_immediately="true" @@ -208,37 +208,6 @@ </text> <color_swatch can_apply_immediately="true" - color="EmphasisColor_35" - follows="left|top" - height="24" - label_height="0" - layout="topleft" - left="360" - name="objects" - top_pad="-15" - width="44" > - <color_swatch.init_callback - function="Pref.getUIColor" - parameter="ObjectChatColor" /> - <color_swatch.commit_callback - function="Pref.applyUIColor" - parameter="ObjectChatColor" /> - </color_swatch> - <text - type="string" - length="1" - follows="left|top" - height="10" - layout="topleft" - left_pad="5" - mouse_opaque="false" - name="text_box6" - top_delta="5" - width="95"> - Objects - </text> - <color_swatch - can_apply_immediately="true" color="LtYellow" follows="left|top" height="24" @@ -305,7 +274,7 @@ left="30" height="12" name="bubble_chat" - top_pad="28" + top_pad="20" width="120" > Bubble chat: @@ -336,11 +305,58 @@ height="16" increment="0.05" initial_value="1" - label="Opacity" + label="Opacity:" layout="topleft" - left_pad="15" - label_width="56" + left_pad="10" + label_width="70" name="bubble_chat_opacity" top_delta = "6" - width="347" /> + width="378" /> + <text + follows="left|top" + layout="topleft" + left="30" + height="12" + name="bubble_chat" + top_pad="15" + width="120" + > + Floater Opacity: + </text> + <slider + can_edit_text="false" + control_name="ActiveFloaterTransparency" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0.8" + layout="topleft" + label_width="115" + label="Active :" + left="50" + max_val="1.00" + min_val="0.00" + name="active" + show_text="true" + top_pad="5" + width="415" /> + <slider + can_edit_text="false" + control_name="InactiveFloaterTransparency" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.01" + initial_value="0.5" + layout="topleft" + label_width="115" + label="Inctive :" + left="50" + max_val="1.00" + min_val="0.00" + name="active" + show_text="true" + top_pad="5" + width="415" /> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml index a660b5d785..36f8f99178 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml @@ -331,6 +331,7 @@ Pressing letter keys: </text> <radio_group + control_name="LetterKeysFocusChatBar" height="20" layout="topleft" left="35" @@ -338,12 +339,12 @@ name="inworld_typing_preference"> <radio_item label="Starts local chat" - name="radio_button1" + name="radio_start_chat" top_delta="20" layout="topleft" height="16" left="0" - value="0" + value="1" width="150" /> <radio_item label="Affects movement (i.e. WASD)" @@ -351,8 +352,8 @@ layout="topleft" top_delta="0" height="16" - name="radio_button2" - value="1" + name="radio_move" + value="0" width="75" /> </radio_group> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 7d49a671e6..3ceee60927 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -163,536 +163,546 @@ top="76" width="485"> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="5" - name="ShadersText" - top="3" - width="128"> + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="5" + name="ShadersText" + top="3" + width="128"> Shaders: </text> <check_box - control_name="RenderObjectBump" - height="16" - initial_value="true" - label="Bump mapping and shiny" - layout="topleft" - left_delta="0" - name="BumpShiny" - top_pad="7" - width="256" /> + control_name="RenderTransparentWater" + height="16" + initial_value="true" + label="Transparent Water" + layout="topleft" + left_delta="0" + name="BumpShiny" + top_pad="7" + width="256" /> <check_box - control_name="VertexShaderEnable" - height="16" - initial_value="true" - label="Basic shaders" - layout="topleft" - left_delta="0" - name="BasicShaders" - tool_tip="Disabling this option may prevent some graphics card drivers from crashing" - top_pad="1" - width="315"> + control_name="RenderObjectBump" + height="16" + initial_value="true" + label="Bump mapping and shiny" + layout="topleft" + left_delta="0" + name="BumpShiny" + top_pad="1" + width="256" /> + <check_box + control_name="VertexShaderEnable" + height="16" + initial_value="true" + label="Basic shaders" + layout="topleft" + left_delta="0" + name="BasicShaders" + tool_tip="Disabling this option may prevent some graphics card drivers from crashing" + top_pad="1" + width="315"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.VertexShaderEnable" /> </check_box> <check_box - control_name="WindLightUseAtmosShaders" - height="16" - initial_value="true" - label="Atmospheric shaders" - layout="topleft" - left_delta="0" - name="WindLightUseAtmosShaders" - top_pad="1" - width="256"> + control_name="WindLightUseAtmosShaders" + height="16" + initial_value="true" + label="Atmospheric shaders" + layout="topleft" + left_delta="0" + name="WindLightUseAtmosShaders" + top_pad="1" + width="256"> <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + function="Pref.VertexShaderEnable" /> </check_box> <!-- DISABLED UNTIL WE REALLY WANT TO SUPPORT THIS - <check_box - control_name="RenderDeferred" - height="16" - initial_value="true" - label="Lighting and Shadows" - layout="topleft" - left_delta="0" - name="UseLightShaders" - top_pad="1" - width="256"> - <check_box.commit_callback - function="Pref.VertexShaderEnable" /> - </check_box> - <check_box - control_name="RenderDeferredSSAO" - height="16" - initial_value="true" - label="Ambient Occlusion" - layout="topleft" - left_delta="0" - name="UseSSAO" - top_pad="1" - width="256"> - <check_box.commit_callback - function="Pref.VertexShaderEnable" /> - </check_box> + <check_box + control_name="RenderDeferred" + height="16" + initial_value="true" + label="Lighting and Shadows" + layout="topleft" + left_delta="0" + name="UseLightShaders" + top_pad="1" + width="256"> + <check_box.commit_callback + function="Pref.VertexShaderEnable" /> + </check_box> + <check_box + control_name="RenderDeferredSSAO" + height="16" + initial_value="true" + label="Ambient Occlusion" + layout="topleft" + left_delta="0" + name="UseSSAO" + top_pad="1" + width="256"> + <check_box.commit_callback + function="Pref.VertexShaderEnable" /> + </check_box> - <text - type="string" - length="1" - top_pad="8" - follows="top|left" - height="23" - width="110" - word_wrap="true" - layout="topleft" - left="10" - name="shadows_label"> - Shadows: - </text> - <combo_box - control_name="RenderShadowDetail" - height="23" - layout="topleft" - left="10" - top_pad="0" - name="ShadowDetail" - width="150"> - <combo_box.item - label="None" - name="0" - value="0"/> - <combo_box.item - label="Sun/Moon" - name="1" - value="1"/> - <combo_box.item - label="Sun/Moon + Projectors" - name="2" - value="2"/> - </combo_box> + <text + type="string" + length="1" + top_pad="8" + follows="top|left" + height="23" + width="110" + word_wrap="true" + layout="topleft" + left="10" + name="shadows_label"> + Shadows: + </text> + <combo_box + control_name="RenderShadowDetail" + height="23" + layout="topleft" + left="10" + top_pad="0" + name="ShadowDetail" + width="150"> + <combo_box.item + label="None" + name="0" + value="0"/> + <combo_box.item + label="Sun/Moon" + name="1" + value="1"/> + <combo_box.item + label="Sun/Moon + Projectors" + name="2" + value="2"/> + </combo_box> --> - <text - type="string" - length="1" - top_pad="8" - follows="top|left" - height="23" - width="110" - word_wrap="true" - layout="topleft" - left="10" - name="reflection_label"> - Water Reflections: - </text> - <combo_box - control_name="RenderReflectionDetail" - height="23" - layout="topleft" - left_delta="10" - top_pad ="0" - name="Reflections" - width="150"> - <combo_box.item - label="Minimal" - name="0" - value="0"/> - <combo_box.item - label="Terrain and trees" - name="1" - value="1"/> - <combo_box.item - label="All static objects" - name="2" - value="2"/> - <combo_box.item - label="All avatars and objects" - name="3" - value="3"/> - <combo_box.item - label="Everything" - name="4" - value="4"/> - </combo_box> + <text + type="string" + length="1" + top_pad="8" + follows="top|left" + height="12" + width="110" + word_wrap="true" + layout="topleft" + left="05" + name="reflection_label"> + Water Reflections: + </text> + <combo_box + control_name="RenderReflectionDetail" + height="18" + layout="topleft" + left_delta="10" + top_pad ="3" + name="Reflections" + width="150"> + <combo_box.item + label="Minimal" + name="0" + value="0"/> + <combo_box.item + label="Terrain and trees" + name="1" + value="1"/> + <combo_box.item + label="All static objects" + name="2" + value="2"/> + <combo_box.item + label="All avatars and objects" + name="3" + value="3"/> + <combo_box.item + label="Everything" + name="4" + value="4"/> + </combo_box> <slider - control_name="RenderFarClip" - decimal_digits="0" - follows="left|top" - height="16" - increment="8" - initial_value="160" - label="Draw distance:" - label_width="185" - layout="topleft" - left="200" - max_val="512" - min_val="64" - name="DrawDistance" - top="3" - width="296" /> + control_name="RenderFarClip" + decimal_digits="0" + follows="left|top" + height="16" + increment="8" + initial_value="160" + label="Draw distance:" + label_width="185" + layout="topleft" + left="200" + max_val="512" + min_val="64" + name="DrawDistance" + top="3" + width="296" /> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="291" - name="DrawDistanceMeterText2" - top_delta="0" - width="128"> + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="291" + name="DrawDistanceMeterText2" + top_delta="0" + width="128"> m </text> <slider - control_name="RenderMaxPartCount" - decimal_digits="0" - follows="left|top" - height="16" - increment="256" - initial_value="4096" - label="Max. particle count:" - label_width="185" - layout="topleft" - left="200" - max_val="8192" - name="MaxParticleCount" - top_pad="7" - width="303" /> - <slider - control_name="RenderAvatarMaxVisible" - decimal_digits="0" - follows="left|top" - height="16" - increment="1" - initial_value="12" - label="Max. # of non-impostor avatars:" - label_width="185" - layout="topleft" - left_delta="0" - max_val="65" - min_val="1" - name="MaxNumberAvatarDrawn" - top_pad="4" - width="290" /> + control_name="RenderMaxPartCount" + decimal_digits="0" + follows="left|top" + height="16" + increment="256" + initial_value="4096" + label="Max. particle count:" + label_width="185" + layout="topleft" + left="200" + max_val="8192" + name="MaxParticleCount" + top_pad="7" + width="303" /> + <slider + control_name="RenderAvatarMaxVisible" + decimal_digits="0" + follows="left|top" + height="16" + increment="1" + initial_value="12" + label="Max. # of non-impostor avatars:" + label_width="185" + layout="topleft" + left_delta="0" + max_val="65" + min_val="1" + name="MaxNumberAvatarDrawn" + top_pad="4" + width="290" /> <slider - control_name="RenderGlowResolutionPow" - decimal_digits="0" - follows="left|top" - height="16" - increment="1" - initial_value="8" - label="Post process quality:" - label_width="185" - layout="topleft" - left="200" - max_val="9" - min_val="8" - name="RenderPostProcess" - show_text="false" - top_pad="4" - width="264"> + control_name="RenderGlowResolutionPow" + decimal_digits="0" + follows="left|top" + height="16" + increment="1" + initial_value="8" + label="Post process quality:" + label_width="185" + layout="topleft" + left="200" + max_val="9" + min_val="8" + name="RenderPostProcess" + show_text="false" + top_pad="4" + width="264"> <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="PostProcessText" /> + function="Pref.UpdateSliderText" + parameter="PostProcessText" /> </slider> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="MeshDetailText" - top_pad="5" - width="128"> + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="MeshDetailText" + top_pad="5" + width="128"> Mesh detail: </text> <slider - control_name="RenderVolumeLODFactor" - follows="left|top" - height="16" - increment="0.125" - initial_value="160" - label=" Objects:" - label_width="185" - layout="topleft" - left_delta="0" - max_val="2" - name="ObjectMeshDetail" - show_text="false" - top_pad="6" - width="264"> + control_name="RenderVolumeLODFactor" + follows="left|top" + height="16" + increment="0.125" + initial_value="160" + label=" Objects:" + label_width="185" + layout="topleft" + left_delta="0" + max_val="2" + name="ObjectMeshDetail" + show_text="false" + top_pad="6" + width="264"> <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="ObjectMeshDetailText" /> + function="Pref.UpdateSliderText" + parameter="ObjectMeshDetailText" /> </slider> <slider - control_name="RenderFlexTimeFactor" - follows="left|top" - height="16" - initial_value="160" - label=" Flexiprims:" - label_width="185" - layout="topleft" - left_delta="0" - name="FlexibleMeshDetail" - show_text="false" - top_pad="4" - width="264"> + control_name="RenderFlexTimeFactor" + follows="left|top" + height="16" + initial_value="160" + label=" Flexiprims:" + label_width="185" + layout="topleft" + left_delta="0" + name="FlexibleMeshDetail" + show_text="false" + top_pad="4" + width="264"> <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="FlexibleMeshDetailText" /> + function="Pref.UpdateSliderText" + parameter="FlexibleMeshDetailText" /> </slider> <slider - control_name="RenderTreeLODFactor" - follows="left|top" - height="16" - increment="0.125" - initial_value="160" - label=" Trees:" - label_width="185" - layout="topleft" - left_delta="0" - name="TreeMeshDetail" - show_text="false" - top_pad="4" - width="264"> - <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="TreeMeshDetailText" /> - </slider> + control_name="RenderTreeLODFactor" + follows="left|top" + height="16" + increment="0.125" + initial_value="160" + label=" Trees:" + label_width="185" + layout="topleft" + left_delta="0" + name="TreeMeshDetail" + show_text="false" + top_pad="4" + width="264"> + <slider.commit_callback + function="Pref.UpdateSliderText" + parameter="TreeMeshDetailText" /> + </slider> <slider - control_name="RenderAvatarLODFactor" - follows="left|top" - height="16" - increment="0.125" - initial_value="160" - label=" Avatars:" - label_width="185" - layout="topleft" - left_delta="0" - name="AvatarMeshDetail" - show_text="false" - top_pad="4" - width="264"> - <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="AvatarMeshDetailText" /> + control_name="RenderAvatarLODFactor" + follows="left|top" + height="16" + increment="0.125" + initial_value="160" + label=" Avatars:" + label_width="185" + layout="topleft" + left_delta="0" + name="AvatarMeshDetail" + show_text="false" + top_pad="4" + width="264"> + <slider.commit_callback + function="Pref.UpdateSliderText" + parameter="AvatarMeshDetailText" /> </slider> <slider - control_name="RenderTerrainLODFactor" - follows="left|top" - height="16" - increment="0.125" - initial_value="160" - label=" Terrain:" - label_width="185" - layout="topleft" - left_delta="0" - max_val="2" - min_val="1" - name="TerrainMeshDetail" - show_text="false" - top_pad="4" - width="264"> - <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="TerrainMeshDetailText" /> + control_name="RenderTerrainLODFactor" + follows="left|top" + height="16" + increment="0.125" + initial_value="160" + label=" Terrain:" + label_width="185" + layout="topleft" + left_delta="0" + max_val="2" + min_val="1" + name="TerrainMeshDetail" + show_text="false" + top_pad="4" + width="264"> + <slider.commit_callback + function="Pref.UpdateSliderText" + parameter="TerrainMeshDetailText" /> </slider> <slider - control_name="WLSkyDetail" - enabled_control="WindLightUseAtmosShaders" - decimal_digits="0" - follows="left|top" - height="16" - increment="8" - initial_value="160" - label=" Sky:" - label_width="185" - layout="topleft" - left_delta="0" - max_val="128" - min_val="16" - name="SkyMeshDetail" - show_text="false" - top_pad="4" - width="264"> - <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="SkyMeshDetailText" /> + control_name="WLSkyDetail" + enabled_control="WindLightUseAtmosShaders" + decimal_digits="0" + follows="left|top" + height="16" + increment="8" + initial_value="160" + label=" Sky:" + label_width="185" + layout="topleft" + left_delta="0" + max_val="128" + min_val="16" + name="SkyMeshDetail" + show_text="false" + top_pad="4" + width="264"> + <slider.commit_callback + function="Pref.UpdateSliderText" + parameter="SkyMeshDetailText" /> </slider> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left="469" - name="PostProcessText" - top="60" - width="128"> - Low + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="469" + name="PostProcessText" + top="60" + width="128"> + Low </text> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="ObjectMeshDetailText" - top_pad="26" - width="128"> - Low + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="ObjectMeshDetailText" + top_pad="26" + width="128"> + Low </text> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="FlexibleMeshDetailText" - top_pad="8" - width="128"> - Low + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="FlexibleMeshDetailText" + top_pad="8" + width="128"> + Low </text> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="TreeMeshDetailText" - top_pad="8" - width="128"> - Low + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="TreeMeshDetailText" + top_pad="8" + width="128"> + Low </text> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="AvatarMeshDetailText" - top_pad="8" - width="128"> - Low + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="AvatarMeshDetailText" + top_pad="8" + width="128"> + Low </text> <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="TerrainMeshDetailText" - top_pad="8" - width="128"> - Low + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="TerrainMeshDetailText" + top_pad="8" + width="128"> + Low </text> <text - enabled_control="WindLightUseAtmosShaders" - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="0" - name="SkyMeshDetailText" - top_pad="8" - width="128"> - Low + enabled_control="WindLightUseAtmosShaders" + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="0" + name="SkyMeshDetailText" + top_pad="8" + width="128"> + Low </text> - <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left_delta="-260" - name="AvatarRenderingText" - top_pad="18" - width="128"> - Avatar rendering: + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="-260" + name="AvatarRenderingText" + top_pad="18" + width="128"> + Avatar rendering: </text> <check_box - control_name="RenderUseImpostors" - height="16" - initial_value="true" - label="Avatar impostors" - layout="topleft" - left_delta="0" - name="AvatarImpostors" - top_pad="7" - width="256" /> + control_name="RenderUseImpostors" + height="16" + initial_value="true" + label="Avatar impostors" + layout="topleft" + left_delta="0" + name="AvatarImpostors" + top_pad="7" + width="256" /> <check_box - control_name="RenderAvatarVP" - height="16" - initial_value="true" - label="Hardware skinning" - layout="topleft" - left_delta="0" - name="AvatarVertexProgram" - top_pad="1" - width="256"> - <check_box.commit_callback - function="Pref.VertexShaderEnable" /> + control_name="RenderAvatarVP" + height="16" + initial_value="true" + label="Hardware skinning" + layout="topleft" + left_delta="0" + name="AvatarVertexProgram" + top_pad="1" + width="256"> + <check_box.commit_callback + function="Pref.VertexShaderEnable" /> </check_box> <check_box - control_name="RenderAvatarCloth" - height="16" - initial_value="true" - label="Avatar cloth" - layout="topleft" - left_delta="0" - name="AvatarCloth" - top_pad="1" - width="256" /> - <text - type="string" - length="1" - follows="left|top" - height="12" - layout="topleft" - left="358" - left_pad="-30" - name="TerrainDetailText" - top="226" - width="155"> - Terrain detail: - </text> - <radio_group - control_name="RenderTerrainDetail" - draw_border="false" - height="38" - layout="topleft" - left_delta="0" - name="TerrainDetailRadio" - top_pad="5" - width="70"> - <radio_item - height="16" - label="Low" - layout="topleft" - name="0" - top="3" - width="50" /> - <radio_item - height="16" - label="High" - layout="topleft" - name="2" - top_delta="16" - width="50" /> - </radio_group> --> + control_name="RenderAvatarCloth" + height="16" + initial_value="true" + label="Avatar cloth" + layout="topleft" + left_delta="0" + name="AvatarCloth" + top_pad="1" + width="256" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="358" + left_pad="-30" + name="TerrainDetailText" + top="226" + width="155"> + Terrain detail: + </text> + <radio_group + control_name="RenderTerrainDetail" + draw_border="false" + height="38" + layout="topleft" + left_delta="0" + name="TerrainDetailRadio" + top_pad="5" + width="70"> + <radio_item + height="16" + label="Low" + layout="topleft" + name="0" + top="3" + width="50" /> + <radio_item + height="16" + label="High" + layout="topleft" + name="2" + top_delta="16" + width="50" /> + </radio_group> --> </panel> - <button + <button follows="left|bottom" height="23" label="Apply" @@ -701,8 +711,7 @@ left="10" name="Apply" top="383" - width="115" - > + width="115"> <button.commit_callback function="Pref.Apply" /> </button> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml index ec80efe188..d2fc6ea09a 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml @@ -177,7 +177,10 @@ left_delta="0" name="double_click_chkbox" width="237" - top_pad="0"/> + top_pad="0"> + <check_box.commit_callback + function="Pref.CommitDoubleClickChekbox"/> + </check_box> <radio_group height="20" layout="topleft" @@ -191,7 +194,6 @@ left="0" name="radio_teleport" top_delta="20" - value="0" width="100" /> <radio_item height="16" @@ -200,7 +202,19 @@ layout="topleft" name="radio_autopilot" top_delta="0" - value="1" width="75" /> + <radio_group.commit_callback + function="Pref.CommitRadioDoubleClick"/> </radio_group> -</panel> + <button + height="23" + label="Other Devices" + left="30" + name="joystick_setup_button" + top="30" + width="155"> + <button.commit_callback + function="Floater.Show" + parameter="pref_joystick" /> + </button> +</panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 14aa38c5d3..584bd1ea9d 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -341,4 +341,20 @@ name="web_proxy_port" top_delta="0" width="145" /> + + <check_box + top_delta="2" + enabled="true" + follows="left|top" + height="18" + initial_value="true" + control_name="UpdaterServiceActive" + label="Automatically download and install [APP_NAME] updates" + left="30" + mouse_opaque="true" + name="updater_service_active" + radio_style="false" + width="400" + top_pad="10"/> + </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 8ade41f587..da366f30ae 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -70,7 +70,7 @@ name="UI Volume" show_text="false" slider_label.halign="right" - top_pad="5" + top_pad="4" volume="true" width="300"> <slider.commit_callback @@ -104,7 +104,7 @@ name="Wind Volume" show_text="false" slider_label.halign="right" - top_pad="5" + top_pad="4" volume="true" width="300"> <slider.commit_callback @@ -138,7 +138,7 @@ left="0" name="SFX Volume" show_text="false" - top_pad="7" + top_pad="4" volume="true" width="300"> <slider.commit_callback @@ -172,7 +172,7 @@ name="Music Volume" slider_label.halign="right" show_text="false" - top_pad="5" + top_pad="4" volume="true" width="300"> <slider.commit_callback @@ -215,7 +215,7 @@ name="Media Volume" show_text="false" slider_label.halign="right" - top_pad="5" + top_pad="4" volume="true" width="300"> <slider.commit_callback @@ -257,7 +257,7 @@ label_width="120" layout="topleft" left="0" - top_pad="5" + top_pad="4" name="Voice Volume" show_text="false" slider_label.halign="right" @@ -301,9 +301,9 @@ height="15" tool_tip="Check this to let media auto-play if it wants" label="Allow Media to auto-play" - top_pad="5" + top_pad="1" left="25"/> - <check_box + <check_box name="media_show_on_others_btn" control_name="MediaShowOnOthers" value="true" @@ -313,16 +313,6 @@ label="Play media attached to other avatars" left="25" width="230"/> - <check_box - control_name="LipSyncEnabled" - follows="left|top" - height="20" - label="Move avatar lips when speaking" - layout="topleft" - left_pad="0" - name="enable_lip_sync" - width="237" - top_delta="-4" /> <text type="string" @@ -333,7 +323,7 @@ left="25" name="voice_chat_settings" width="180" - top_pad="10"> + top_pad="7"> Voice Chat Settings </text> <text @@ -341,10 +331,10 @@ length="1" follows="left|top" layout="topleft" - left="80" + left="46" top_delta="16" name="Listen from" - width="102"> + width="112"> Listen from: </text> <icon @@ -363,7 +353,7 @@ height="18" image_name="Move_Walk_Off" layout="topleft" - left_pad="130" + left_pad="170" name="avatar_icon" mouse_opaque="false" visible="true" @@ -375,7 +365,7 @@ draw_border="false" follows="left|top" layout="topleft" - left_delta="-128" + left_delta="-168" width="221" height="20" name="ear_location"> @@ -391,11 +381,21 @@ follows="left|top" label="Avatar position" layout="topleft" - left_pad="-54" + left_pad="-16" name="1" top_delta ="0" width="200" /> </radio_group> + <check_box + control_name="LipSyncEnabled" + follows="left|top" + height="15" + label="Move avatar lips when speaking" + layout="topleft" + left="44" + name="enable_lip_sync" + top_pad="5" + width="237"/> <check_box follows="top|left" enabled_control="EnableVoiceChat" @@ -403,10 +403,11 @@ height="15" label="Toggle speak on/off when I press:" layout="topleft" - left="30" + left="44" name="push_to_talk_toggle_check" width="237" - tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."/> + tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down." + top_pad="3"/> <line_editor follows="top|left" control_name="PushToTalkButton" @@ -454,7 +455,7 @@ label="Input/Output devices" layout="topleft" left="20" - top_pad="8" + top_pad="6" name="device_settings_btn" width="190"> </button> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 1ec0d34d9a..51fba470cb 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1823,8 +1823,8 @@ key llRequestUsername(key id) Requests single-word username of an avatar. When data is available the dataserver event will be raised. </string> <string name="LSLTipText_llGetDisplayName" translate="false"> -string llGetDisplayName(key id) -Returns the name of an avatar, iff the avatar is in the current simulator, otherwise the empty string. + string llGetDisplayName(key id) + Returns the name of an avatar, iff the avatar is in the current simulator, and the name has been cached, otherwise the same as llGetUsername. Use llRequestDisplayName if you absolutely must have the display name. </string> <string name="LSLTipText_llRequestDisplayName" translate="false"> key llRequestDisplayName(key id) diff --git a/indra/newview/skins/default/xui/es/floater_im.xml b/indra/newview/skins/default/xui/es/floater_im.xml deleted file mode 100644 index 3850b94fd6..0000000000 --- a/indra/newview/skins/default/xui/es/floater_im.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<multi_floater name="im_floater" title="Mensaje Instantáneo"> - <string name="only_user_message"> - Eres el único Residente en esta sesión. - </string> - <string name="offline_message"> - [FIRST] [LAST] no está conectado. - </string> - <string name="invite_message"> - Pulse el botón [BUTTON NAME] para aceptar/conectar este chat de voz. - </string> - <string name="muted_message"> - Has ignorado a este Residente. Enviándole un mensaje, automáticamente dejarás de ignorarle. - </string> - <string name="generic_request_error"> - Error al hacer lo solicitado; por favor, inténtelo más tarde. - </string> - <string name="insufficient_perms_error"> - Usted no tiene permisos suficientes. - </string> - <string name="session_does_not_exist_error"> - La sesión ya acabó - </string> - <string name="no_ability_error"> - Usted no tiene esa capacidad. - </string> - <string name="not_a_mod_error"> - Usted no es un moderador de la sesión. - </string> - <string name="muted_error"> - Un moderador del grupo le ha desactivado el chat de texto. - </string> - <string name="add_session_event"> - No es posible añadir Residentes a la sesión de chat con [RECIPIENT]. - </string> - <string name="message_session_event"> - No se ha podido enviar su mensaje a la sesión de chat con [RECIPIENT]. - </string> - <string name="removed_from_group"> - Ha sido eliminado del grupo. - </string> - <string name="close_on_no_ability"> - Usted ya no tendrá más la capacidad de estar en la sesión de chat. - </string> -</multi_floater> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 286af718e3..6c5fe6a9eb 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -2469,7 +2469,7 @@ Por favor, vuelve a intentarlo en unos momentos. Rehusado el ofrecimiento de amistad. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] te está ofreciendo su tarjeta de visita. + [NAME] te está ofreciendo su tarjeta de visita. Esto añadirá un marcador en tu inventario para que puedas enviarle rápidamente un MI. <form name="form"> <button name="Accept" text="Aceptar"/> diff --git a/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml index 8bda133a0b..17254ff325 100644 --- a/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml +++ b/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml @@ -3,7 +3,7 @@ <menu_item_call label="Voir le profil" name="view_profile"/> <menu_item_call label="Devenir amis" name="add_friend"/> <menu_item_call label="IM" name="im"/> - <menu_item_call label="Appeler" name="call"/> + <menu_item_call label="Appel" name="call"/> <menu_item_call label="Téléporter" name="teleport"/> <menu_item_call label="Inviter dans le groupe" name="invite_to_group"/> <menu_item_call label="Ignorer" name="block"/> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index 89fd9c6fdc..341cc9830d 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -2464,7 +2464,7 @@ Veuillez réessayer dans quelques minutes. Amitié refusée. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] vous offre sa carte de visite. + [NAME] vous offre sa carte de visite. Cela ajoute un marque-page dans votre inventaire, ce qui vous permet d'envoyer rapidement un IM à ce résident. <form name="form"> <button name="Accept" text="Accepter"/> diff --git a/indra/newview/skins/default/xui/fr/panel_edit_profile.xml b/indra/newview/skins/default/xui/fr/panel_edit_profile.xml index 30799caf1f..ef65d2fe24 100644 --- a/indra/newview/skins/default/xui/fr/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/fr/panel_edit_profile.xml @@ -54,7 +54,7 @@ <text name="my_account_link" value="[[URL] Accéder à ma Page d'accueil]"/> <text name="title_partner_text" value="Mon partenaire :"/> <panel name="partner_data_panel"> - <text initial_value="(récupération en cours)" name="partner_text" value="[FIRST] [LAST]"/> + <text initial_value="(récupération en cours)" name="partner_text"/> </panel> <text name="partner_edit_link" value="[[URL] Modifier]"/> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml index e4c35d60fe..3e7225d8ac 100644 --- a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Choses" name="main inventory panel"> <panel.string name="ItemcountFetching"> - Récupération de [ITEM_COUNT] articles... [FILTER] + Récupération : [ITEM_COUNT] articles... [FILTER] </panel.string> <panel.string name="ItemcountCompleted"> [ITEM_COUNT] articles [FILTER] diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index d6c701dc90..8b958119eb 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -1089,7 +1089,7 @@ <string name="Textures" value=" Textures,"/> <string name="Snapshots" value=" Photos,"/> <string name="No Filters" value="Non "/> - <string name="Since Logoff" value=" - Depuis la déconnexion"/> + <string name="Since Logoff" value=" depuis la déconnexion"/> <string name="InvFolder My Inventory"> Mon inventaire </string> diff --git a/indra/newview/skins/default/xui/it/floater_bumps.xml b/indra/newview/skins/default/xui/it/floater_bumps.xml index d9dd3f26d7..6de2fea67f 100644 --- a/indra/newview/skins/default/xui/it/floater_bumps.xml +++ b/indra/newview/skins/default/xui/it/floater_bumps.xml @@ -4,19 +4,19 @@ Nessuno rilevato </floater.string> <floater.string name="bump"> - [TIME] [FIRST] [LAST] ti ha urtato + [TIME] [NAME] ti ha urtato </floater.string> <floater.string name="llpushobject"> - [TIME] [FIRST] [LAST] ti ha spinto per mezzo di uno script + [TIME] [NAME] ti ha spinto per mezzo di uno script </floater.string> <floater.string name="selected_object_collide"> - [TIME] [FIRST] [LAST] ti ha colpito con un oggetto + [TIME] [NAME] ti ha colpito con un oggetto </floater.string> <floater.string name="scripted_object_collide"> - [TIME] [FIRST] [LAST] ti ha colpito con un oggetto scriptato + [TIME] [NAME] ti ha colpito con un oggetto scriptato </floater.string> <floater.string name="physical_object_collide"> - [TIME] [FIRST] [LAST] ti ha colpito con un oggetto fisico + [TIME] [NAME] ti ha colpito con un oggetto fisico </floater.string> <floater.string name="timeStr"> [[hour,datetime,slt]:[min,datetime,slt]] diff --git a/indra/newview/skins/default/xui/it/floater_pay.xml b/indra/newview/skins/default/xui/it/floater_pay.xml index c1ea8ec9c8..6389cbfbf7 100644 --- a/indra/newview/skins/default/xui/it/floater_pay.xml +++ b/indra/newview/skins/default/xui/it/floater_pay.xml @@ -11,7 +11,7 @@ </text> <icon name="icon_person" tool_tip="Persona"/> <text left="115" name="payee_name"> - [FIRST] [LAST] + Test Name That Is Extremely Long To Check Clipping </text> <button label="1 L$" label_selected="1 L$" left="118" name="fastpay 1" width="80"/> <button label="5 L$" label_selected="5 L$" left="210" name="fastpay 5"/> diff --git a/indra/newview/skins/default/xui/it/floater_pay_object.xml b/indra/newview/skins/default/xui/it/floater_pay_object.xml index 37f549b5da..8805f3208e 100644 --- a/indra/newview/skins/default/xui/it/floater_pay_object.xml +++ b/indra/newview/skins/default/xui/it/floater_pay_object.xml @@ -8,7 +8,7 @@ </string> <icon name="icon_person" tool_tip="Persona"/> <text left="120" name="payee_name"> - [FIRST] [LAST] + Ericacita Moostopolison </text> <text halign="left" left="5" name="object_name_label" width="110"> Mediante l'oggetto: diff --git a/indra/newview/skins/default/xui/it/floater_tools.xml b/indra/newview/skins/default/xui/it/floater_tools.xml index fbe611407e..a8c985cb12 100644 --- a/indra/newview/skins/default/xui/it/floater_tools.xml +++ b/indra/newview/skins/default/xui/it/floater_tools.xml @@ -283,7 +283,7 @@ <combo_box.item label="Plastica" name="Plastic"/> <combo_box.item label="Gomma" name="Rubber"/> </combo_box> - <text name="text cut"> + <text name="text cut" left_delta="-10" width="170"> Riduci una sezione (inizio/fine) </text> <spinner label="I" name="cut begin"/> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index ffd27d55e8..32483881b2 100644 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2035,10 +2035,10 @@ Inseriscilo in una pagina web per dare ad altri un accesso facile a questa ubica Oggetto: [SUBJECT], Messaggio: [MESSAGE] </notification> <notification name="FriendOnline"> - [FIRST] [LAST] è Online + [NAME] è Online </notification> <notification name="FriendOffline"> - [FIRST] [LAST] è Offline + [NAME] è Offline </notification> <notification name="AddSelfFriend"> Anche se sei molto simpatico, non puoi aggiungere te stesso all'elenco degli amici. @@ -2105,9 +2105,6 @@ Questo potrebbe incidere sulla tua password. <notification name="CannotRemoveProtectedCategories"> Non è possibile rimuovere le categorie protette. </notification> - <notification name="OfferedCard"> - Hai offerto un biglietto da visita a [FIRST] [LAST] - </notification> <notification name="UnableToBuyWhileDownloading"> Impossibile acquistare l'oggetto durante il download dei dati. Riprova. @@ -2223,7 +2220,7 @@ Reinstalla il plugin o contatta il venditore se continui ad avere questi problem Gli oggetti che possiedi sul terreno selezionato ti sono stati restituiti nell'inventario. </notification> <notification name="OtherObjectsReturned"> - Gli oggetti selezionati sul terreno che è di proprietà di [FIRST] [LAST] sono stati restituiti nel suo inventario. + Gli oggetti selezionati sul terreno che è di proprietà di [NAME] sono stati restituiti nel suo inventario. </notification> <notification name="OtherObjectsReturned2"> Sono stati restituiti al proprietario gli oggetti selezionati sul lotto nella terra di proprietà del residente '[NAME]'. @@ -2433,7 +2430,7 @@ Riprova tra qualche istante. Offerta di amicizia rifiutata. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] ti offre il suo biglietto da visita. + [NAME] ti offre il suo biglietto da visita. Questo sarà aggiunto nel tuo inventario come segnalibro per consentirti di inviare rapidamente messaggi IM a questo residente. <form name="form"> <button name="Accept" text="Accetta"/> @@ -2493,7 +2490,7 @@ Concedi questa richiesta? </form> </notification> <notification name="ScriptDialog"> - [FIRST] [LAST] '[TITLE]' + [NAME] '<nolink>[TITLE]</nolink>' [MESSAGE] <form name="form"> <button name="Ignore" text="Ignora"/> @@ -2537,13 +2534,13 @@ Clicca su Accetta per unirti alla chiamata oppure su Declina to declinare l&apos </form> </notification> <notification name="AutoUnmuteByIM"> - [FIRST] [LAST] ha ricevuto un IM ed è stato automaticamente sbloccato. + [NAME] ha ricevuto un IM ed è stato automaticamente sbloccato. </notification> <notification name="AutoUnmuteByMoney"> - [FIRST] [LAST] ha ricevuto del denaro e pertanto è stato automaticamente sbloccato. + [NAME] ha ricevuto del denaro e pertanto è stato automaticamente sbloccato. </notification> <notification name="AutoUnmuteByInventory"> - A [FIRST] [LAST] è stato offerto un elemento dell'Inventario e pertanto è stato automaticamente sbloccato. + A [NAME] è stato offerto un elemento dell'Inventario e pertanto è stato automaticamente sbloccato. </notification> <notification name="VoiceInviteGroup"> [NAME] si è aggiunto alla chiamata in chat vocale con il gruppo [GROUP]. diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 9dbfc2b79c..dfe635182e 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -3478,7 +3478,7 @@ Se il messaggio persiste, contatta [SUPPORT_SITE]. Sei l'unico utente di questa sessione. </string> <string name="offline_message"> - [FIRST] [LAST] è offline. + [NAME] è offline. </string> <string name="invite_message"> Clicca il tasto [BUTTON NAME] per accettare/connetterti a questa voice chat. diff --git a/indra/newview/skins/default/xui/ja/floater_bumps.xml b/indra/newview/skins/default/xui/ja/floater_bumps.xml index 8a1e19b852..c7e4dd348f 100644 --- a/indra/newview/skins/default/xui/ja/floater_bumps.xml +++ b/indra/newview/skins/default/xui/ja/floater_bumps.xml @@ -4,19 +4,19 @@ 検出ãªã— </floater.string> <floater.string name="bump"> - [TIME] [FIRST] [LAST]ãŒã€ã‚ãªãŸã«ã¶ã¤ã‹ã‚Šã¾ã—ãŸã€‚ + [TIME] [NAME]ãŒã€ã‚ãªãŸã«ã¶ã¤ã‹ã‚Šã¾ã—ãŸã€‚ </floater.string> <floater.string name="llpushobject"> - [TIME] [FIRST] [LAST]ãŒã€ã‚¹ã‚¯ãƒªãƒ—トã§ã‚ãªãŸã‚’プッシュã—ã¾ã—ãŸã€‚ + [TIME] [NAME]ãŒã€ã‚¹ã‚¯ãƒªãƒ—トã§ã‚ãªãŸã‚’プッシュã—ã¾ã—ãŸã€‚ </floater.string> <floater.string name="selected_object_collide"> - [TIME] [FIRST] [LAST]ãŒã€ã‚ªãƒ–ジェクトをã‚ãªãŸã«å½“ã¦ã¾ã—ãŸã€‚ + [TIME] [NAME]ãŒã€ã‚ªãƒ–ジェクトをã‚ãªãŸã«å½“ã¦ã¾ã—ãŸã€‚ </floater.string> <floater.string name="scripted_object_collide"> - [TIME] [FIRST] [LAST]ãŒã€ã‚¹ã‚¯ãƒªãƒ—ト・オブジェクトをã‚ãªãŸã«å½“ã¦ã¾ã—ãŸã€‚ + [TIME] [NAME]ãŒã€ã‚¹ã‚¯ãƒªãƒ—ト・オブジェクトをã‚ãªãŸã«å½“ã¦ã¾ã—ãŸã€‚ </floater.string> <floater.string name="physical_object_collide"> - [TIME] [FIRST] [LAST]ãŒã€ç‰©ç†ã‚ªãƒ–ジェクトをã‚ãªãŸã«å½“ã¦ã¾ã—ãŸã€‚ + [TIME] [NAME]ãŒã€ç‰©ç†ã‚ªãƒ–ジェクトをã‚ãªãŸã«å½“ã¦ã¾ã—ãŸã€‚ </floater.string> <floater.string name="timeStr"> [[hour,datetime,slt]:[min,datetime,slt]] diff --git a/indra/newview/skins/default/xui/ja/floater_pay.xml b/indra/newview/skins/default/xui/ja/floater_pay.xml index 39bc37bc6c..83a3c641f9 100644 --- a/indra/newview/skins/default/xui/ja/floater_pay.xml +++ b/indra/newview/skins/default/xui/ja/floater_pay.xml @@ -11,7 +11,7 @@ </text> <icon name="icon_person" tool_tip="ä½äºº"/> <text name="payee_name"> - [FIRST] [LAST] + Test Name That Is Extremely Long To Check Clipping </text> <button label="L$1" label_selected="L$1" name="fastpay 1"/> <button label="L$5" label_selected="L$5" name="fastpay 5"/> diff --git a/indra/newview/skins/default/xui/ja/floater_pay_object.xml b/indra/newview/skins/default/xui/ja/floater_pay_object.xml index ffd57ab67b..637ad496ef 100644 --- a/indra/newview/skins/default/xui/ja/floater_pay_object.xml +++ b/indra/newview/skins/default/xui/ja/floater_pay_object.xml @@ -8,7 +8,7 @@ </string> <icon name="icon_person" tool_tip="ä½äºº"/> <text name="payee_name"> - [FIRST] [LAST] + Ericacita Moostopolison </text> <text name="object_name_label"> オブジェクトを介ã—ã¦ï¼š diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index 93d6644902..c0af0e03ff 100644 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2082,10 +2082,10 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã 件å: [SUBJECT]ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ï¼š [MESSAGE] </notification> <notification name="FriendOnline"> - [FIRST] [LAST] ã¯ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã§ã™ + [NAME] ã¯ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã§ã™ </notification> <notification name="FriendOffline"> - [FIRST] [LAST] ã¯ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ + [NAME] ã¯ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ </notification> <notification name="AddSelfFriend"> 残念ãªãŒã‚‰è‡ªåˆ†è‡ªèº«ã‚’フレンド登録ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 @@ -2153,9 +2153,6 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã <notification name="CannotRemoveProtectedCategories"> ä¿è·ã•ã‚ŒãŸã‚«ãƒ†ã‚´ãƒªã¯å‰Šé™¤ã§ãã¾ã›ã‚“。 </notification> - <notification name="OfferedCard"> - [FIRST] [LAST] ã«ã‚³ãƒ¼ãƒªãƒ³ã‚°ã‚«ãƒ¼ãƒ‰ã‚’é€ã‚Šã¾ã—ãŸã€‚ - </notification> <notification name="UnableToBuyWhileDownloading"> オブジェクトデータã®ãƒ€ã‚¦ãƒ³ãƒãƒ¼ãƒ‰ä¸ã¯è³¼å…¥ã§ãã¾ã›ã‚“。 ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。 @@ -2273,7 +2270,7 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã </notification> <notification name="OtherObjectsReturned"> é¸æŠžã—ãŸåœŸåœ°ã®åŒºç”»ä¸Šã«ã‚ã£ãŸ - [FIRST] [LAST] + [NAME] ãŒæ‰€æœ‰ã™ã‚‹ã‚ªãƒ–ジェクトã¯ã€ã™ã¹ã¦æ‰€æœ‰è€…ã®ã€ŒæŒã¡ç‰©ã€ã«è¿”å´ã•ã‚Œã¾ã—ãŸã€‚ </notification> <notification name="OtherObjectsReturned2"> @@ -2488,7 +2485,7 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã フレンドã®ç™»éŒ²ä¾é ¼ãŒæ‹’å¦ã•ã‚Œã¾ã—ãŸã€‚ </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] ãŒã‚³ãƒ¼ãƒªãƒ³ã‚°ã‚«ãƒ¼ãƒ‰ã‚’渡ãã†ã¨ã—ã¦ã„ã¾ã™ã€‚ + [NAME] ãŒã‚³ãƒ¼ãƒªãƒ³ã‚°ã‚«ãƒ¼ãƒ‰ã‚’渡ãã†ã¨ã—ã¦ã„ã¾ã™ã€‚ ã‚ãªãŸã®ã€ŒæŒã¡ç‰©ã€ã«ãƒ–ックマークãŒè¿½åŠ ã•ã‚Œã€ã“ã®ä½äººã«ç´ æ—©ã IM ã‚’é€ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ <form name="form"> <button name="Accept" text="å—ã‘入れる"/> @@ -2548,7 +2545,7 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã </form> </notification> <notification name="ScriptDialog"> - [FIRST] [LAST] ã®ã€Œ [TITLE] 〠+ [NAME] ã®ã€Œ <nolink>[TITLE]</nolink> 〠[MESSAGE] <form name="form"> <button name="Ignore" text="無視ã™ã‚‹"/> @@ -2592,13 +2589,13 @@ M ã‚ーを押ã—ã¦å¤‰æ›´ã—ã¾ã™ã€‚ </form> </notification> <notification name="AutoUnmuteByIM"> - [FIRST] [LAST] ã¯ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ãƒˆãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’å—ã‘å–ã‚Šã€è‡ªå‹•çš„ã«ãƒ–ãƒãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸã€‚ + [NAME] ã¯ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ãƒˆãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’å—ã‘å–ã‚Šã€è‡ªå‹•çš„ã«ãƒ–ãƒãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸã€‚ </notification> <notification name="AutoUnmuteByMoney"> - [FIRST] [LAST] ã¯ãŠé‡‘ã‚’å—ã‘å–ã‚Šã€è‡ªå‹•çš„ã«ãƒ–ãƒãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸã€‚ + [NAME] ã¯ãŠé‡‘ã‚’å—ã‘å–ã‚Šã€è‡ªå‹•çš„ã«ãƒ–ãƒãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸã€‚ </notification> <notification name="AutoUnmuteByInventory"> - [FIRST] [LAST] ã¯ã‚¢ã‚¤ãƒ†ãƒ ã‚’å—ã‘å–ã‚Šã€è‡ªå‹•çš„ã«ãƒ–ãƒãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸã€‚ + [NAME] ã¯ã‚¢ã‚¤ãƒ†ãƒ ã‚’å—ã‘å–ã‚Šã€è‡ªå‹•çš„ã«ãƒ–ãƒãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸã€‚ </notification> <notification name="VoiceInviteGroup"> [NAME] 㯠[GROUP] ã®ãƒœã‚¤ã‚¹ãƒãƒ£ãƒƒãƒˆã‚³ãƒ¼ãƒ«ã«å‚åŠ ã—ã¾ã—ãŸã€‚ diff --git a/indra/newview/skins/default/xui/ja/panel_edit_profile.xml b/indra/newview/skins/default/xui/ja/panel_edit_profile.xml index 2aba4edc0d..334cf54a4d 100644 --- a/indra/newview/skins/default/xui/ja/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/ja/panel_edit_profile.xml @@ -46,7 +46,7 @@ <text name="my_account_link" value="[[URL] マイアカウントã«ç§»å‹•]"/> <text name="title_partner_text" value="マイパートナー:"/> <panel name="partner_data_panel"> - <name_box initial_value="(å–å¾—ä¸ï¼‰" name="partner_text" value="[FIRST] [LAST]"/> + <name_box initial_value="(å–å¾—ä¸ï¼‰" name="partner_text"/> </panel> <text name="partner_edit_link" value="[[URL] 編集]" width="100"/> </panel> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 92bbedaee5..187f21257a 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -3574,7 +3574,7 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンãƒãƒ¼ãƒ‰ã—ã¦ãã ã ã“ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã«ã„るユーザーã¯ã‚ãªãŸã ã‘ã§ã™ã€‚ </string> <string name="offline_message"> - [FIRST] [LAST] ã¯ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚ + [NAME] ã¯ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚ </string> <string name="invite_message"> ã“ã®ãƒœã‚¤ã‚¹ãƒãƒ£ãƒƒãƒˆã«å¿œç”・接続ã™ã‚‹å ´åˆã¯ã€[BUTTON NAME] をクリックã—ã¦ãã ã•ã„。 diff --git a/indra/newview/skins/default/xui/nl/floater_bumps.xml b/indra/newview/skins/default/xui/nl/floater_bumps.xml index df9a99d62e..516b59658d 100644 --- a/indra/newview/skins/default/xui/nl/floater_bumps.xml +++ b/indra/newview/skins/default/xui/nl/floater_bumps.xml @@ -4,18 +4,18 @@ Geen gedetecteerd </string> <string name="bump"> - [TIME] [FIRST] [LAST] botste tegen u aan + [TIME] [NAME] botste tegen u aan </string> <string name="llpushobject"> - [TIME] [FIRST] [LAST] duwde u met een script + [TIME] [NAME] duwde u met een script </string> <string name="selected_object_collide"> - [TIME] [FIRST] [LAST] raakte u met een object + [TIME] [NAME] raakte u met een object </string> <string name="scripted_object_collide"> - [TIME] [FIRST] [LAST] raakte u met een gescript object + [TIME] [NAME] raakte u met een gescript object </string> <string name="physical_object_collide"> - [TIME] [FIRST] [LAST] raakte u met een fysiek object + [TIME] [NAME] raakte u met een fysiek object </string> </floater> diff --git a/indra/newview/skins/default/xui/nl/floater_pay.xml b/indra/newview/skins/default/xui/nl/floater_pay.xml index 4018ebdc93..f2b34d78d7 100644 --- a/indra/newview/skins/default/xui/nl/floater_pay.xml +++ b/indra/newview/skins/default/xui/nl/floater_pay.xml @@ -10,7 +10,7 @@ Betaal inwoner: </text> <text name="payee_name" left="110"> - [FIRST] [LAST] + Test Name That Is Extremely Long To Check Clipping </text> <text name="fastpay text"> Snel betalen: diff --git a/indra/newview/skins/default/xui/nl/floater_pay_object.xml b/indra/newview/skins/default/xui/nl/floater_pay_object.xml index d3826648f2..11fa6d4a44 100644 --- a/indra/newview/skins/default/xui/nl/floater_pay_object.xml +++ b/indra/newview/skins/default/xui/nl/floater_pay_object.xml @@ -7,7 +7,7 @@ Betaal inwoner: </text> <text name="payee_name" left="100" width="200"> - [FIRST] [LAST] + Ericacita Moostopolison </text> <text name="object_name_label" left="5" width="90" halign="left"> Via object: diff --git a/indra/newview/skins/default/xui/nl/floater_tools.xml b/indra/newview/skins/default/xui/nl/floater_tools.xml index d49ffc2f51..4ffe675831 100644 --- a/indra/newview/skins/default/xui/nl/floater_tools.xml +++ b/indra/newview/skins/default/xui/nl/floater_tools.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="toolbox floater" title="" short_title="BOUWEN" height="587"> +<floater name="toolbox floater" title="" short_title="BOUWEN" height="592"> <button label="" label_selected="" name="button focus" tool_tip="Focus"/> <button label="" label_selected="" name="button move" tool_tip="Verplaats"/> <button label="" label_selected="" name="button edit" tool_tip="Bewerk"/> @@ -81,13 +81,13 @@ <text name="Strength:"> Sterkte </text> - <text name="obj_count" top_pad="15"> + <text name="obj_count" top_pad="20"> Geselecteerde objecten: [COUNT] </text> <text name="prim_count"> primitieven: [COUNT] </text> - <tab_container name="Object Info Tabs" tab_max_width="62" tab_min_width="30" top="180"> + <tab_container name="Object Info Tabs" tab_max_width="62" tab_min_width="30" top="185"> <panel label="Algemeen" name="General"> <text name="Name:"> Naam: @@ -115,19 +115,19 @@ <text name="Group Name Proxy"> De Lindens </text> - <button label="Instellen..." label_selected="Instellen..." name="button set group" left_pad="13"/> + <button label="Instellen..." label_selected="Instellen..." name="button set group"/> <text name="Permissions:"> Permissies: </text> - <check_box label="Deel met groep" name="checkbox share with group" tool_tip="Alle leden van de ingestelde groep toestaan om te delen en uw permissies voor dit object te gebruiken. U moet 'Overdragen' om rolbeperkingen in te schakelen." left="100"/> + <check_box label="Deel met groep" name="checkbox share with group" tool_tip="Alle leden van de ingestelde groep toestaan om te delen en uw permissies voor dit object te gebruiken. U moet 'Overdragen' om rolbeperkingen in te schakelen."/> <string name="text deed continued"> Overdragen... </string> <string name="text deed"> Overdragen </string> - <button label="Overdragen..." label_selected="Overdragen..." name="button deed" tool_tip="Groepgedeelde objecten kunnen door een groepofficier worden overgedragen" left_pad="19"/> + <button label="Overdragen..." label_selected="Overdragen..." name="button deed" tool_tip="Groepgedeelde objecten kunnen door een groepofficier worden overgedragen"/> <check_box label="Iedereen mag verplaatsen" name="checkbox allow everyone move"/> <check_box label="Iedereen mag kopiëren" name="checkbox allow everyone copy"/> <check_box label="Toon in zoeken" name="search_check" tool_tip="Laat mensen dit object zien in zoekresultaten"/> diff --git a/indra/newview/skins/default/xui/nl/notifications.xml b/indra/newview/skins/default/xui/nl/notifications.xml index b4b56a035f..be0c17d2ff 100644 --- a/indra/newview/skins/default/xui/nl/notifications.xml +++ b/indra/newview/skins/default/xui/nl/notifications.xml @@ -2478,9 +2478,6 @@ Wilt u de [SECOND_LIFE] website bezoeken om dit in te stellen? <notification name="CannotRemoveProtectedCategories"> U kunt geen beschermde categorieën verwijderen. </notification> - <notification name="OfferedCard"> - U heeft een visitekaartje aangeboden aan [FIRST] [LAST] - </notification> <notification name="UnableToBuyWhileDownloading"> Niet mogelijk te kopen terwijl objectdata wordt gedownload. Probeer het alstublieft opnieuw. </notification> @@ -2780,7 +2777,7 @@ Probeer het alstublieft opnieuw over enkele ogenblikken. [NAME] heeft uw vriendschapsaanbod afgewezen. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] biedt zijn/haar visitekaartje aan. + [NAME] biedt zijn/haar visitekaartje aan. Dit zal een bladwijzer in uw inventaris toevoegen zodat u deze inwoner snel kunt een IM kunt sturen. <form name="form"> <button name="Accept" text="Accepteren"/> diff --git a/indra/newview/skins/default/xui/nl/panel_edit_profile.xml b/indra/newview/skins/default/xui/nl/panel_edit_profile.xml index 172395e20a..fffdb9e8df 100644 --- a/indra/newview/skins/default/xui/nl/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/nl/panel_edit_profile.xml @@ -35,7 +35,7 @@ </panel> <text name="title_partner_text" value="Partner:"/> <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> + <text name="partner_text"/> </panel> <text name="text_box3"> Antwoord bij Niet Storen: diff --git a/indra/newview/skins/default/xui/nl/strings.xml b/indra/newview/skins/default/xui/nl/strings.xml index 844945913f..07265d2716 100644 --- a/indra/newview/skins/default/xui/nl/strings.xml +++ b/indra/newview/skins/default/xui/nl/strings.xml @@ -3211,7 +3211,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. U bent de enige gebruiker in deze sessie. </string> <string name="offline_message"> - [FIRST] [LAST] is offline. + [NAME] is offline. </string> <string name="invite_message"> Klik de [BUTTON NAME] knop om deze voicechat te accepteren/verbinden. diff --git a/indra/newview/skins/default/xui/pl/floater_tools.xml b/indra/newview/skins/default/xui/pl/floater_tools.xml index 8c77df9248..7c1ced0eae 100644 --- a/indra/newview/skins/default/xui/pl/floater_tools.xml +++ b/indra/newview/skins/default/xui/pl/floater_tools.xml @@ -307,7 +307,7 @@ <combo_box.item label="Kwadrat" name="Square"/> <combo_box.item label="TrójkÄ…t" name="Triangle"/> </combo_box> - <text name="text twist"> + <text name="text twist" left_delta="-5" width="160"> SkrÄ™cenie (poczÄ…tek/koniec) </text> <spinner label="P" name="Twist Begin"/> diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index 7e5ed43475..8151c7eb93 100644 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -2440,7 +2440,7 @@ Spróbuj ponowanie za kilka minut. Propozycja znajomoÅ›ci zostaÅ‚a odrzucona. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] daje Tobie swojÄ… wizytówkÄ™. + [NAME] daje Tobie swojÄ… wizytówkÄ™. Wizytówka bÄ™dzie znajdowaÅ‚a siÄ™ w Szafie i umożliwi szybkie wysÅ‚anie IM do tego Rezydenta. <form name="form"> <button name="Accept" text="Zaakceptuj"/> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_profile.xml b/indra/newview/skins/default/xui/pl/panel_edit_profile.xml index dad8bca183..c409666ec9 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_profile.xml @@ -46,7 +46,7 @@ <text name="my_account_link" value="[[URL] idź do dashboard]"/> <text name="title_partner_text" value="Partner:"/> <panel name="partner_data_panel"> - <text initial_value="(wyszukiwanie)" name="partner_text" value="[FIRST] [LAST]"/> + <text initial_value="(wyszukiwanie)" name="partner_text"/> </panel> <text name="partner_edit_link" value="[[URL] Edytuj]"/> </panel> diff --git a/indra/newview/skins/default/xui/pt/floater_im.xml b/indra/newview/skins/default/xui/pt/floater_im.xml deleted file mode 100644 index c81d0dd7ef..0000000000 --- a/indra/newview/skins/default/xui/pt/floater_im.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<multi_floater name="im_floater" title="Mensagem Instantânea"> - <string name="only_user_message"> - Você é o único residente nesta sessão - </string> - <string name="offline_message"> - [FIRST] [LAST] está offline. - </string> - <string name="invite_message"> - Clique no botão [BUTTON NAME] para aceitar/ conectar a este bate-papo em voz. - </string> - <string name="muted_message"> - Você bloqueou este residente. Se quiser retirar o bloqueio, basta enviar uma mensagem. - </string> - <string name="generic_request_error"> - Erro na requisição, por favor, tente novamente. - </string> - <string name="insufficient_perms_error"> - Você não tem permissões suficientes. - </string> - <string name="session_does_not_exist_error"> - A sessão deixou de existir - </string> - <string name="no_ability_error"> - Você não possui esta habilidade. - </string> - <string name="not_a_mod_error"> - Você não é um moderador de sessão. - </string> - <string name="muted_error"> - Um moderador do grupo desabilitou seu bate-papo em texto. - </string> - <string name="add_session_event"> - Não foi possÃvel adicionar residentes ao bate-papo com [RECIPIENT]. - </string> - <string name="message_session_event"> - Não foi possÃvel enviar sua mensagem na sessão de bate- papo com [RECIPIENT]. - </string> - <string name="removed_from_group"> - Você foi removido do grupo. - </string> - <string name="close_on_no_ability"> - Você não possui mais a habilidade de estar na sessão de bate-papo. - </string> -</multi_floater> diff --git a/indra/newview/skins/default/xui/pt/floater_tools.xml b/indra/newview/skins/default/xui/pt/floater_tools.xml index 2925e286ed..bd5fbf80d1 100644 --- a/indra/newview/skins/default/xui/pt/floater_tools.xml +++ b/indra/newview/skins/default/xui/pt/floater_tools.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="toolbox floater" short_title="BUILD TOOLS" title="" width="288"> +<floater name="toolbox floater" short_title="BUILD TOOLS" title=""> <floater.string name="status_rotate"> Arrastar as faixas coloridas para girar o objeto </floater.string> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index 466a24742d..76399e966c 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -2448,7 +2448,7 @@ Cada um pode ver o status do outro (definição padrão). Oferta de amizada aceita. </notification> <notification name="OfferCallingCard"> - [FIRST] [LAST] estão te oferecendo um cartão de visita. + [NAME] estão te oferecendo um cartão de visita. Ele colocará um item de inventário, para você possa contatá-lo facilmente. <form name="form"> <button name="Accept" text="Aceitar"/> @@ -2552,13 +2552,13 @@ Clique em Aceitar para atender ou em Recusar para recusar este convite. Clique </form> </notification> <notification name="AutoUnmuteByIM"> - [FIRST] recebeu uma MI e foi desbloqueado(a) automaticamente. + [NAME] recebeu uma MI e foi desbloqueado(a) automaticamente. </notification> <notification name="AutoUnmuteByMoney"> - [FIRST] recebeu dinheiro e foi desbloqueado(a) automaticamente. + [NAME] recebeu dinheiro e foi desbloqueado(a) automaticamente. </notification> <notification name="AutoUnmuteByInventory"> - [FIRST] recebeu dinheiro e foi desbloqueado(a) automaticamente. + [NAME] recebeu dinheiro e foi desbloqueado(a) automaticamente. </notification> <notification name="VoiceInviteGroup"> [NAME] atendeu uma ligação de bate-papo de voz com o grupo [GROUP]. diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index db50b89620..b902c7ab09 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -48,6 +48,9 @@ const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid"); const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno"); +const std::string VIEWERLOGIN_CHANNEL("invalid_channel"); +const std::string VIEWERLOGIN_VERSION_CHANNEL("invalid_version"); + // Link seams. //----------------------------------------------------------------------------- @@ -160,7 +163,6 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name) //----------------------------------------------------------------------------- #include "../llviewercontrol.h" LLControlGroup gSavedSettings("Global"); -std::string gCurrentVersion = "invalid_version"; LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name){} @@ -177,6 +179,10 @@ BOOL LLControlGroup::declareString(const std::string& name, const std::string &i #include "lluicolortable.h" void LLUIColorTable::saveUserSettings(void)const {} +//----------------------------------------------------------------------------- +#include "../llversioninfo.h" +const std::string &LLVersionInfo::getVersionAndChannel() { return VIEWERLOGIN_VERSION_CHANNEL; } +const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; } //----------------------------------------------------------------------------- #include "llnotifications.h" @@ -290,7 +296,6 @@ namespace tut gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE); gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE); gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE); - gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE); gSavedSettings.declareString("NextLoginLocation", "", "", FALSE); gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE); diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp new file mode 100644 index 0000000000..8855a24ead --- /dev/null +++ b/indra/newview/tests/llversioninfo_test.cpp @@ -0,0 +1,114 @@ +/** + * @file llversioninfo_test.cpp + * + * $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$ + */ + +#include "linden_common.h" + +#include "../test/lltut.h" + +#include "../llversioninfo.h" +#include "llversionviewer.h" + +namespace tut +{ + struct versioninfo + { + versioninfo() + : mResetChannel("Reset Channel") + { + std::ostringstream stream; + stream << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; + mVersion = stream.str(); + stream.str(""); + + stream << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH; + mShortVersion = stream.str(); + stream.str(""); + + stream << mVersion + << " " + << LL_CHANNEL; + mVersionAndChannel = stream.str(); + stream.str(""); + + stream << mVersion + << " " + << mResetChannel; + mResetVersionAndChannel = stream.str(); + } + std::string mResetChannel; + std::string mVersion; + std::string mShortVersion; + std::string mVersionAndChannel; + std::string mResetVersionAndChannel; + }; + + typedef test_group<versioninfo> versioninfo_t; + typedef versioninfo_t::object versioninfo_object_t; + tut::versioninfo_t tut_versioninfo("LLVersionInfo"); + + template<> template<> + void versioninfo_object_t::test<1>() + { + ensure_equals("Major version", + LLVersionInfo::getMajor(), + LL_VERSION_MAJOR); + ensure_equals("Minor version", + LLVersionInfo::getMinor(), + LL_VERSION_MINOR); + ensure_equals("Patch version", + LLVersionInfo::getPatch(), + LL_VERSION_PATCH); + ensure_equals("Build version", + LLVersionInfo::getBuild(), + LL_VERSION_BUILD); + ensure_equals("Channel version", + LLVersionInfo::getChannel(), + LL_CHANNEL); + + ensure_equals("Version String", + LLVersionInfo::getVersion(), + mVersion); + ensure_equals("Short Version String", + LLVersionInfo::getShortVersion(), + mShortVersion); + ensure_equals("Version and channel String", + LLVersionInfo::getVersionAndChannel(), + mVersionAndChannel); + + LLVersionInfo::resetChannel(mResetChannel); + ensure_equals("Reset channel version", + LLVersionInfo::getChannel(), + mResetChannel); + + ensure_equals("Reset Version and channel String", + LLVersionInfo::getVersionAndChannel(), + mResetVersionAndChannel); + } +} diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp index a0f1d1c3c3..b425b50c8b 100644 --- a/indra/newview/tests/llviewerhelputil_test.cpp +++ b/indra/newview/tests/llviewerhelputil_test.cpp @@ -72,16 +72,13 @@ static void substitute_string(std::string &input, const std::string &search, con } } -class LLAgent -{ -public: - LLAgent() {} - ~LLAgent() {} -#ifdef __GNUC__ - __attribute__ ((noinline)) -#endif - bool isGodlike() const { return FALSE; } -}; +#include "../llagent.h" +LLAgent::LLAgent() : mAgentAccess(gSavedSettings) { } +LLAgent::~LLAgent() { } +bool LLAgent::isGodlike() const { return FALSE; } +LLAgentAccess::LLAgentAccess(LLControlGroup& settings) : mSavedSettings(settings) { } +LLUIColor::LLUIColor() {} + LLAgent gAgent; std::string LLWeb::expandURLSubstitutions(const std::string &url, diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6861f02bfb..1bc118139f 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -247,6 +247,8 @@ class WindowsManifest(ViewerManifest): self.disable_manifest_check() + self.path(src="../viewer_components/updater/scripts/windows/update_install.bat", dst="update_install.bat") + # Get shared libs from the shared libs staging directory if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']), dst=""): @@ -572,6 +574,8 @@ class DarwinManifest(ViewerManifest): # copy additional libs in <bundle>/Contents/MacOS/ self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") + self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install") + # most everything goes in the Resources directory if self.prefix(src="", dst="Resources"): super(DarwinManifest, self).construct() @@ -743,6 +747,11 @@ class DarwinManifest(ViewerManifest): devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() + if devfile != '/dev/disk1': + # adding more debugging info based upon nat's hunches to the + # logs to help track down 'SetFile -a V' failures -brad + print "WARNING: 'SetFile -a V' command below is probably gonna fail" + # Copy everything in to the mounted .dmg if self.default_channel() and not self.default_grid(): @@ -842,6 +851,8 @@ class LinuxManifest(ViewerManifest): # recurse self.end_prefix("res-sdl") + self.path("../viewer_components/updater/scripts/linux/update_install", "bin/update_install") + # plugins if self.prefix(src="", dst="bin/llplugin"): self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") @@ -870,7 +881,7 @@ class LinuxManifest(ViewerManifest): if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" - self.run_command("find %(d)r/bin %(d)r/lib -type f | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure + self.run_command("find %(d)r/bin %(d)r/lib -type f \\! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure # Fix access permissions self.run_command(""" @@ -897,6 +908,9 @@ class LinuxManifest(ViewerManifest): 'dir': self.get_build_prefix(), 'inst_name': installer_name, 'inst_path':self.build_path_of(installer_name)}) + else: + print "Skipping %s.tar.bz2 for non-Release build (%s)" % \ + (installer_name, self.args['buildtype']) finally: self.run_command("mv %(inst)s %(dst)s" % { 'dst': self.get_dst_prefix(), diff --git a/indra/viewer_components/CMakeLists.txt b/indra/viewer_components/CMakeLists.txt index 0993b64b14..74c9b4568d 100644 --- a/indra/viewer_components/CMakeLists.txt +++ b/indra/viewer_components/CMakeLists.txt @@ -1,4 +1,4 @@ # -*- cmake -*- add_subdirectory(login) - +add_subdirectory(updater) diff --git a/indra/viewer_components/updater/CMakeLists.txt b/indra/viewer_components/updater/CMakeLists.txt new file mode 100644 index 0000000000..0e288bb496 --- /dev/null +++ b/indra/viewer_components/updater/CMakeLists.txt @@ -0,0 +1,82 @@ +# -*- cmake -*- + +project(updater_service) + +include(00-Common) +if(LL_TESTS) + include(LLAddBuildTest) +endif(LL_TESTS) +include(CMakeCopyIfDifferent) +include(CURL) +include(LLCommon) +include(LLMessage) +include(LLPlugin) +include(LLVFS) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLPLUGIN_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} + ${CURL_INCLUDE_DIRS} + ) + +set(updater_service_SOURCE_FILES + llupdaterservice.cpp + llupdatechecker.cpp + llupdatedownloader.cpp + llupdateinstaller.cpp + ) + +set(updater_service_HEADER_FILES + llupdaterservice.h + llupdatechecker.h + llupdatedownloader.h + llupdateinstaller.h + ) + +set_source_files_properties(${updater_service_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND + updater_service_SOURCE_FILES + ${updater_service_HEADER_FILES} + ) + +add_library(llupdaterservice + ${updater_service_SOURCE_FILES} + ) + +target_link_libraries(llupdaterservice + ${LLCOMMON_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLPLUGIN_LIBRARIES} + ${LLVFS_LIBRARIES} + ) + +if(LL_TESTS) + SET(llupdater_service_TEST_SOURCE_FILES + llupdaterservice.cpp + ) + +# *NOTE:Mani - I was trying to use the preprocessor seam to mock out +# llifstream (and other) llcommon classes. I didn't work +# because of the windows declspec(dllimport)attribute. +#set_source_files_properties( +# llupdaterservice.cpp +# PROPERTIES +# LL_TEST_ADDITIONAL_CFLAGS "-Dllifstream=llus_mock_llifstream" +# ) + + LL_ADD_PROJECT_UNIT_TESTS(llupdaterservice "${llupdater_service_TEST_SOURCE_FILES}") +endif(LL_TESTS) + +set(UPDATER_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/viewer_components/updater + CACHE INTERNAL "" +) + +set(UPDATER_LIBRARIES + llupdaterservice + CACHE INTERNAL "" +) diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp new file mode 100644 index 0000000000..c6aa9b0f11 --- /dev/null +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -0,0 +1,194 @@ +/** + * @file llupdaterservice.cpp + * + * $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$ + */ + +#include "linden_common.h" +#include <stdexcept> +#include <boost/format.hpp> +#include "llhttpclient.h" +#include "llsd.h" +#include "llupdatechecker.h" +#include "lluri.h" + + +#if LL_WINDOWS +#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally +#endif + + +class LLUpdateChecker::CheckError: + public std::runtime_error +{ +public: + CheckError(const char * message): + std::runtime_error(message) + { + ; // No op. + } +}; + + +class LLUpdateChecker::Implementation: + public LLHTTPClient::Responder +{ +public: + Implementation(Client & client); + ~Implementation(); + void check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); + + // Responder: + virtual void completed(U32 status, + const std::string & reason, + const LLSD& content); + virtual void error(U32 status, const std::string & reason); + +private: + static const char * sProtocolVersion; + + Client & mClient; + LLHTTPClient mHttpClient; + bool mInProgress; + std::string mVersion; + + std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); + + LOG_CLASS(LLUpdateChecker::Implementation); +}; + + + +// LLUpdateChecker +//----------------------------------------------------------------------------- + + +LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client): + mImplementation(new LLUpdateChecker::Implementation(client)) +{ + ; // No op. +} + + +void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) +{ + mImplementation->check(protocolVersion, hostUrl, servicePath, channel, version); +} + + + +// LLUpdateChecker::Implementation +//----------------------------------------------------------------------------- + + +const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.0"; + + +LLUpdateChecker::Implementation::Implementation(LLUpdateChecker::Client & client): + mClient(client), + mInProgress(false) +{ + ; // No op. +} + + +LLUpdateChecker::Implementation::~Implementation() +{ + ; // No op. +} + + +void LLUpdateChecker::Implementation::check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) +{ + llassert(!mInProgress); + + if(protocolVersion != sProtocolVersion) throw CheckError("unsupported protocol"); + + mInProgress = true; + mVersion = version; + std::string checkUrl = buildUrl(protocolVersion, hostUrl, servicePath, channel, version); + LL_INFOS("UpdateCheck") << "checking for updates at " << checkUrl << llendl; + + // The HTTP client will wrap a raw pointer in a boost::intrusive_ptr causing the + // passed object to be silently and automatically deleted. We pass a self- + // referential intrusive pointer to which we add a reference to keep the + // client from deleting the update checker implementation instance. + LLHTTPClient::ResponderPtr temporaryPtr(this); + boost::intrusive_ptr_add_ref(temporaryPtr.get()); + mHttpClient.get(checkUrl, temporaryPtr); +} + +void LLUpdateChecker::Implementation::completed(U32 status, + const std::string & reason, + const LLSD & content) +{ + mInProgress = false; + + if(status != 200) { + LL_WARNS("UpdateCheck") << "html error " << status << " (" << reason << ")" << llendl; + mClient.error(reason); + } else if(!content.asBoolean()) { + LL_INFOS("UpdateCheck") << "up to date" << llendl; + mClient.upToDate(); + } else if(content["required"].asBoolean()) { + LL_INFOS("UpdateCheck") << "version invalid" << llendl; + LLURI uri(content["url"].asString()); + mClient.requiredUpdate(content["version"].asString(), uri, content["hash"].asString()); + } else { + LL_INFOS("UpdateCheck") << "newer version " << content["version"].asString() << " available" << llendl; + LLURI uri(content["url"].asString()); + mClient.optionalUpdate(content["version"].asString(), uri, content["hash"].asString()); + } +} + + +void LLUpdateChecker::Implementation::error(U32 status, const std::string & reason) +{ + mInProgress = false; + LL_WARNS("UpdateCheck") << "update check failed; " << reason << llendl; + mClient.error(reason); +} + + +std::string LLUpdateChecker::Implementation::buildUrl(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) +{ +#ifdef LL_WINDOWS + static const char * platform = "win"; +#elif LL_DARWIN + static const char * platform = "mac"; +#else + static const char * platform = "lnx"; +#endif + + LLSD path; + path.append(servicePath); + path.append(protocolVersion); + path.append(channel); + path.append(version); + path.append(platform); + return LLURI::buildHTTP(hostUrl, path).asString(); +} diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h new file mode 100644 index 0000000000..cea1f13647 --- /dev/null +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -0,0 +1,82 @@ +/** + * @file llupdatechecker.h + * + * $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$ + */ + +#ifndef LL_UPDATERCHECKER_H +#define LL_UPDATERCHECKER_H + + +#include <boost/shared_ptr.hpp> + + +// +// Implements asynchronous checking for updates. +// +class LLUpdateChecker { +public: + class Client; + class Implementation; + + // An exception that may be raised on check errors. + class CheckError; + + LLUpdateChecker(Client & client); + + // Check status of current app on the given host for the channel and version provided. + void check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); + +private: + boost::shared_ptr<Implementation> mImplementation; +}; + + +class LLURI; // From lluri.h + + +// +// The client interface implemented by a requestor checking for an update. +// +class LLUpdateChecker::Client +{ +public: + // An error occurred while checking for an update. + virtual void error(std::string const & message) = 0; + + // A newer version is available, but the current version may still be used. + virtual void optionalUpdate(std::string const & newVersion, + LLURI const & uri, + std::string const & hash) = 0; + + // A newer version is available, and the current version is no longer valid. + virtual void requiredUpdate(std::string const & newVersion, + LLURI const & uri, + std::string const & hash) = 0; + + // The checked version is up to date; no newer version exists. + virtual void upToDate(void) = 0; +}; + + +#endif diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp new file mode 100644 index 0000000000..c17a50e242 --- /dev/null +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -0,0 +1,428 @@ +/** + * @file llupdatedownloader.cpp + * + * $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$ + */ + +#include "linden_common.h" +#include <stdexcept> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> +#include <curl/curl.h> +#include "lldir.h" +#include "llfile.h" +#include "llmd5.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llthread.h" +#include "llupdatedownloader.h" +#include "llupdaterservice.h" + + +class LLUpdateDownloader::Implementation: + public LLThread +{ +public: + Implementation(LLUpdateDownloader::Client & client); + ~Implementation(); + void cancel(void); + void download(LLURI const & uri, std::string const & hash); + bool isDownloading(void); + size_t onHeader(void * header, size_t size); + size_t onBody(void * header, size_t size); + void resume(void); + +private: + bool mCancelled; + LLUpdateDownloader::Client & mClient; + CURL * mCurl; + LLSD mDownloadData; + llofstream mDownloadStream; + std::string mDownloadRecordPath; + curl_slist * mHeaderList; + + void initializeCurlGet(std::string const & url, bool processHeader); + void resumeDownloading(size_t startByte); + void run(void); + void startDownloading(LLURI const & uri, std::string const & hash); + void throwOnCurlError(CURLcode code); + bool validateDownload(void); + + LOG_CLASS(LLUpdateDownloader::Implementation); +}; + + +namespace { + class DownloadError: + public std::runtime_error + { + public: + DownloadError(const char * message): + std::runtime_error(message) + { + ; // No op. + } + }; + + + const char * gSecondLifeUpdateRecord = "SecondLifeUpdateDownload.xml"; +}; + + + +// LLUpdateDownloader +//----------------------------------------------------------------------------- + + + +std::string LLUpdateDownloader::downloadMarkerPath(void) +{ + return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, gSecondLifeUpdateRecord); +} + + +LLUpdateDownloader::LLUpdateDownloader(Client & client): + mImplementation(new LLUpdateDownloader::Implementation(client)) +{ + ; // No op. +} + + +void LLUpdateDownloader::cancel(void) +{ + mImplementation->cancel(); +} + + +void LLUpdateDownloader::download(LLURI const & uri, std::string const & hash) +{ + mImplementation->download(uri, hash); +} + + +bool LLUpdateDownloader::isDownloading(void) +{ + return mImplementation->isDownloading(); +} + + +void LLUpdateDownloader::resume(void) +{ + mImplementation->resume(); +} + + + +// LLUpdateDownloader::Implementation +//----------------------------------------------------------------------------- + + +namespace { + size_t write_function(void * data, size_t blockSize, size_t blocks, void * downloader) + { + size_t bytes = blockSize * blocks; + return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onBody(data, bytes); + } + + + size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader) + { + size_t bytes = blockSize * blocks; + return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onHeader(data, bytes); + } +} + + +LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client): + LLThread("LLUpdateDownloader"), + mCancelled(false), + mClient(client), + mCurl(0), + mHeaderList(0) +{ + CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. + llverify(code == CURLE_OK); // TODO: real error handling here. +} + + +LLUpdateDownloader::Implementation::~Implementation() +{ + if(isDownloading()) { + cancel(); + shutdown(); + } else { + ; // No op. + } + if(mCurl) curl_easy_cleanup(mCurl); +} + + +void LLUpdateDownloader::Implementation::cancel(void) +{ + mCancelled = true; +} + + +void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash) +{ + if(isDownloading()) mClient.downloadError("download in progress"); + + mDownloadRecordPath = downloadMarkerPath(); + mDownloadData = LLSD(); + try { + startDownloading(uri, hash); + } catch(DownloadError const & e) { + mClient.downloadError(e.what()); + } +} + + +bool LLUpdateDownloader::Implementation::isDownloading(void) +{ + return !isStopped(); +} + + +void LLUpdateDownloader::Implementation::resume(void) +{ + mCancelled = false; + + if(isDownloading()) { + mClient.downloadError("download in progress"); + } + + mDownloadRecordPath = downloadMarkerPath(); + llifstream dataStream(mDownloadRecordPath); + if(!dataStream) { + mClient.downloadError("no download marker"); + return; + } + + LLSDSerialize::fromXMLDocument(mDownloadData, dataStream); + + if(!mDownloadData.asBoolean()) { + mClient.downloadError("no download information in marker"); + return; + } + + std::string filePath = mDownloadData["path"].asString(); + try { + if(LLFile::isfile(filePath)) { + llstat fileStatus; + LLFile::stat(filePath, &fileStatus); + if(fileStatus.st_size != mDownloadData["size"].asInteger()) { + resumeDownloading(fileStatus.st_size); + } else if(!validateDownload()) { + LLFile::remove(filePath); + download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); + } else { + mClient.downloadComplete(mDownloadData); + } + } else { + download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); + } + } catch(DownloadError & e) { + mClient.downloadError(e.what()); + } +} + + +size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) +{ + char const * headerPtr = reinterpret_cast<const char *> (buffer); + std::string header(headerPtr, headerPtr + size); + size_t colonPosition = header.find(':'); + if(colonPosition == std::string::npos) return size; // HTML response; ignore. + + if(header.substr(0, colonPosition) == "Content-Length") { + try { + size_t firstDigitPos = header.find_first_of("0123456789", colonPosition); + size_t lastDigitPos = header.find_last_of("0123456789"); + std::string contentLength = header.substr(firstDigitPos, lastDigitPos - firstDigitPos + 1); + size_t size = boost::lexical_cast<size_t>(contentLength); + LL_INFOS("UpdateDownload") << "download size is " << size << LL_ENDL; + + mDownloadData["size"] = LLSD(LLSD::Integer(size)); + llofstream odataStream(mDownloadRecordPath); + LLSDSerialize::toPrettyXML(mDownloadData, odataStream); + } catch (std::exception const & e) { + LL_WARNS("UpdateDownload") << "unable to read content length (" + << e.what() << ")" << LL_ENDL; + } + } else { + ; // No op. + } + + return size; +} + + +size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) +{ + if(mCancelled) return 0; // Forces a write error which will halt curl thread. + if((size == 0) || (buffer == 0)) return 0; + + mDownloadStream.write(reinterpret_cast<const char *>(buffer), size); + if(mDownloadStream.bad()) { + return 0; + } else { + return size; + } +} + + +void LLUpdateDownloader::Implementation::run(void) +{ + CURLcode code = curl_easy_perform(mCurl); + mDownloadStream.close(); + if(code == CURLE_OK) { + LLFile::remove(mDownloadRecordPath); + if(validateDownload()) { + LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; + mClient.downloadComplete(mDownloadData); + } else { + LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL; + std::string filePath = mDownloadData["path"].asString(); + if(filePath.size() != 0) LLFile::remove(filePath); + mClient.downloadError("failed hash check"); + } + } else if(mCancelled && (code == CURLE_WRITE_ERROR)) { + LL_INFOS("UpdateDownload") << "download canceled by user" << LL_ENDL; + // Do not call back client. + } else { + LL_WARNS("UpdateDownload") << "download failed with error '" << + curl_easy_strerror(code) << "'" << LL_ENDL; + LLFile::remove(mDownloadRecordPath); + if(mDownloadData.has("path")) LLFile::remove(mDownloadData["path"].asString()); + mClient.downloadError("curl error"); + } + + if(mHeaderList) { + curl_slist_free_all(mHeaderList); + mHeaderList = 0; + } +} + + +void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader) +{ + if(mCurl == 0) { + mCurl = curl_easy_init(); + } else { + curl_easy_reset(mCurl); + } + + if(mCurl == 0) throw DownloadError("failed to initialize curl"); + + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this)); + if(processHeader) { + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this)); + } + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str())); +} + + +void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte) +{ + LL_INFOS("UpdateDownload") << "resuming download from " << mDownloadData["url"].asString() + << " at byte " << startByte << LL_ENDL; + + initializeCurlGet(mDownloadData["url"].asString(), false); + + // The header 'Range: bytes n-' will request the bytes remaining in the + // source begining with byte n and ending with the last byte. + boost::format rangeHeaderFormat("Range: bytes=%u-"); + rangeHeaderFormat % startByte; + mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str()); + if(mHeaderList == 0) throw DownloadError("cannot add Range header"); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList)); + + mDownloadStream.open(mDownloadData["path"].asString(), + std::ios_base::out | std::ios_base::binary | std::ios_base::app); + start(); +} + + +void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash) +{ + mDownloadData["url"] = uri.asString(); + mDownloadData["hash"] = hash; + mDownloadData["current_version"] = ll_get_version(); + LLSD path = uri.pathArray(); + if(path.size() == 0) throw DownloadError("no file path"); + std::string fileName = path[path.size() - 1].asString(); + std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName); + mDownloadData["path"] = filePath; + + LL_INFOS("UpdateDownload") << "downloading " << filePath + << " from " << uri.asString() << LL_ENDL; + LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL; + + llofstream dataStream(mDownloadRecordPath); + LLSDSerialize::toPrettyXML(mDownloadData, dataStream); + + mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary); + initializeCurlGet(uri.asString(), true); + start(); +} + + +void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code) +{ + if(code != CURLE_OK) { + const char * errorString = curl_easy_strerror(code); + if(errorString != 0) { + throw DownloadError(curl_easy_strerror(code)); + } else { + throw DownloadError("unknown curl error"); + } + } else { + ; // No op. + } +} + + +bool LLUpdateDownloader::Implementation::validateDownload(void) +{ + std::string filePath = mDownloadData["path"].asString(); + llifstream fileStream(filePath, std::ios_base::in | std::ios_base::binary); + if(!fileStream) return false; + + std::string hash = mDownloadData["hash"].asString(); + if(hash.size() != 0) { + LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL; + char digest[33]; + LLMD5(fileStream).hex_digest(digest); + if(hash != digest) { + LL_WARNS("UpdateDownload") << "download hash mismatch; expeted " << hash << + " but download is " << digest << LL_ENDL; + } + return hash == digest; + } else { + return true; // No hash check provided. + } +} diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h new file mode 100644 index 0000000000..1b3d7480fd --- /dev/null +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -0,0 +1,87 @@ +/** + * @file llupdatedownloader.h + * + * $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$ + */ + +#ifndef LL_UPDATE_DOWNLOADER_H +#define LL_UPDATE_DOWNLOADER_H + + +#include <string> +#include <boost/shared_ptr.hpp> +#include "lluri.h" + + +// +// An asynchronous download service for fetching updates. +// +class LLUpdateDownloader +{ +public: + class Client; + class Implementation; + + // Returns the path to the download marker file containing details of the + // latest download. + static std::string downloadMarkerPath(void); + + LLUpdateDownloader(Client & client); + + // Cancel any in progress download; a no op if none is in progress. The + // client will not receive a complete or error callback. + void cancel(void); + + // Start a new download. + void download(LLURI const & uri, std::string const & hash); + + // Returns true if a download is in progress. + bool isDownloading(void); + + // Resume a partial download. + void resume(void); + +private: + boost::shared_ptr<Implementation> mImplementation; +}; + + +// +// An interface to be implemented by clients initiating a update download. +// +class LLUpdateDownloader::Client { +public: + + // The download has completed successfully. + // data is a map containing the following items: + // url - source (remote) location + // hash - the md5 sum that should match the installer file. + // path - destination (local) location + // size - the size of the installer in bytes + virtual void downloadComplete(LLSD const & data) = 0; + + // The download failed. + virtual void downloadError(std::string const & message) = 0; +}; + + +#endif diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp new file mode 100644 index 0000000000..6e69bcf28b --- /dev/null +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -0,0 +1,90 @@ +/** + * @file llupdateinstaller.cpp + * + * $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$ + */ + +#include "linden_common.h" +#include <apr_file_io.h> +#include "llapr.h" +#include "llprocesslauncher.h" +#include "llupdateinstaller.h" +#include "lldir.h" + + +namespace { + class RelocateError {}; + + + std::string copy_to_temp(std::string const & path) + { + std::string scriptFile = gDirUtilp->getBaseFileName(path); + std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile); + apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp); + if(status != APR_SUCCESS) throw RelocateError(); + + return newPath; + } +} + + +int ll_install_update(std::string const & script, std::string const & updatePath, LLInstallScriptMode mode) +{ + std::string actualScriptPath; + switch(mode) { + case LL_COPY_INSTALL_SCRIPT_TO_TEMP: + try { + actualScriptPath = copy_to_temp(script); + } + catch (RelocateError &) { + return -1; + } + break; + case LL_RUN_INSTALL_SCRIPT_IN_PLACE: + actualScriptPath = script; + break; + default: + llassert(!"unpossible copy mode"); + } + + llinfos << "UpdateInstaller: installing " << updatePath << " using " << + actualScriptPath << LL_ENDL; + + LLProcessLauncher launcher; + launcher.setExecutable(actualScriptPath); + launcher.addArgument(updatePath); + launcher.addArgument(ll_install_failed_marker_path().c_str()); + int result = launcher.launch(); + launcher.orphan(); + + return result; +} + + +std::string const & ll_install_failed_marker_path(void) +{ + static std::string path; + if(path.empty()) { + path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeInstallFailed.marker"); + } + return path; +} diff --git a/indra/viewer_components/updater/llupdateinstaller.h b/indra/viewer_components/updater/llupdateinstaller.h new file mode 100644 index 0000000000..6ce08ce6fa --- /dev/null +++ b/indra/viewer_components/updater/llupdateinstaller.h @@ -0,0 +1,57 @@ +/** + * @file llupdateinstaller.h + * + * $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$ + */ + +#ifndef LL_UPDATE_INSTALLER_H +#define LL_UPDATE_INSTALLER_H + + +#include <string> + + +enum LLInstallScriptMode { + LL_RUN_INSTALL_SCRIPT_IN_PLACE, + LL_COPY_INSTALL_SCRIPT_TO_TEMP +}; + +// +// Launch the installation script. +// +// The updater will overwrite the current installation, so it is highly recommended +// that the current application terminate once this function is called. +// +int ll_install_update( + std::string const & script, // Script to execute. + std::string const & updatePath, // Path to update file. + LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp? + + +// +// Returns the path which points to the failed install marker file, should it +// exist. +// +std::string const & ll_install_failed_marker_path(void); + + +#endif diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp new file mode 100644 index 0000000000..cc60eaead2 --- /dev/null +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -0,0 +1,519 @@ +/** + * @file llupdaterservice.cpp + * + * $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$ + */ + +#include "linden_common.h" + +#include "llupdatedownloader.h" +#include "llevents.h" +#include "lltimer.h" +#include "llupdaterservice.h" +#include "llupdatechecker.h" +#include "llupdateinstaller.h" +#include "llversionviewer.h" + +#include <boost/scoped_ptr.hpp> +#include <boost/weak_ptr.hpp> +#include "lldir.h" +#include "llsdserialize.h" +#include "llfile.h" + +#if LL_WINDOWS +#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally +#endif + + +namespace +{ + boost::weak_ptr<LLUpdaterServiceImpl> gUpdater; + + const std::string UPDATE_MARKER_FILENAME("SecondLifeUpdateReady.xml"); + std::string update_marker_path() + { + return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + UPDATE_MARKER_FILENAME); + } + + std::string install_script_path(void) + { +#ifdef LL_WINDOWS + std::string scriptFile = "update_install.bat"; +#else + std::string scriptFile = "update_install"; +#endif + return gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, scriptFile); + } + + LLInstallScriptMode install_script_mode(void) + { +#ifdef LL_WINDOWS + return LL_COPY_INSTALL_SCRIPT_TO_TEMP; +#else + return LL_RUN_INSTALL_SCRIPT_IN_PLACE; +#endif + }; + +} + +class LLUpdaterServiceImpl : + public LLUpdateChecker::Client, + public LLUpdateDownloader::Client +{ + static const std::string sListenerName; + + std::string mProtocolVersion; + std::string mUrl; + std::string mPath; + std::string mChannel; + std::string mVersion; + + unsigned int mCheckPeriod; + bool mIsChecking; + bool mIsDownloading; + + LLUpdateChecker mUpdateChecker; + LLUpdateDownloader mUpdateDownloader; + LLTimer mTimer; + + LLUpdaterService::app_exit_callback_t mAppExitCallback; + + LOG_CLASS(LLUpdaterServiceImpl); + +public: + LLUpdaterServiceImpl(); + virtual ~LLUpdaterServiceImpl(); + + void initialize(const std::string& protocol_version, + const std::string& url, + const std::string& path, + const std::string& channel, + const std::string& version); + + void setCheckPeriod(unsigned int seconds); + + void startChecking(bool install_if_ready); + void stopChecking(); + bool isChecking(); + + void setAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) { mAppExitCallback = aecb;} + + bool checkForInstall(bool launchInstaller); // Test if a local install is ready. + bool checkForResume(); // Test for resumeable d/l. + + // LLUpdateChecker::Client: + virtual void error(std::string const & message); + virtual void optionalUpdate(std::string const & newVersion, + LLURI const & uri, + std::string const & hash); + virtual void requiredUpdate(std::string const & newVersion, + LLURI const & uri, + std::string const & hash); + virtual void upToDate(void); + + // LLUpdateDownloader::Client + void downloadComplete(LLSD const & data); + void downloadError(std::string const & message); + + bool onMainLoop(LLSD const & event); + +private: + void restartTimer(unsigned int seconds); + void stopTimer(); +}; + +const std::string LLUpdaterServiceImpl::sListenerName = "LLUpdaterServiceImpl"; + +LLUpdaterServiceImpl::LLUpdaterServiceImpl() : + mIsChecking(false), + mIsDownloading(false), + mCheckPeriod(0), + mUpdateChecker(*this), + mUpdateDownloader(*this) +{ +} + +LLUpdaterServiceImpl::~LLUpdaterServiceImpl() +{ + LL_INFOS("UpdaterService") << "shutting down updater service" << LL_ENDL; + LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName); +} + +void LLUpdaterServiceImpl::initialize(const std::string& protocol_version, + const std::string& url, + const std::string& path, + const std::string& channel, + const std::string& version) +{ + if(mIsChecking || mIsDownloading) + { + throw LLUpdaterService::UsageError("LLUpdaterService::initialize call " + "while updater is running."); + } + + mProtocolVersion = protocol_version; + mUrl = url; + mPath = path; + mChannel = channel; + mVersion = version; +} + +void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds) +{ + mCheckPeriod = seconds; +} + +void LLUpdaterServiceImpl::startChecking(bool install_if_ready) +{ + if(mUrl.empty() || mChannel.empty() || mVersion.empty()) + { + throw LLUpdaterService::UsageError("Set params before call to " + "LLUpdaterService::startCheck()."); + } + + mIsChecking = true; + + // Check to see if an install is ready. + bool has_install = checkForInstall(install_if_ready); + if(!has_install) + { + checkForResume(); // will set mIsDownloading to true if resuming + + if(!mIsDownloading) + { + // Checking can only occur during the mainloop. + // reset the timer to 0 so that the next mainloop event + // triggers a check; + restartTimer(0); + } + } +} + +void LLUpdaterServiceImpl::stopChecking() +{ + if(mIsChecking) + { + mIsChecking = false; + stopTimer(); + } + + if(mIsDownloading) + { + mUpdateDownloader.cancel(); + mIsDownloading = false; + } +} + +bool LLUpdaterServiceImpl::isChecking() +{ + return mIsChecking; +} + +bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller) +{ + bool foundInstall = false; // return true if install is found. + + llifstream update_marker(update_marker_path(), + std::ios::in | std::ios::binary); + + if(update_marker.is_open()) + { + // Found an update info - now lets see if its valid. + LLSD update_info; + LLSDSerialize::fromXMLDocument(update_info, update_marker); + update_marker.close(); + + // Get the path to the installer file. + LLSD path = update_info.get("path"); + if(update_info["current_version"].asString() != ll_get_version()) + { + // This viewer is not the same version as the one that downloaded + // the update. Do not install this update. + if(!path.asString().empty()) + { + llinfos << "ignoring update dowloaded by different client version" << llendl; + LLFile::remove(path.asString()); + LLFile::remove(update_marker_path()); + } + else + { + ; // Nothing to clean up. + } + + foundInstall = false; + } + else if(path.isDefined() && !path.asString().empty()) + { + if(launchInstaller) + { + LLFile::remove(update_marker_path()); + + int result = ll_install_update(install_script_path(), + update_info["path"].asString(), + install_script_mode()); + + if((result == 0) && mAppExitCallback) + { + mAppExitCallback(); + } else if(result != 0) { + llwarns << "failed to run update install script" << LL_ENDL; + } else { + ; // No op. + } + } + + foundInstall = true; + } + } + return foundInstall; +} + +bool LLUpdaterServiceImpl::checkForResume() +{ + bool result = false; + std::string download_marker_path = mUpdateDownloader.downloadMarkerPath(); + if(LLFile::isfile(download_marker_path)) + { + llifstream download_marker_stream(download_marker_path, + std::ios::in | std::ios::binary); + if(download_marker_stream.is_open()) + { + LLSD download_info; + LLSDSerialize::fromXMLDocument(download_info, download_marker_stream); + download_marker_stream.close(); + if(download_info["current_version"].asString() == ll_get_version()) + { + mIsDownloading = true; + mUpdateDownloader.resume(); + result = true; + } + else + { + // The viewer that started this download is not the same as this viewer; ignore. + llinfos << "ignoring partial download from different viewer version" << llendl; + std::string path = download_info["path"].asString(); + if(!path.empty()) LLFile::remove(path); + LLFile::remove(download_marker_path); + } + } + } + return result; +} + +void LLUpdaterServiceImpl::error(std::string const & message) +{ + if(mIsChecking) + { + restartTimer(mCheckPeriod); + } +} + +void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, + LLURI const & uri, + std::string const & hash) +{ + stopTimer(); + mIsDownloading = true; + mUpdateDownloader.download(uri, hash); +} + +void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, + LLURI const & uri, + std::string const & hash) +{ + stopTimer(); + mIsDownloading = true; + mUpdateDownloader.download(uri, hash); +} + +void LLUpdaterServiceImpl::upToDate(void) +{ + if(mIsChecking) + { + restartTimer(mCheckPeriod); + } +} + +void LLUpdaterServiceImpl::downloadComplete(LLSD const & data) +{ + mIsDownloading = false; + + // Save out the download data to the SecondLifeUpdateReady + // marker file. + llofstream update_marker(update_marker_path()); + LLSDSerialize::toPrettyXML(data, update_marker); + + LLSD event; + event["pump"] = LLUpdaterService::pumpName(); + LLSD payload; + payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_COMPLETE); + event["payload"] = payload; + LLEventPumps::instance().obtain("mainlooprepeater").post(event); +} + +void LLUpdaterServiceImpl::downloadError(std::string const & message) +{ + LL_INFOS("UpdaterService") << "Error downloading: " << message << LL_ENDL; + + mIsDownloading = false; + + // Restart the timer on error + if(mIsChecking) + { + restartTimer(mCheckPeriod); + } + + LLSD event; + event["pump"] = LLUpdaterService::pumpName(); + LLSD payload; + payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_ERROR); + payload["message"] = message; + event["payload"] = payload; + LLEventPumps::instance().obtain("mainlooprepeater").post(event); +} + +void LLUpdaterServiceImpl::restartTimer(unsigned int seconds) +{ + LL_INFOS("UpdaterService") << "will check for update again in " << + seconds << " seconds" << LL_ENDL; + mTimer.start(); + mTimer.setTimerExpirySec(seconds); + LLEventPumps::instance().obtain("mainloop").listen( + sListenerName, boost::bind(&LLUpdaterServiceImpl::onMainLoop, this, _1)); +} + +void LLUpdaterServiceImpl::stopTimer() +{ + mTimer.stop(); + LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName); +} + +bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event) +{ + if(mTimer.getStarted() && mTimer.hasExpired()) + { + stopTimer(); + + // Check for failed install. + if(LLFile::isfile(ll_install_failed_marker_path())) + { + // TODO: notify the user. + llinfos << "found marker " << ll_install_failed_marker_path() << llendl; + llinfos << "last install attempt failed" << llendl; + LLFile::remove(ll_install_failed_marker_path()); + + LLSD event; + event["type"] = LLSD(LLUpdaterService::INSTALL_ERROR); + LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).post(event); + } + else + { + mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion); + } + } + else + { + // Keep on waiting... + } + + return false; +} + + +//----------------------------------------------------------------------- +// Facade interface + +std::string const & LLUpdaterService::pumpName(void) +{ + static std::string name("updater_service"); + return name; +} + +LLUpdaterService::LLUpdaterService() +{ + if(gUpdater.expired()) + { + mImpl = + boost::shared_ptr<LLUpdaterServiceImpl>(new LLUpdaterServiceImpl()); + gUpdater = mImpl; + } + else + { + mImpl = gUpdater.lock(); + } +} + +LLUpdaterService::~LLUpdaterService() +{ +} + +void LLUpdaterService::initialize(const std::string& protocol_version, + const std::string& url, + const std::string& path, + const std::string& channel, + const std::string& version) +{ + mImpl->initialize(protocol_version, url, path, channel, version); +} + +void LLUpdaterService::setCheckPeriod(unsigned int seconds) +{ + mImpl->setCheckPeriod(seconds); +} + +void LLUpdaterService::startChecking(bool install_if_ready) +{ + mImpl->startChecking(install_if_ready); +} + +void LLUpdaterService::stopChecking() +{ + mImpl->stopChecking(); +} + +bool LLUpdaterService::isChecking() +{ + return mImpl->isChecking(); +} + +void LLUpdaterService::setImplAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) +{ + return mImpl->setAppExitCallback(aecb); +} + + +std::string const & ll_get_version(void) { + static std::string version(""); + + if (version.empty()) { + std::ostringstream stream; + stream << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; + version = stream.str(); + } + + return version; +} + diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h new file mode 100644 index 0000000000..752a6f834b --- /dev/null +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -0,0 +1,85 @@ +/** + * @file llupdaterservice.h + * + * $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$ + */ + +#ifndef LL_UPDATERSERVICE_H +#define LL_UPDATERSERVICE_H + +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> + +class LLUpdaterServiceImpl; + +class LLUpdaterService +{ +public: + class UsageError: public std::runtime_error + { + public: + UsageError(const std::string& msg) : std::runtime_error(msg) {} + }; + + // Name of the event pump through which update events will be delivered. + static std::string const & pumpName(void); + + // Type codes for events posted by this service. Stored the event's 'type' element. + enum eUpdateEvent { + INVALID, + DOWNLOAD_COMPLETE, + DOWNLOAD_ERROR, + INSTALL_ERROR + }; + + LLUpdaterService(); + ~LLUpdaterService(); + + void initialize(const std::string& protocol_version, + const std::string& url, + const std::string& path, + const std::string& channel, + const std::string& version); + + void setCheckPeriod(unsigned int seconds); + + void startChecking(bool install_if_ready = false); + void stopChecking(); + bool isChecking(); + + typedef boost::function<void (void)> app_exit_callback_t; + template <typename F> + void setAppExitCallback(F const &callable) + { + app_exit_callback_t aecb = callable; + setImplAppExitCallback(aecb); + } + +private: + boost::shared_ptr<LLUpdaterServiceImpl> mImpl; + void setImplAppExitCallback(app_exit_callback_t aecb); +}; + +// Returns the full version as a string. +std::string const & ll_get_version(void); + +#endif // LL_UPDATERSERVICE_H diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install new file mode 100644 index 0000000000..b174b3570a --- /dev/null +++ b/indra/viewer_components/updater/scripts/darwin/update_install @@ -0,0 +1,9 @@ +#! /bin/bash + +# +# The first argument contains the path to the installer app. The second a path +# to a marker file which should be created if the installer fails.q +# + +open ../Resources/mac-updater.app --args -dmg "$1" -name "Second Life Viewer 2" -marker "$2" +exit 0 diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install new file mode 100644 index 0000000000..fef5ef7d09 --- /dev/null +++ b/indra/viewer_components/updater/scripts/linux/update_install @@ -0,0 +1,10 @@ +#! /bin/bash +INSTALL_DIR=$(cd "$(dirname $0)/.." ; pwd) +export LD_LIBRARY_PATH=$INSTALL_DIR/lib +bin/linux-updater.bin --file "$1" --dest "$INSTALL_DIR" --name "Second Life Viewer 2" --stringsdir "$INSTALL_DIR/skins/default/xui/en" --stringsfile "strings.xml" + +if [ $? -ne 0 ] + then touch $2 +fi + +rm -f $1 diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat new file mode 100644 index 0000000000..42e148a707 --- /dev/null +++ b/indra/viewer_components/updater/scripts/windows/update_install.bat @@ -0,0 +1,3 @@ +start /WAIT %1 /SKIP_DIALOGS
+IF ERRORLEVEL 1 ECHO %ERRORLEVEL% > %2
+DEL %1
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp new file mode 100644 index 0000000000..04ed4e6364 --- /dev/null +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -0,0 +1,199 @@ +/**
+ * @file llupdaterservice_test.cpp
+ * @brief Tests of llupdaterservice.cpp.
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "../llupdaterservice.h"
+#include "../llupdatechecker.h"
+#include "../llupdatedownloader.h"
+#include "../llupdateinstaller.h"
+
+#include "../../../test/lltut.h"
+//#define DEBUG_ON
+#include "../../../test/debug.h"
+
+#include "llevents.h"
+#include "lldir.h"
+
+/*****************************************************************************
+* MOCK'd
+*****************************************************************************/
+LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client)
+{}
+void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{}
+LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
+void LLUpdateDownloader::download(LLURI const & , std::string const &){}
+
+class LLDir_Mock : public LLDir
+{
+ void initAppDirs(const std::string &app_name,
+ const std::string& app_read_only_data_dir = "") {}
+ U32 countFilesInDir(const std::string &dirname, const std::string &mask)
+ {
+ return 0;
+ }
+
+ BOOL getNextFileInDir(const std::string &dirname,
+ const std::string &mask,
+ std::string &fname)
+ {
+ return false;
+ }
+ void getRandomFileInDir(const std::string &dirname,
+ const std::string &mask,
+ std::string &fname) {}
+ std::string getCurPath() { return ""; }
+ BOOL fileExists(const std::string &filename) const { return false; }
+ std::string getLLPluginLauncher() { return ""; }
+ std::string getLLPluginFilename(std::string base_name) { return ""; }
+
+} gDirUtil;
+LLDir* gDirUtilp = &gDirUtil;
+LLDir::LLDir() {}
+LLDir::~LLDir() {}
+S32 LLDir::deleteFilesInDir(const std::string &dirname,
+ const std::string &mask)
+{ return 0; }
+
+void LLDir::setChatLogsDir(const std::string &path){}
+void LLDir::setPerAccountChatLogsDir(const std::string &username){}
+void LLDir::setLindenUserDir(const std::string &username){}
+void LLDir::setSkinFolder(const std::string &skin_folder){}
+bool LLDir::setCacheDir(const std::string &path){ return true; }
+void LLDir::dumpCurrentDirectories() {}
+
+std::string LLDir::getExpandedFilename(ELLPath location,
+ const std::string &filename) const
+{
+ return "";
+}
+
+std::string LLUpdateDownloader::downloadMarkerPath(void)
+{
+ return "";
+}
+
+void LLUpdateDownloader::resume(void) {}
+void LLUpdateDownloader::cancel(void) {}
+
+int ll_install_update(std::string const &, std::string const &, LLInstallScriptMode)
+{
+ return 0;
+}
+
+std::string const & ll_install_failed_marker_path()
+{
+ static std::string wubba;
+ return wubba;
+}
+
+/*
+#pragma warning(disable: 4273)
+llus_mock_llifstream::llus_mock_llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode,
+ int _Prot) :
+ std::basic_istream<char,std::char_traits< char > >(NULL,true)
+{}
+
+llus_mock_llifstream::~llus_mock_llifstream() {}
+bool llus_mock_llifstream::is_open() const {return true;}
+void llus_mock_llifstream::close() {}
+*/
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct llupdaterservice_data
+ {
+ llupdaterservice_data() :
+ pumps(LLEventPumps::instance()),
+ test_url("dummy_url"),
+ test_channel("dummy_channel"),
+ test_version("dummy_version")
+ {}
+ LLEventPumps& pumps;
+ std::string test_url;
+ std::string test_channel;
+ std::string test_version;
+ };
+
+ typedef test_group<llupdaterservice_data> llupdaterservice_group;
+ typedef llupdaterservice_group::object llupdaterservice_object;
+ llupdaterservice_group llupdaterservicegrp("LLUpdaterService");
+
+ template<> template<>
+ void llupdaterservice_object::test<1>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ bool got_usage_error = false;
+ try
+ {
+ updater.startChecking();
+ }
+ catch(LLUpdaterService::UsageError)
+ {
+ got_usage_error = true;
+ }
+ ensure("Caught start before params", got_usage_error);
+ }
+
+ template<> template<>
+ void llupdaterservice_object::test<2>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ bool got_usage_error = false;
+ try
+ {
+ updater.initialize("1.0",test_url, "update" ,test_channel, test_version);
+ updater.startChecking();
+ updater.initialize("1.0", "other_url", "update", test_channel, test_version);
+ }
+ catch(LLUpdaterService::UsageError)
+ {
+ got_usage_error = true;
+ }
+ ensure("Caught params while running", got_usage_error);
+ }
+
+ template<> template<>
+ void llupdaterservice_object::test<3>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ updater.initialize("1.0", test_url, "update", test_channel, test_version);
+ updater.startChecking();
+ ensure(updater.isChecking());
+ updater.stopChecking();
+ ensure(!updater.isChecking());
+ }
+}
|